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	"context"
20	"crypto/tls"
21	"fmt"
22	"io/ioutil"
23	"log"
24	"math/rand"
25	"net/http"
26	"net/http/httptest"
27	"reflect"
28	"testing"
29	"time"
30
31	"github.com/Azure/go-autorest/autorest/mocks"
32)
33
34func TestLoggingInspectorWithInspection(t *testing.T) {
35	b := bytes.Buffer{}
36	c := Client{}
37	li := LoggingInspector{Logger: log.New(&b, "", 0)}
38	c.RequestInspector = li.WithInspection()
39
40	Prepare(mocks.NewRequestWithContent("Content"),
41		c.WithInspection())
42
43	if len(b.String()) <= 0 {
44		t.Fatal("autorest: LoggingInspector#WithInspection did not record Request to the log")
45	}
46}
47
48func TestLoggingInspectorWithInspectionEmitsErrors(t *testing.T) {
49	b := bytes.Buffer{}
50	c := Client{}
51	r := mocks.NewRequestWithContent("Content")
52	li := LoggingInspector{Logger: log.New(&b, "", 0)}
53	c.RequestInspector = li.WithInspection()
54
55	if _, err := Prepare(r,
56		c.WithInspection()); err != nil {
57		t.Error(err)
58	}
59
60	if len(b.String()) <= 0 {
61		t.Fatal("autorest: LoggingInspector#WithInspection did not record Request to the log")
62	}
63}
64
65func TestLoggingInspectorWithInspectionRestoresBody(t *testing.T) {
66	b := bytes.Buffer{}
67	c := Client{}
68	r := mocks.NewRequestWithContent("Content")
69	li := LoggingInspector{Logger: log.New(&b, "", 0)}
70	c.RequestInspector = li.WithInspection()
71
72	Prepare(r,
73		c.WithInspection())
74
75	s, _ := ioutil.ReadAll(r.Body)
76	if len(s) <= 0 {
77		t.Fatal("autorest: LoggingInspector#WithInspection did not restore the Request body")
78	}
79}
80
81func TestLoggingInspectorByInspecting(t *testing.T) {
82	b := bytes.Buffer{}
83	c := Client{}
84	li := LoggingInspector{Logger: log.New(&b, "", 0)}
85	c.ResponseInspector = li.ByInspecting()
86
87	Respond(mocks.NewResponseWithContent("Content"),
88		c.ByInspecting())
89
90	if len(b.String()) <= 0 {
91		t.Fatal("autorest: LoggingInspector#ByInspection did not record Response to the log")
92	}
93}
94
95func TestLoggingInspectorByInspectingEmitsErrors(t *testing.T) {
96	b := bytes.Buffer{}
97	c := Client{}
98	r := mocks.NewResponseWithContent("Content")
99	li := LoggingInspector{Logger: log.New(&b, "", 0)}
100	c.ResponseInspector = li.ByInspecting()
101
102	if err := Respond(r,
103		c.ByInspecting()); err != nil {
104		t.Fatal(err)
105	}
106
107	if len(b.String()) <= 0 {
108		t.Fatal("autorest: LoggingInspector#ByInspection did not record Response to the log")
109	}
110}
111
112func TestLoggingInspectorByInspectingRestoresBody(t *testing.T) {
113	b := bytes.Buffer{}
114	c := Client{}
115	r := mocks.NewResponseWithContent("Content")
116	li := LoggingInspector{Logger: log.New(&b, "", 0)}
117	c.ResponseInspector = li.ByInspecting()
118
119	Respond(r,
120		c.ByInspecting())
121
122	s, _ := ioutil.ReadAll(r.Body)
123	if len(s) <= 0 {
124		t.Fatal("autorest: LoggingInspector#ByInspecting did not restore the Response body")
125	}
126}
127
128func TestNewClientWithUserAgent(t *testing.T) {
129	ua := "UserAgent"
130	c := NewClientWithUserAgent(ua)
131	completeUA := fmt.Sprintf("%s %s", UserAgent(), ua)
132	if c.UserAgent != completeUA {
133		t.Fatalf("autorest: NewClientWithUserAgent failed to set the UserAgent -- expected %s, received %s",
134			completeUA, c.UserAgent)
135	}
136	r := c.Sender.(*http.Client).Transport.(*http.Transport).TLSClientConfig.Renegotiation
137	if r != tls.RenegotiateNever {
138		t.Fatal("autorest: TestNewClientWithUserAgentTLSRenegotiation expected RenegotiateNever")
139	}
140}
141
142func TestNewClientWithOptions(t *testing.T) {
143	const ua = "UserAgent"
144	c1 := NewClientWithOptions(ClientOptions{
145		UserAgent:     ua,
146		Renegotiation: tls.RenegotiateFreelyAsClient,
147	})
148	r1 := c1.Sender.(*http.Client).Transport.(*http.Transport).TLSClientConfig.Renegotiation
149	if r1 != tls.RenegotiateFreelyAsClient {
150		t.Fatal("autorest: TestNewClientWithUserAgentTLSRenegotiation expected RenegotiateFreelyAsClient")
151	}
152	// ensure default value doesn't stomp over previous value
153	c2 := NewClientWithUserAgent(ua)
154	r2 := c2.Sender.(*http.Client).Transport.(*http.Transport).TLSClientConfig.Renegotiation
155	if r2 != tls.RenegotiateNever {
156		t.Fatal("autorest: TestNewClientWithUserAgentTLSRenegotiation expected RenegotiateNever")
157	}
158	r1 = c1.Sender.(*http.Client).Transport.(*http.Transport).TLSClientConfig.Renegotiation
159	if r1 != tls.RenegotiateFreelyAsClient {
160		t.Fatal("autorest: TestNewClientWithUserAgentTLSRenegotiation expected RenegotiateFreelyAsClient (overwritten)")
161	}
162	r2 = c2.Sender.(*http.Client).Transport.(*http.Transport).TLSClientConfig.Renegotiation
163	if r2 != tls.RenegotiateNever {
164		t.Fatal("autorest: TestNewClientWithUserAgentTLSRenegotiation expected RenegotiateNever (overwritten)")
165	}
166}
167
168func TestAddToUserAgent(t *testing.T) {
169	ua := "UserAgent"
170	c := NewClientWithUserAgent(ua)
171	ext := "extension"
172	err := c.AddToUserAgent(ext)
173	if err != nil {
174		t.Fatalf("autorest: AddToUserAgent returned error -- expected nil, received %s", err)
175	}
176	completeUA := fmt.Sprintf("%s %s %s", UserAgent(), ua, ext)
177
178	if c.UserAgent != completeUA {
179		t.Fatalf("autorest: AddToUserAgent failed to add an extension to the UserAgent -- expected %s, received %s",
180			completeUA, c.UserAgent)
181	}
182
183	err = c.AddToUserAgent("")
184	if err == nil {
185		t.Fatalf("autorest: AddToUserAgent didn't return error -- expected %s, received nil",
186			fmt.Errorf("Extension was empty, User Agent stayed as %s", c.UserAgent))
187	}
188	if c.UserAgent != completeUA {
189		t.Fatalf("autorest: AddToUserAgent failed to not add an empty extension to the UserAgent -- expected %s, received %s",
190			completeUA, c.UserAgent)
191	}
192}
193
194func TestClientSenderReturnsHttpClientByDefault(t *testing.T) {
195	c := Client{}
196
197	if fmt.Sprintf("%T", c.sender(tls.RenegotiateNever)) != "*http.Client" {
198		t.Fatal("autorest: Client#sender failed to return http.Client by default")
199	}
200}
201
202func TestClientSenderReturnsSetSender(t *testing.T) {
203	c := Client{}
204
205	s := mocks.NewSender()
206	c.Sender = s
207
208	if c.sender(tls.RenegotiateNever) != s {
209		t.Fatal("autorest: Client#sender failed to return set Sender")
210	}
211}
212
213func TestClientDoInvokesSender(t *testing.T) {
214	c := Client{}
215
216	s := mocks.NewSender()
217	c.Sender = s
218
219	c.Do(&http.Request{})
220	if s.Attempts() != 1 {
221		t.Fatal("autorest: Client#Do failed to invoke the Sender")
222	}
223}
224
225func TestClientDoSetsUserAgent(t *testing.T) {
226	ua := "UserAgent"
227	c := Client{UserAgent: ua}
228	r := mocks.NewRequest()
229	s := mocks.NewSender()
230	c.Sender = s
231
232	c.Do(r)
233
234	if r.UserAgent() != ua {
235		t.Fatalf("autorest: Client#Do failed to correctly set User-Agent header: %s=%s",
236			http.CanonicalHeaderKey(headerUserAgent), r.UserAgent())
237	}
238}
239
240func TestClientDoSetsAuthorization(t *testing.T) {
241	r := mocks.NewRequest()
242	s := mocks.NewSender()
243	c := Client{Authorizer: mockAuthorizer{}, Sender: s}
244
245	c.Do(r)
246	if len(r.Header.Get(http.CanonicalHeaderKey(headerAuthorization))) <= 0 {
247		t.Fatalf("autorest: Client#Send failed to set Authorization header -- %s=%s",
248			http.CanonicalHeaderKey(headerAuthorization),
249			r.Header.Get(http.CanonicalHeaderKey(headerAuthorization)))
250	}
251}
252
253func TestClientDoInvokesRequestInspector(t *testing.T) {
254	r := mocks.NewRequest()
255	s := mocks.NewSender()
256	i := &mockInspector{}
257	c := Client{RequestInspector: i.WithInspection(), Sender: s}
258
259	c.Do(r)
260	if !i.wasInvoked {
261		t.Fatal("autorest: Client#Send failed to invoke the RequestInspector")
262	}
263}
264
265func TestClientDoInvokesResponseInspector(t *testing.T) {
266	r := mocks.NewRequest()
267	s := mocks.NewSender()
268	i := &mockInspector{}
269	c := Client{ResponseInspector: i.ByInspecting(), Sender: s}
270
271	c.Do(r)
272	if !i.wasInvoked {
273		t.Fatal("autorest: Client#Send failed to invoke the ResponseInspector")
274	}
275}
276
277func TestClientDoReturnsErrorIfPrepareFails(t *testing.T) {
278	c := Client{}
279	s := mocks.NewSender()
280	c.Authorizer = mockFailingAuthorizer{}
281	c.Sender = s
282
283	_, err := c.Do(&http.Request{})
284	if err == nil {
285		t.Fatalf("autorest: Client#Do failed to return an error when Prepare failed")
286	}
287}
288
289func TestClientDoDoesNotSendIfPrepareFails(t *testing.T) {
290	c := Client{}
291	s := mocks.NewSender()
292	c.Authorizer = mockFailingAuthorizer{}
293	c.Sender = s
294
295	c.Do(&http.Request{})
296	if s.Attempts() > 0 {
297		t.Fatal("autorest: Client#Do failed to invoke the Sender")
298	}
299}
300
301func TestClientAuthorizerReturnsNullAuthorizerByDefault(t *testing.T) {
302	c := Client{}
303
304	if fmt.Sprintf("%T", c.authorizer()) != "autorest.NullAuthorizer" {
305		t.Fatal("autorest: Client#authorizer failed to return the NullAuthorizer by default")
306	}
307}
308
309func TestClientAuthorizerReturnsSetAuthorizer(t *testing.T) {
310	c := Client{}
311	c.Authorizer = mockAuthorizer{}
312
313	if fmt.Sprintf("%T", c.authorizer()) != "autorest.mockAuthorizer" {
314		t.Fatal("autorest: Client#authorizer failed to return the set Authorizer")
315	}
316}
317
318func TestClientWithAuthorizer(t *testing.T) {
319	c := Client{}
320	c.Authorizer = mockAuthorizer{}
321
322	req, _ := Prepare(&http.Request{},
323		c.WithAuthorization())
324
325	if req.Header.Get(headerAuthorization) == "" {
326		t.Fatal("autorest: Client#WithAuthorizer failed to return the WithAuthorizer from the active Authorizer")
327	}
328}
329
330func TestClientWithInspection(t *testing.T) {
331	c := Client{}
332	r := &mockInspector{}
333	c.RequestInspector = r.WithInspection()
334
335	Prepare(&http.Request{},
336		c.WithInspection())
337
338	if !r.wasInvoked {
339		t.Fatal("autorest: Client#WithInspection failed to invoke RequestInspector")
340	}
341}
342
343func TestClientWithInspectionSetsDefault(t *testing.T) {
344	c := Client{}
345
346	r1 := &http.Request{}
347	r2, _ := Prepare(r1,
348		c.WithInspection())
349
350	if !reflect.DeepEqual(r1, r2) {
351		t.Fatal("autorest: Client#WithInspection failed to provide a default RequestInspector")
352	}
353}
354
355func TestClientByInspecting(t *testing.T) {
356	c := Client{}
357	r := &mockInspector{}
358	c.ResponseInspector = r.ByInspecting()
359
360	Respond(&http.Response{},
361		c.ByInspecting())
362
363	if !r.wasInvoked {
364		t.Fatal("autorest: Client#ByInspecting failed to invoke ResponseInspector")
365	}
366}
367
368func TestClientByInspectingSetsDefault(t *testing.T) {
369	c := Client{}
370
371	r := &http.Response{}
372	Respond(r,
373		c.ByInspecting())
374
375	if !reflect.DeepEqual(r, &http.Response{}) {
376		t.Fatal("autorest: Client#ByInspecting failed to provide a default ResponseInspector")
377	}
378}
379
380func TestCookies(t *testing.T) {
381	second := "second"
382	expected := http.Cookie{
383		Name:  "tastes",
384		Value: "delicious",
385	}
386
387	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
388		http.SetCookie(w, &expected)
389		b, err := ioutil.ReadAll(r.Body)
390		if err != nil {
391			t.Fatalf("autorest: ioutil.ReadAll failed reading request body: %s", err)
392		}
393		if string(b) == second {
394			cookie, err := r.Cookie(expected.Name)
395			if err != nil {
396				t.Fatalf("autorest: r.Cookie could not get request cookie: %s", err)
397			}
398			if cookie == nil {
399				t.Fatalf("autorest: got nil cookie, expecting %v", expected)
400			}
401			if cookie.Value != expected.Value {
402				t.Fatalf("autorest: got cookie value '%s', expecting '%s'", cookie.Value, expected.Name)
403			}
404		}
405	}))
406	defer server.Close()
407
408	client := NewClientWithUserAgent("")
409	_, err := SendWithSender(client, mocks.NewRequestForURL(server.URL))
410	if err != nil {
411		t.Fatalf("autorest: first request failed: %s", err)
412	}
413
414	r2, err := http.NewRequest(http.MethodGet, server.URL, mocks.NewBody(second))
415	if err != nil {
416		t.Fatalf("autorest: failed creating second request: %s", err)
417	}
418
419	_, err = SendWithSender(client, r2)
420	if err != nil {
421		t.Fatalf("autorest: second request failed: %s", err)
422	}
423}
424
425func TestResponseIsHTTPStatus(t *testing.T) {
426	r := Response{}
427	if r.IsHTTPStatus(http.StatusBadRequest) {
428		t.Fatal("autorest: expected false for nil response")
429	}
430	r.Response = &http.Response{StatusCode: http.StatusOK}
431	if r.IsHTTPStatus(http.StatusBadRequest) {
432		t.Fatal("autorest: expected false")
433	}
434	if !r.IsHTTPStatus(http.StatusOK) {
435		t.Fatal("autorest: expected true")
436	}
437}
438
439func TestResponseHasHTTPStatus(t *testing.T) {
440	r := Response{}
441	if r.HasHTTPStatus(http.StatusBadRequest, http.StatusInternalServerError) {
442		t.Fatal("autorest: expected false for nil response")
443	}
444	r.Response = &http.Response{StatusCode: http.StatusAccepted}
445	if r.HasHTTPStatus(http.StatusBadRequest, http.StatusInternalServerError) {
446		t.Fatal("autorest: expected false")
447	}
448	if !r.HasHTTPStatus(http.StatusOK, http.StatusCreated, http.StatusAccepted) {
449		t.Fatal("autorest: expected true")
450	}
451	if r.HasHTTPStatus() {
452		t.Fatal("autorest: expected false for no status codes")
453	}
454}
455
456func randomString(n int) string {
457	const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
458	r := rand.New(rand.NewSource(time.Now().UTC().UnixNano()))
459	s := make([]byte, n)
460	for i := range s {
461		s[i] = chars[r.Intn(len(chars))]
462	}
463	return string(s)
464}
465
466func TestClientSendMethod(t *testing.T) {
467	sender := mocks.NewSender()
468	sender.AppendResponse(newAcceptedResponse())
469	client := Client{
470		Sender: sender,
471	}
472	req, err := http.NewRequest(http.MethodGet, mocks.TestURL, nil)
473	req = req.WithContext(context.Background())
474	if err != nil {
475		t.Fatal(err)
476	}
477	// no SendDecorators
478	resp, err := client.Send(req)
479	if err != nil {
480		t.Fatal(err)
481	}
482	if resp.StatusCode != http.StatusAccepted {
483		t.Fatalf("expected status code %d, got %d", http.StatusAccepted, resp.StatusCode)
484	}
485	// default SendDecorators
486	sender.AppendResponse(newAcceptedResponse())
487	resp, err = client.Send(req, DefaultSendDecorator())
488	if err != nil {
489		t.Fatal(err)
490	}
491	if v := resp.Header.Get("default-decorator"); v != "true" {
492		t.Fatal("didn't find default-decorator header in response")
493	}
494	// using client SendDecorators
495	sender.AppendResponse(newAcceptedResponse())
496	client.SendDecorators = []SendDecorator{ClientSendDecorator()}
497	resp, err = client.Send(req, DefaultSendDecorator())
498	if err != nil {
499		t.Fatal(err)
500	}
501	if v := resp.Header.Get("client-decorator"); v != "true" {
502		t.Fatal("didn't find client-decorator header in response")
503	}
504	if v := resp.Header.Get("default-decorator"); v == "true" {
505		t.Fatal("unexpected default-decorator header in response")
506	}
507	// using context SendDecorators
508	sender.AppendResponse(newAcceptedResponse())
509	req = req.WithContext(WithSendDecorators(req.Context(), []SendDecorator{ContextSendDecorator()}))
510	resp, err = client.Send(req, DefaultSendDecorator())
511	if err != nil {
512		t.Fatal(err)
513	}
514	if v := resp.Header.Get("context-decorator"); v != "true" {
515		t.Fatal("didn't find context-decorator header in response")
516	}
517	if v := resp.Header.Get("client-decorator"); v == "true" {
518		t.Fatal("unexpected client-decorator header in response")
519	}
520	if v := resp.Header.Get("default-decorator"); v == "true" {
521		t.Fatal("unexpected default-decorator header in response")
522	}
523}
524
525func DefaultSendDecorator() SendDecorator {
526	return func(s Sender) Sender {
527		return SenderFunc(func(r *http.Request) (*http.Response, error) {
528			resp, err := s.Do(r)
529			resp.Header.Set("default-decorator", "true")
530			return resp, err
531		})
532	}
533}
534
535func ClientSendDecorator() SendDecorator {
536	return func(s Sender) Sender {
537		return SenderFunc(func(r *http.Request) (*http.Response, error) {
538			resp, err := s.Do(r)
539			resp.Header.Set("client-decorator", "true")
540			return resp, err
541		})
542	}
543}
544
545func ContextSendDecorator() SendDecorator {
546	return func(s Sender) Sender {
547		return SenderFunc(func(r *http.Request) (*http.Response, error) {
548			resp, err := s.Do(r)
549			resp.Header.Set("context-decorator", "true")
550			return resp, err
551		})
552	}
553}
554