1// +build go1.13
2
3// Copyright (c) Microsoft Corporation. All rights reserved.
4// Licensed under the MIT License.
5
6package azcore
7
8import (
9	"context"
10	"net/http"
11	"testing"
12	"time"
13
14	"github.com/Azure/azure-sdk-for-go/sdk/internal/mock"
15)
16
17func TestResponseUnmarshalXML(t *testing.T) {
18	srv, close := mock.NewServer()
19	defer close()
20	// include UTF8 BOM
21	srv.SetResponse(mock.WithBody([]byte("\xef\xbb\xbf<testXML><SomeInt>1</SomeInt><SomeString>s</SomeString></testXML>")))
22	pl := NewPipeline(srv)
23	req, err := NewRequest(context.Background(), http.MethodGet, srv.URL())
24	if err != nil {
25		t.Fatalf("unexpected error: %v", err)
26	}
27	resp, err := pl.Do(req)
28	if err != nil {
29		t.Fatalf("unexpected error: %v", err)
30	}
31	if !resp.HasStatusCode(http.StatusOK) {
32		t.Fatalf("unexpected status code: %d", resp.StatusCode)
33	}
34	var tx testXML
35	if err := resp.UnmarshalAsXML(&tx); err != nil {
36		t.Fatalf("unexpected error unmarshalling: %v", err)
37	}
38	if tx.SomeInt != 1 || tx.SomeString != "s" {
39		t.Fatal("unexpected value")
40	}
41}
42
43func TestResponseFailureStatusCode(t *testing.T) {
44	srv, close := mock.NewServer()
45	defer close()
46	srv.SetResponse(mock.WithStatusCode(http.StatusForbidden))
47	pl := NewPipeline(srv)
48	req, err := NewRequest(context.Background(), http.MethodGet, srv.URL())
49	if err != nil {
50		t.Fatalf("unexpected error: %v", err)
51	}
52	resp, err := pl.Do(req)
53	if err != nil {
54		t.Fatalf("unexpected error: %v", err)
55	}
56	if resp.HasStatusCode(http.StatusOK) {
57		t.Fatalf("unexpected status code: %d", resp.StatusCode)
58	}
59}
60
61func TestResponseUnmarshalJSON(t *testing.T) {
62	srv, close := mock.NewServer()
63	defer close()
64	srv.SetResponse(mock.WithBody([]byte(`{ "someInt": 1, "someString": "s" }`)))
65	pl := NewPipeline(srv)
66	req, err := NewRequest(context.Background(), http.MethodGet, srv.URL())
67	if err != nil {
68		t.Fatalf("unexpected error: %v", err)
69	}
70	resp, err := pl.Do(req)
71	if err != nil {
72		t.Fatalf("unexpected error: %v", err)
73	}
74	if !resp.HasStatusCode(http.StatusOK) {
75		t.Fatalf("unexpected status code: %d", resp.StatusCode)
76	}
77	var tx testJSON
78	if err := resp.UnmarshalAsJSON(&tx); err != nil {
79		t.Fatalf("unexpected error unmarshalling: %v", err)
80	}
81	if tx.SomeInt != 1 || tx.SomeString != "s" {
82		t.Fatal("unexpected value")
83	}
84}
85
86func TestResponseUnmarshalJSONskipDownload(t *testing.T) {
87	srv, close := mock.NewServer()
88	defer close()
89	srv.SetResponse(mock.WithBody([]byte(`{ "someInt": 1, "someString": "s" }`)))
90	pl := NewPipeline(srv)
91	req, err := NewRequest(context.Background(), http.MethodGet, srv.URL())
92	if err != nil {
93		t.Fatalf("unexpected error: %v", err)
94	}
95	req.SkipBodyDownload()
96	resp, err := pl.Do(req)
97	if err != nil {
98		t.Fatalf("unexpected error: %v", err)
99	}
100	if !resp.HasStatusCode(http.StatusOK) {
101		t.Fatalf("unexpected status code: %d", resp.StatusCode)
102	}
103	var tx testJSON
104	if err := resp.UnmarshalAsJSON(&tx); err != nil {
105		t.Fatalf("unexpected error unmarshalling: %v", err)
106	}
107	if tx.SomeInt != 1 || tx.SomeString != "s" {
108		t.Fatal("unexpected value")
109	}
110}
111
112func TestResponseUnmarshalJSONNoBody(t *testing.T) {
113	srv, close := mock.NewServer()
114	defer close()
115	srv.SetResponse(mock.WithBody([]byte{}))
116	pl := NewPipeline(srv)
117	req, err := NewRequest(context.Background(), http.MethodGet, srv.URL())
118	if err != nil {
119		t.Fatalf("unexpected error: %v", err)
120	}
121	resp, err := pl.Do(req)
122	if err != nil {
123		t.Fatalf("unexpected error: %v", err)
124	}
125	if !resp.HasStatusCode(http.StatusOK) {
126		t.Fatalf("unexpected status code: %d", resp.StatusCode)
127	}
128	if err := resp.UnmarshalAsJSON(nil); err != nil {
129		t.Fatalf("unexpected error unmarshalling: %v", err)
130	}
131}
132
133func TestResponseUnmarshalXMLNoBody(t *testing.T) {
134	srv, close := mock.NewServer()
135	defer close()
136	srv.SetResponse(mock.WithBody([]byte{}))
137	pl := NewPipeline(srv)
138	req, err := NewRequest(context.Background(), http.MethodGet, srv.URL())
139	if err != nil {
140		t.Fatalf("unexpected error: %v", err)
141	}
142	resp, err := pl.Do(req)
143	if err != nil {
144		t.Fatalf("unexpected error: %v", err)
145	}
146	if !resp.HasStatusCode(http.StatusOK) {
147		t.Fatalf("unexpected status code: %d", resp.StatusCode)
148	}
149	if err := resp.UnmarshalAsXML(nil); err != nil {
150		t.Fatalf("unexpected error unmarshalling: %v", err)
151	}
152}
153
154func TestRetryAfter(t *testing.T) {
155	raw := &http.Response{
156		Header: http.Header{},
157	}
158	resp := Response{raw}
159	if d := resp.retryAfter(); d > 0 {
160		t.Fatalf("unexpected retry-after value %d", d)
161	}
162	raw.Header.Set(HeaderRetryAfter, "300")
163	d := resp.retryAfter()
164	if d <= 0 {
165		t.Fatal("expected retry-after value from seconds")
166	}
167	if d != 300*time.Second {
168		t.Fatalf("expected 300 seconds, got %d", d/time.Second)
169	}
170	atDate := time.Now().Add(600 * time.Second)
171	raw.Header.Set(HeaderRetryAfter, atDate.Format(time.RFC1123))
172	d = resp.retryAfter()
173	if d <= 0 {
174		t.Fatal("expected retry-after value from date")
175	}
176	// d will not be exactly 600 seconds but it will be close
177	if s := d / time.Second; s < 598 || s > 602 {
178		t.Fatalf("expected ~600 seconds, got %d", s)
179	}
180}
181
182func TestResponseUnmarshalAsByteArrayURLFormat(t *testing.T) {
183	srv, close := mock.NewServer()
184	defer close()
185	srv.SetResponse(mock.WithBody([]byte(`"YSBzdHJpbmcgdGhhdCBnZXRzIGVuY29kZWQgd2l0aCBiYXNlNjR1cmw"`)))
186	pl := NewPipeline(srv)
187	req, err := NewRequest(context.Background(), http.MethodGet, srv.URL())
188	if err != nil {
189		t.Fatalf("unexpected error: %v", err)
190	}
191	resp, err := pl.Do(req)
192	if err != nil {
193		t.Fatalf("unexpected error: %v", err)
194	}
195	if !resp.HasStatusCode(http.StatusOK) {
196		t.Fatalf("unexpected status code: %d", resp.StatusCode)
197	}
198	var ba *[]byte
199	if err := resp.UnmarshalAsByteArray(&ba, Base64URLFormat); err != nil {
200		t.Fatalf("unexpected error unmarshalling: %v", err)
201	}
202	if string(*ba) != "a string that gets encoded with base64url" {
203		t.Fatalf("bad payload, got %s", string(*ba))
204	}
205}
206
207func TestResponseUnmarshalAsByteArrayStdFormat(t *testing.T) {
208	srv, close := mock.NewServer()
209	defer close()
210	srv.SetResponse(mock.WithBody([]byte(`"YSBzdHJpbmcgdGhhdCBnZXRzIGVuY29kZWQgd2l0aCBiYXNlNjR1cmw="`)))
211	pl := NewPipeline(srv)
212	req, err := NewRequest(context.Background(), http.MethodGet, srv.URL())
213	if err != nil {
214		t.Fatalf("unexpected error: %v", err)
215	}
216	resp, err := pl.Do(req)
217	if err != nil {
218		t.Fatalf("unexpected error: %v", err)
219	}
220	if !resp.HasStatusCode(http.StatusOK) {
221		t.Fatalf("unexpected status code: %d", resp.StatusCode)
222	}
223	var ba *[]byte
224	if err := resp.UnmarshalAsByteArray(&ba, Base64StdFormat); err != nil {
225		t.Fatalf("unexpected error unmarshalling: %v", err)
226	}
227	if string(*ba) != "a string that gets encoded with base64url" {
228		t.Fatalf("bad payload, got %s", string(*ba))
229	}
230}
231