1package autorest
2
3// Copyright 2017 Microsoft Corporation
4//
5//  Licensed under the Apache License, Version 2.0 (the "License");
6//  you may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at
8//
9//      http://www.apache.org/licenses/LICENSE-2.0
10//
11//  Unless required by applicable law or agreed to in writing, software
12//  distributed under the License is distributed on an "AS IS" BASIS,
13//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14//  See the License for the specific language governing permissions and
15//  limitations under the License.
16
17import (
18	"bytes"
19	"encoding/json"
20	"fmt"
21	"io/ioutil"
22	"net/http"
23	"reflect"
24	"strings"
25	"testing"
26
27	"github.com/Azure/go-autorest/autorest/mocks"
28)
29
30func ExampleWithErrorUnlessOK() {
31	r := mocks.NewResponse()
32	r.Request = mocks.NewRequest()
33
34	// Respond and leave the response body open (for a subsequent responder to close)
35	err := Respond(r,
36		WithErrorUnlessOK(),
37		ByDiscardingBody(),
38		ByClosingIfError())
39
40	if err == nil {
41		fmt.Printf("%s of %s returned HTTP 200", r.Request.Method, r.Request.URL)
42
43		// Complete handling the response and close the body
44		Respond(r,
45			ByDiscardingBody(),
46			ByClosing())
47	}
48	// Output: GET of https://microsoft.com/a/b/c/ returned HTTP 200
49}
50
51func TestByUnmarshallingBytes(t *testing.T) {
52	expected := []byte("Lorem Ipsum Dolor")
53
54	// we'll create a fixed-sized array here, since that's the expectation
55	bytes := make([]byte, len(expected))
56
57	Respond(mocks.NewResponseWithBytes(expected),
58		ByUnmarshallingBytes(&bytes),
59		ByClosing())
60
61	if len(bytes) != len(expected) {
62		t.Fatalf("Expected Response to be %d bytes but got %d bytes", len(expected), len(bytes))
63	}
64
65	if !reflect.DeepEqual(expected, bytes) {
66		t.Fatalf("Expected Response to be %s but got %s", expected, bytes)
67	}
68}
69
70func ExampleByUnmarshallingJSON() {
71	c := `
72	{
73		"name" : "Rob Pike",
74		"age"  : 42
75	}
76	`
77
78	type V struct {
79		Name string `json:"name"`
80		Age  int    `json:"age"`
81	}
82
83	v := &V{}
84
85	Respond(mocks.NewResponseWithContent(c),
86		ByUnmarshallingJSON(v),
87		ByClosing())
88
89	fmt.Printf("%s is %d years old\n", v.Name, v.Age)
90	// Output: Rob Pike is 42 years old
91}
92
93func ExampleByUnmarshallingXML() {
94	c := `<?xml version="1.0" encoding="UTF-8"?>
95	<Person>
96	  <Name>Rob Pike</Name>
97	  <Age>42</Age>
98	</Person>`
99
100	type V struct {
101		Name string `xml:"Name"`
102		Age  int    `xml:"Age"`
103	}
104
105	v := &V{}
106
107	Respond(mocks.NewResponseWithContent(c),
108		ByUnmarshallingXML(v),
109		ByClosing())
110
111	fmt.Printf("%s is %d years old\n", v.Name, v.Age)
112	// Output: Rob Pike is 42 years old
113}
114
115func TestCreateResponderDoesNotModify(t *testing.T) {
116	r1 := mocks.NewResponse()
117	r2 := mocks.NewResponse()
118	p := CreateResponder()
119	err := p.Respond(r1)
120	if err != nil {
121		t.Fatalf("autorest: CreateResponder failed (%v)", err)
122	}
123	if !reflect.DeepEqual(r1, r2) {
124		t.Fatalf("autorest: CreateResponder without decorators modified the response")
125	}
126}
127
128func TestCreateResponderRunsDecoratorsInOrder(t *testing.T) {
129	s := ""
130
131	d := func(n int) RespondDecorator {
132		return func(r Responder) Responder {
133			return ResponderFunc(func(resp *http.Response) error {
134				err := r.Respond(resp)
135				if err == nil {
136					s += fmt.Sprintf("%d", n)
137				}
138				return err
139			})
140		}
141	}
142
143	p := CreateResponder(d(1), d(2), d(3))
144	err := p.Respond(&http.Response{})
145	if err != nil {
146		t.Fatalf("autorest: Respond failed (%v)", err)
147	}
148
149	if s != "123" {
150		t.Fatalf("autorest: CreateResponder invoked decorators in an incorrect order; expected '123', received '%s'", s)
151	}
152}
153
154func TestByIgnoring(t *testing.T) {
155	r := mocks.NewResponse()
156
157	Respond(r,
158		(func() RespondDecorator {
159			return func(r Responder) Responder {
160				return ResponderFunc(func(r2 *http.Response) error {
161					r1 := mocks.NewResponse()
162					if !reflect.DeepEqual(r1, r2) {
163						t.Fatalf("autorest: ByIgnoring modified the HTTP Response -- received %v, expected %v", r2, r1)
164					}
165					return nil
166				})
167			}
168		})(),
169		ByIgnoring(),
170		ByClosing())
171}
172
173func TestByCopying_Copies(t *testing.T) {
174	r := mocks.NewResponseWithContent(jsonT)
175	b := &bytes.Buffer{}
176
177	err := Respond(r,
178		ByCopying(b),
179		ByUnmarshallingJSON(&mocks.T{}),
180		ByClosing())
181	if err != nil {
182		t.Fatalf("autorest: ByCopying returned an unexpected error -- %v", err)
183	}
184	if b.String() != jsonT {
185		t.Fatalf("autorest: ByCopying failed to copy the bytes read")
186	}
187}
188
189func TestByCopying_ReturnsNestedErrors(t *testing.T) {
190	r := mocks.NewResponseWithContent(jsonT)
191
192	r.Body.Close()
193	err := Respond(r,
194		ByCopying(&bytes.Buffer{}),
195		ByUnmarshallingJSON(&mocks.T{}),
196		ByClosing())
197	if err == nil {
198		t.Fatalf("autorest: ByCopying failed to return the expected error")
199	}
200}
201
202func TestByCopying_AcceptsNilReponse(t *testing.T) {
203	r := mocks.NewResponse()
204
205	Respond(r,
206		(func() RespondDecorator {
207			return func(r Responder) Responder {
208				return ResponderFunc(func(resp *http.Response) error {
209					resp.Body.Close()
210					r.Respond(nil)
211					return nil
212				})
213			}
214		})(),
215		ByCopying(&bytes.Buffer{}))
216}
217
218func TestByCopying_AcceptsNilBody(t *testing.T) {
219	r := mocks.NewResponse()
220
221	Respond(r,
222		(func() RespondDecorator {
223			return func(r Responder) Responder {
224				return ResponderFunc(func(resp *http.Response) error {
225					resp.Body.Close()
226					resp.Body = nil
227					r.Respond(resp)
228					return nil
229				})
230			}
231		})(),
232		ByCopying(&bytes.Buffer{}))
233}
234
235func TestByClosing(t *testing.T) {
236	r := mocks.NewResponse()
237	err := Respond(r, ByClosing())
238	if err != nil {
239		t.Fatalf("autorest: ByClosing failed (%v)", err)
240	}
241	if r.Body.(*mocks.Body).IsOpen() {
242		t.Fatalf("autorest: ByClosing did not close the response body")
243	}
244}
245
246func TestByClosingAcceptsNilResponse(t *testing.T) {
247	r := mocks.NewResponse()
248
249	Respond(r,
250		(func() RespondDecorator {
251			return func(r Responder) Responder {
252				return ResponderFunc(func(resp *http.Response) error {
253					resp.Body.Close()
254					r.Respond(nil)
255					return nil
256				})
257			}
258		})(),
259		ByClosing())
260}
261
262func TestByClosingAcceptsNilBody(t *testing.T) {
263	r := mocks.NewResponse()
264
265	Respond(r,
266		(func() RespondDecorator {
267			return func(r Responder) Responder {
268				return ResponderFunc(func(resp *http.Response) error {
269					resp.Body.Close()
270					resp.Body = nil
271					r.Respond(resp)
272					return nil
273				})
274			}
275		})(),
276		ByClosing())
277}
278
279func TestByClosingClosesEvenAfterErrors(t *testing.T) {
280	var e error
281
282	r := mocks.NewResponse()
283	Respond(r,
284		withErrorRespondDecorator(&e),
285		ByClosing())
286
287	if r.Body.(*mocks.Body).IsOpen() {
288		t.Fatalf("autorest: ByClosing did not close the response body after an error occurred")
289	}
290}
291
292func TestByClosingClosesReturnsNestedErrors(t *testing.T) {
293	var e error
294
295	r := mocks.NewResponse()
296	err := Respond(r,
297		withErrorRespondDecorator(&e),
298		ByClosing())
299
300	if err == nil || !reflect.DeepEqual(e, err) {
301		t.Fatalf("autorest: ByClosing failed to return a nested error")
302	}
303}
304
305func TestByClosingIfErrorAcceptsNilResponse(t *testing.T) {
306	var e error
307
308	r := mocks.NewResponse()
309
310	Respond(r,
311		withErrorRespondDecorator(&e),
312		(func() RespondDecorator {
313			return func(r Responder) Responder {
314				return ResponderFunc(func(resp *http.Response) error {
315					resp.Body.Close()
316					r.Respond(nil)
317					return nil
318				})
319			}
320		})(),
321		ByClosingIfError())
322}
323
324func TestByClosingIfErrorAcceptsNilBody(t *testing.T) {
325	var e error
326
327	r := mocks.NewResponse()
328
329	Respond(r,
330		withErrorRespondDecorator(&e),
331		(func() RespondDecorator {
332			return func(r Responder) Responder {
333				return ResponderFunc(func(resp *http.Response) error {
334					resp.Body.Close()
335					resp.Body = nil
336					r.Respond(resp)
337					return nil
338				})
339			}
340		})(),
341		ByClosingIfError())
342}
343
344func TestByClosingIfErrorClosesIfAnErrorOccurs(t *testing.T) {
345	var e error
346
347	r := mocks.NewResponse()
348	Respond(r,
349		withErrorRespondDecorator(&e),
350		ByClosingIfError())
351
352	if r.Body.(*mocks.Body).IsOpen() {
353		t.Fatalf("autorest: ByClosingIfError did not close the response body after an error occurred")
354	}
355}
356
357func TestByClosingIfErrorDoesNotClosesIfNoErrorOccurs(t *testing.T) {
358	r := mocks.NewResponse()
359	Respond(r,
360		ByClosingIfError())
361
362	if !r.Body.(*mocks.Body).IsOpen() {
363		t.Fatalf("autorest: ByClosingIfError closed the response body even though no error occurred")
364	}
365}
366
367func TestByDiscardingBody(t *testing.T) {
368	r := mocks.NewResponse()
369	err := Respond(r,
370		ByDiscardingBody())
371	if err != nil {
372		t.Fatalf("autorest: ByDiscardingBody failed (%v)", err)
373	}
374	buf, err := ioutil.ReadAll(r.Body)
375	if err != nil {
376		t.Fatalf("autorest: Reading result of ByDiscardingBody failed (%v)", err)
377	}
378
379	if len(buf) != 0 {
380		t.Logf("autorest: Body was not empty after calling ByDiscardingBody.")
381		t.Fail()
382	}
383}
384
385func TestByDiscardingBodyAcceptsNilResponse(t *testing.T) {
386	var e error
387
388	r := mocks.NewResponse()
389
390	Respond(r,
391		withErrorRespondDecorator(&e),
392		(func() RespondDecorator {
393			return func(r Responder) Responder {
394				return ResponderFunc(func(resp *http.Response) error {
395					resp.Body.Close()
396					r.Respond(nil)
397					return nil
398				})
399			}
400		})(),
401		ByDiscardingBody())
402}
403
404func TestByDiscardingBodyAcceptsNilBody(t *testing.T) {
405	var e error
406
407	r := mocks.NewResponse()
408
409	Respond(r,
410		withErrorRespondDecorator(&e),
411		(func() RespondDecorator {
412			return func(r Responder) Responder {
413				return ResponderFunc(func(resp *http.Response) error {
414					resp.Body.Close()
415					resp.Body = nil
416					r.Respond(resp)
417					return nil
418				})
419			}
420		})(),
421		ByDiscardingBody())
422}
423
424func TestByUnmarshallingJSON(t *testing.T) {
425	v := &mocks.T{}
426	r := mocks.NewResponseWithContent(jsonT)
427	err := Respond(r,
428		ByUnmarshallingJSON(v),
429		ByClosing())
430	if err != nil {
431		t.Fatalf("autorest: ByUnmarshallingJSON failed (%v)", err)
432	}
433	if v.Name != "Rob Pike" || v.Age != 42 {
434		t.Fatalf("autorest: ByUnmarshallingJSON failed to properly unmarshal")
435	}
436}
437
438func TestByUnmarshallingJSON_HandlesReadErrors(t *testing.T) {
439	v := &mocks.T{}
440	r := mocks.NewResponseWithContent(jsonT)
441	r.Body.(*mocks.Body).Close()
442
443	err := Respond(r,
444		ByUnmarshallingJSON(v),
445		ByClosing())
446	if err == nil {
447		t.Fatalf("autorest: ByUnmarshallingJSON failed to receive / respond to read error")
448	}
449}
450
451func TestByUnmarshallingJSONIncludesJSONInErrors(t *testing.T) {
452	v := &mocks.T{}
453	j := jsonT[0 : len(jsonT)-2]
454	r := mocks.NewResponseWithContent(j)
455	err := Respond(r,
456		ByUnmarshallingJSON(v),
457		ByClosing())
458	if err == nil || !strings.Contains(err.Error(), j) {
459		t.Fatalf("autorest: ByUnmarshallingJSON failed to return JSON in error (%v)", err)
460	}
461}
462
463func TestByUnmarshallingJSONEmptyInput(t *testing.T) {
464	v := &mocks.T{}
465	r := mocks.NewResponseWithContent(``)
466	err := Respond(r,
467		ByUnmarshallingJSON(v),
468		ByClosing())
469	if err != nil {
470		t.Fatalf("autorest: ByUnmarshallingJSON failed to return nil in case of empty JSON (%v)", err)
471	}
472}
473
474func TestByUnmarshallingXML(t *testing.T) {
475	v := &mocks.T{}
476	r := mocks.NewResponseWithContent(xmlT)
477	err := Respond(r,
478		ByUnmarshallingXML(v),
479		ByClosing())
480	if err != nil {
481		t.Fatalf("autorest: ByUnmarshallingXML failed (%v)", err)
482	}
483	if v.Name != "Rob Pike" || v.Age != 42 {
484		t.Fatalf("autorest: ByUnmarshallingXML failed to properly unmarshal")
485	}
486}
487
488func TestByUnmarshallingXML_HandlesReadErrors(t *testing.T) {
489	v := &mocks.T{}
490	r := mocks.NewResponseWithContent(xmlT)
491	r.Body.(*mocks.Body).Close()
492
493	err := Respond(r,
494		ByUnmarshallingXML(v),
495		ByClosing())
496	if err == nil {
497		t.Fatalf("autorest: ByUnmarshallingXML failed to receive / respond to read error")
498	}
499}
500
501func TestByUnmarshallingXMLIncludesXMLInErrors(t *testing.T) {
502	v := &mocks.T{}
503	x := xmlT[0 : len(xmlT)-2]
504	r := mocks.NewResponseWithContent(x)
505	err := Respond(r,
506		ByUnmarshallingXML(v),
507		ByClosing())
508	if err == nil || !strings.Contains(err.Error(), x) {
509		t.Fatalf("autorest: ByUnmarshallingXML failed to return XML in error (%v)", err)
510	}
511}
512
513func TestRespondAcceptsNullResponse(t *testing.T) {
514	err := Respond(nil)
515	if err != nil {
516		t.Fatalf("autorest: Respond returned an unexpected error when given a null Response (%v)", err)
517	}
518}
519
520func TestWithErrorUnlessStatusCodeOKResponse(t *testing.T) {
521	v := &mocks.T{}
522	r := mocks.NewResponseWithContent(jsonT)
523	err := Respond(r,
524		WithErrorUnlessStatusCode(http.StatusOK),
525		ByUnmarshallingJSON(v),
526		ByClosing())
527
528	if err != nil {
529		t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) failed on okay response. (%v)", err)
530	}
531
532	if v.Name != "Rob Pike" || v.Age != 42 {
533		t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) corrupted the response body of okay response.")
534	}
535}
536
537func TesWithErrorUnlessStatusCodeErrorResponse(t *testing.T) {
538	v := &mocks.T{}
539	e := &mocks.T{}
540	r := mocks.NewResponseWithContent(jsonT)
541	r.Status = "400 BadRequest"
542	r.StatusCode = http.StatusBadRequest
543
544	err := Respond(r,
545		WithErrorUnlessStatusCode(http.StatusOK),
546		ByUnmarshallingJSON(v),
547		ByClosing())
548
549	if err == nil {
550		t.Fatal("autorest: WithErrorUnlessStatusCode(http.StatusOK) did not return error, on a response to a bad request.")
551	}
552
553	var errorRespBody []byte
554	if derr, ok := err.(DetailedError); !ok {
555		t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) got wrong error type : %T, expected: DetailedError, on a response to a bad request.", err)
556	} else {
557		errorRespBody = derr.ServiceError
558	}
559
560	if errorRespBody == nil {
561		t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) ServiceError not returned in DetailedError on a response to a bad request.")
562	}
563
564	err = json.Unmarshal(errorRespBody, e)
565	if err != nil {
566		t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK) cannot parse error returned in ServiceError into json. %v", err)
567	}
568
569	expected := &mocks.T{Name: "Rob Pike", Age: 42}
570	if e != expected {
571		t.Fatalf("autorest: WithErrorUnlessStatusCode(http.StatusOK wrong value from parsed ServiceError: got=%#v expected=%#v", e, expected)
572	}
573}
574
575func TestWithErrorUnlessStatusCode(t *testing.T) {
576	r := mocks.NewResponse()
577	r.Request = mocks.NewRequest()
578	r.Status = "400 BadRequest"
579	r.StatusCode = http.StatusBadRequest
580
581	err := Respond(r,
582		WithErrorUnlessStatusCode(http.StatusBadRequest, http.StatusUnauthorized, http.StatusInternalServerError),
583		ByClosingIfError())
584
585	if err != nil {
586		t.Fatalf("autorest: WithErrorUnlessStatusCode returned an error (%v) for an acceptable status code (%s)", err, r.Status)
587	}
588}
589
590func TestWithErrorUnlessStatusCodeEmitsErrorForUnacceptableStatusCode(t *testing.T) {
591	r := mocks.NewResponse()
592	r.Request = mocks.NewRequest()
593	r.Status = "400 BadRequest"
594	r.StatusCode = http.StatusBadRequest
595
596	err := Respond(r,
597		WithErrorUnlessStatusCode(http.StatusOK, http.StatusUnauthorized, http.StatusInternalServerError),
598		ByClosingIfError())
599
600	if err == nil {
601		t.Fatalf("autorest: WithErrorUnlessStatusCode failed to return an error for an unacceptable status code (%s)", r.Status)
602	}
603}
604
605func TestWithErrorUnlessOK(t *testing.T) {
606	r := mocks.NewResponse()
607	r.Request = mocks.NewRequest()
608
609	err := Respond(r,
610		WithErrorUnlessOK(),
611		ByClosingIfError())
612
613	if err != nil {
614		t.Fatalf("autorest: WithErrorUnlessOK returned an error for OK status code (%v)", err)
615	}
616}
617
618func TestWithErrorUnlessOKEmitsErrorIfNotOK(t *testing.T) {
619	r := mocks.NewResponse()
620	r.Request = mocks.NewRequest()
621	r.Status = "400 BadRequest"
622	r.StatusCode = http.StatusBadRequest
623
624	err := Respond(r,
625		WithErrorUnlessOK(),
626		ByClosingIfError())
627
628	if err == nil {
629		t.Fatalf("autorest: WithErrorUnlessOK failed to return an error for a non-OK status code (%v)", err)
630	}
631}
632
633func TestExtractHeader(t *testing.T) {
634	r := mocks.NewResponse()
635	v := []string{"v1", "v2", "v3"}
636	mocks.SetResponseHeaderValues(r, mocks.TestHeader, v)
637
638	if !reflect.DeepEqual(ExtractHeader(mocks.TestHeader, r), v) {
639		t.Fatalf("autorest: ExtractHeader failed to retrieve the expected header -- expected [%s]%v, received [%s]%v",
640			mocks.TestHeader, v, mocks.TestHeader, ExtractHeader(mocks.TestHeader, r))
641	}
642}
643
644func TestExtractHeaderHandlesMissingHeader(t *testing.T) {
645	var v []string
646	r := mocks.NewResponse()
647
648	if !reflect.DeepEqual(ExtractHeader(mocks.TestHeader, r), v) {
649		t.Fatalf("autorest: ExtractHeader failed to handle a missing header -- expected %v, received %v",
650			v, ExtractHeader(mocks.TestHeader, r))
651	}
652}
653
654func TestExtractHeaderValue(t *testing.T) {
655	r := mocks.NewResponse()
656	v := "v1"
657	mocks.SetResponseHeader(r, mocks.TestHeader, v)
658
659	if ExtractHeaderValue(mocks.TestHeader, r) != v {
660		t.Fatalf("autorest: ExtractHeader failed to retrieve the expected header -- expected [%s]%v, received [%s]%v",
661			mocks.TestHeader, v, mocks.TestHeader, ExtractHeaderValue(mocks.TestHeader, r))
662	}
663}
664
665func TestExtractHeaderValueHandlesMissingHeader(t *testing.T) {
666	r := mocks.NewResponse()
667	v := ""
668
669	if ExtractHeaderValue(mocks.TestHeader, r) != v {
670		t.Fatalf("autorest: ExtractHeader failed to retrieve the expected header -- expected [%s]%v, received [%s]%v",
671			mocks.TestHeader, v, mocks.TestHeader, ExtractHeaderValue(mocks.TestHeader, r))
672	}
673}
674
675func TestExtractHeaderValueRetrievesFirstValue(t *testing.T) {
676	r := mocks.NewResponse()
677	v := []string{"v1", "v2", "v3"}
678	mocks.SetResponseHeaderValues(r, mocks.TestHeader, v)
679
680	if ExtractHeaderValue(mocks.TestHeader, r) != v[0] {
681		t.Fatalf("autorest: ExtractHeader failed to retrieve the expected header -- expected [%s]%v, received [%s]%v",
682			mocks.TestHeader, v[0], mocks.TestHeader, ExtractHeaderValue(mocks.TestHeader, r))
683	}
684}
685