1 package storage
2
3
4
5
6 import (
7 "bytes"
8 "encoding/base64"
9 "io/ioutil"
10 "math"
11 "net/http"
12 "net/url"
13 "os"
14 "path/filepath"
15 "reflect"
16 "regexp"
17 "strconv"
18 "strings"
19 "testing"
20 "time"
21
22 "github.com/Azure/go-autorest/autorest/azure"
23 "github.com/dnaeon/go-vcr/cassette"
24 "github.com/dnaeon/go-vcr/recorder"
25 chk "gopkg.in/check.v1"
26 )
27
28
29 func Test(t *testing.T) { chk.TestingT(t) }
30
31 type StorageClientSuite struct{}
32
33 var _ = chk.Suite(&StorageClientSuite{})
34
35 func setHeaders(haystack http.Header, predicate func(string) bool, value string) {
36 for key := range haystack {
37 if predicate(key) {
38 haystack[key] = []string{value}
39 }
40 }
41 }
42
43 func deleteHeaders(haystack http.Header, predicate func(string) bool) {
44 for key := range haystack {
45 if predicate(key) {
46 delete(haystack, key)
47 }
48 }
49 }
50 func getHeaders(haystack http.Header, predicate func(string) bool) string {
51 for key, value := range haystack {
52 if predicate(key) && len(value) > 0 {
53 return value[0]
54 }
55 }
56 return ""
57 }
58
59
60 func getBasicClient(c *chk.C) *Client {
61 name := os.Getenv("ACCOUNT_NAME")
62 if name == "" {
63 name = dummyStorageAccount
64 }
65 key := os.Getenv("ACCOUNT_KEY")
66 if key == "" {
67 key = dummyMiniStorageKey
68 }
69 cli, err := NewBasicClient(name, key)
70 c.Assert(err, chk.IsNil)
71
72 return &cli
73 }
74
75 func (client *Client) appendRecorder(c *chk.C) *recorder.Recorder {
76 tests := strings.Split(c.TestName(), ".")
77 path := filepath.Join(recordingsFolder, tests[0], tests[1])
78
79 if overwriteRec {
80 fullPath := filepath.Join(pwd, path+".yaml")
81 _, err := os.Stat(fullPath)
82 if err == nil {
83 err := os.Remove(fullPath)
84 c.Assert(err, chk.IsNil)
85 }
86 }
87
88 rec, err := recorder.New(path)
89 c.Assert(err, chk.IsNil)
90 client.HTTPClient = &http.Client{
91 Transport: rec,
92 }
93 rec.SetMatcher(func(r *http.Request, i cassette.Request) bool {
94 return compareMethods(r, i) &&
95 compareURLs(r, i) &&
96 compareHeaders(r, i) &&
97 compareBodies(r, i)
98 })
99 return rec
100 }
101
102 func (client *Client) usesDummies() bool {
103 key, err := base64.StdEncoding.DecodeString(dummyMiniStorageKey)
104 if err != nil {
105 return false
106 }
107 if string(client.accountKey) == string(key) &&
108 client.accountName == dummyStorageAccount {
109 return true
110 }
111 return false
112 }
113
114 func compareMethods(r *http.Request, i cassette.Request) bool {
115 return r.Method == i.Method
116 }
117
118 func compareURLs(r *http.Request, i cassette.Request) bool {
119 requestURL := modifyURL(r.URL)
120
121 cassetteURL, err := url.Parse(i.URL)
122 if err != nil {
123 return false
124 }
125
126 err = removeSAS(cassetteURL)
127 if err != nil {
128 return false
129 }
130 return requestURL.String() == cassetteURL.String()
131 }
132
133 func modifyURL(uri *url.URL) *url.URL {
134
135
136 parts := strings.Split(uri.Host, ".")
137
138
139 if !(parts[1] == blobServiceName ||
140 parts[1] == tableServiceName ||
141 parts[1] == queueServiceName ||
142 parts[1] == fileServiceName) {
143 return nil
144 }
145
146 storageEndpointSuffix := strings.Join(parts[2:], ".")
147 if !(storageEndpointSuffix == azure.PublicCloud.StorageEndpointSuffix ||
148 storageEndpointSuffix == azure.USGovernmentCloud.StorageEndpointSuffix ||
149 storageEndpointSuffix == azure.ChinaCloud.StorageEndpointSuffix ||
150 storageEndpointSuffix == azure.GermanCloud.StorageEndpointSuffix) {
151 return nil
152 }
153
154 host := dummyStorageAccount + "." + parts[1] + "." + azure.PublicCloud.StorageEndpointSuffix
155 newURL := uri
156 newURL.Host = host
157
158 err := removeSAS(newURL)
159 if err != nil {
160 return nil
161 }
162 return newURL
163 }
164
165 func removeSAS(uri *url.URL) error {
166
167 v := uri.Query()
168 v.Del("sig")
169
170 q, err := url.QueryUnescape(v.Encode())
171 if err != nil {
172 return err
173 }
174 uri.RawQuery = q
175 return nil
176 }
177
178 func compareHeaders(r *http.Request, i cassette.Request) bool {
179 requestHeaders := r.Header
180 cassetteHeaders := i.Headers
181
182
183 getHeaderMatchPredicate := func(needle string) func(string) bool {
184 return func(straw string) bool {
185 return strings.EqualFold(needle, straw)
186 }
187 }
188
189 isUserAgent := getHeaderMatchPredicate("User-Agent")
190 isAuthorization := getHeaderMatchPredicate("Authorization")
191 isDate := getHeaderMatchPredicate("x-ms-date")
192 deleteHeaders(requestHeaders, isUserAgent)
193 deleteHeaders(requestHeaders, isAuthorization)
194 deleteHeaders(requestHeaders, isDate)
195
196 deleteHeaders(cassetteHeaders, isUserAgent)
197 deleteHeaders(cassetteHeaders, isAuthorization)
198 deleteHeaders(cassetteHeaders, isDate)
199
200 isCopySource := getHeaderMatchPredicate("X-Ms-Copy-Source")
201 srcURLstr := getHeaders(requestHeaders, isCopySource)
202 if srcURLstr != "" {
203 srcURL, err := url.Parse(srcURLstr)
204 if err != nil {
205 return false
206 }
207 modifiedURL := modifyURL(srcURL)
208 setHeaders(requestHeaders, isCopySource, modifiedURL.String())
209 }
210
211
212 if isBatchOp(r.URL.String()) {
213
214 ctPrefixBatch := "multipart/mixed; boundary=batch_"
215
216 isContentType := getHeaderMatchPredicate("Content-Type")
217
218 contentTypeRequest := getHeaders(requestHeaders, isContentType)
219 contentTypeCassette := getHeaders(cassetteHeaders, isContentType)
220 if !(strings.HasPrefix(contentTypeRequest, ctPrefixBatch) &&
221 strings.HasPrefix(contentTypeCassette, ctPrefixBatch)) {
222 return false
223 }
224
225 deleteHeaders(requestHeaders, isContentType)
226 deleteHeaders(cassetteHeaders, isContentType)
227 }
228
229 return reflect.DeepEqual(requestHeaders, cassetteHeaders)
230 }
231
232 func compareBodies(r *http.Request, i cassette.Request) bool {
233 body := bytes.Buffer{}
234 if r.Body != nil {
235 _, err := body.ReadFrom(r.Body)
236 if err != nil {
237 return false
238 }
239 r.Body = ioutil.NopCloser(&body)
240 }
241
242 if isBatchOp(r.URL.String()) {
243 return compareBatchBodies(body.String(), i.Body)
244 }
245 return body.String() == i.Body
246 }
247
248 func compareBatchBodies(rBody, cBody string) bool {
249
250
251 exp, err := regexp.Compile("[0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12}")
252 if err != nil {
253 return false
254 }
255 rBody = replaceStorageAccount(replaceUUIDs(rBody, exp))
256 cBody = replaceUUIDs(cBody, exp)
257 return rBody == cBody
258 }
259
260 func replaceUUIDs(body string, exp *regexp.Regexp) string {
261 indexes := exp.FindAllStringIndex(body, -1)
262 for _, pair := range indexes {
263 body = strings.Replace(body, body[pair[0]:pair[1]], "00000000-0000-0000-0000-000000000000", -1)
264 }
265 return body
266 }
267
268 func isBatchOp(url string) bool {
269 return url == "https://golangrocksonazure.table.core.windows.net/$batch"
270 }
271
272
273 func getEmulatorClient(c *chk.C) Client {
274 cli, err := NewBasicClient(StorageEmulatorAccountName, "")
275 c.Assert(err, chk.IsNil)
276 return cli
277 }
278
279 func (s *StorageClientSuite) TestNewEmulatorClient(c *chk.C) {
280 cli, err := NewBasicClient(StorageEmulatorAccountName, "")
281 c.Assert(err, chk.IsNil)
282 c.Assert(cli.accountName, chk.Equals, StorageEmulatorAccountName)
283 expectedKey, err := base64.StdEncoding.DecodeString(StorageEmulatorAccountKey)
284 c.Assert(err, chk.IsNil)
285 c.Assert(cli.accountKey, chk.DeepEquals, expectedKey)
286 }
287
288 func (s *StorageClientSuite) TestNewFromConnectionString(c *chk.C) {
289 cli, err := NewClientFromConnectionString(
290 "DefaultEndpointsProtocol=https;" +
291 "AccountName=myaccountname;" +
292 "AccountKey=" + StorageEmulatorAccountKey + ";" +
293 "EndpointSuffix=example.com")
294
295 c.Assert(err, chk.IsNil)
296 c.Assert(cli.accountName, chk.Equals, "myaccountname")
297 expectedKey, err := base64.StdEncoding.DecodeString(StorageEmulatorAccountKey)
298 c.Assert(err, chk.IsNil)
299 c.Assert(cli.accountKey, chk.DeepEquals, expectedKey)
300 }
301
302 func (s *StorageClientSuite) TestNewAccountSASClientFromEndpointToken(c *chk.C) {
303 cli, err := NewAccountSASClientFromEndpointToken(
304 "http://golangrocksonazure.blob.core.windows.net",
305 "sv=2017-04-17&ss=bq&srt=sco&sp=rwdlacup&se=2018-01-09T22:32:27Z&st=2018-01-08T14:32:27Z&spr=http&sig=z8K9AiNvsQAoRQmqEgHrk3KdRfY37MxCHckGi%2BJRFDI%3D",
306 )
307
308 c.Assert(err, chk.IsNil)
309 c.Assert(cli.accountSASToken, chk.HasLen, 8)
310 c.Assert(cli.accountName, chk.Equals, "golangrocksonazure")
311 c.Assert(cli.baseURL, chk.Equals, "core.windows.net")
312 c.Assert(cli.apiVersion, chk.Equals, "2017-04-17")
313 c.Assert(cli.useHTTPS, chk.Equals, false)
314 }
315
316 func (s *StorageClientSuite) TestNewAccountSASClientWithoutSpr(c *chk.C) {
317 values, err := url.ParseQuery("st=2019-05-22T02%3A51%3A17Z&se=2019-05-23T02%3A51%3A17Z&sp=r&sv=2018-03-28&tn=test&sig=LYD0MvtngQduTB6SSoMGsbxX8xOCUZ6eUpn%2BVKyUWlc%3D")
318 c.Assert(err, chk.IsNil)
319
320 cli := NewAccountSASClient("nstestazure", values, azure.ChinaCloud)
321
322 c.Assert(cli.accountSASToken, chk.HasLen, 6)
323 c.Assert(cli.accountName, chk.Equals, "nstestazure")
324 c.Assert(cli.baseURL, chk.Equals, "core.chinacloudapi.cn")
325 c.Assert(cli.apiVersion, chk.Equals, "2018-03-28")
326 c.Assert(cli.useHTTPS, chk.Equals, true)
327 }
328
329 func (s *StorageClientSuite) TestIsValidStorageAccount(c *chk.C) {
330 type test struct {
331 account string
332 expected bool
333 }
334 testCases := []test{
335 {"name1", true},
336 {"Name2", false},
337 {"reallyLongName1234567891011", false},
338 {"", false},
339 {"concated&name", false},
340 {"formatted name", false},
341 }
342
343 for _, tc := range testCases {
344 c.Assert(IsValidStorageAccount(tc.account), chk.Equals, tc.expected)
345 }
346 }
347
348 func (s *StorageClientSuite) TestIsValidCosmosAccount(c *chk.C) {
349 type test struct {
350 account string
351 expected bool
352 }
353 testCases := []test{
354 {"name1", true},
355 {"Name2", false},
356 {"really-long-valid-name-less-than-44-chars", true},
357 {"really-long-invalid-name-greater-than-44-chars", false},
358 {"", false},
359 {"concated&name", false},
360 {"formatted name", false},
361 }
362
363 for _, tc := range testCases {
364 c.Assert(IsValidCosmosAccount(tc.account), chk.Equals, tc.expected)
365 }
366 }
367
368 func (s *StorageClientSuite) TestMalformedKeyError(c *chk.C) {
369 _, err := NewBasicClient(dummyStorageAccount, "malformed")
370 c.Assert(err, chk.ErrorMatches, "azure: malformed storage account key: .*")
371 }
372
373 func (s *StorageClientSuite) TestGetBaseURL_Basic_Https(c *chk.C) {
374 cli, err := NewBasicClient(dummyStorageAccount, dummyMiniStorageKey)
375 c.Assert(err, chk.IsNil)
376 c.Assert(cli.apiVersion, chk.Equals, DefaultAPIVersion)
377 c.Assert(err, chk.IsNil)
378 c.Assert(cli.getBaseURL("table").String(), chk.Equals, "https://golangrocksonazure.table.core.windows.net")
379 }
380
381 func (s *StorageClientSuite) TestGetBaseURL_Custom_NoHttps(c *chk.C) {
382 apiVersion := "2015-01-01"
383 cli, err := NewClient(dummyStorageAccount, dummyMiniStorageKey, "core.chinacloudapi.cn", apiVersion, false)
384 c.Assert(err, chk.IsNil)
385 c.Assert(cli.apiVersion, chk.Equals, apiVersion)
386 c.Assert(cli.getBaseURL("table").String(), chk.Equals, "http://golangrocksonazure.table.core.chinacloudapi.cn")
387 }
388
389 func (s *StorageClientSuite) TestGetBaseURL_StorageEmulator(c *chk.C) {
390 cli, err := NewBasicClient(StorageEmulatorAccountName, StorageEmulatorAccountKey)
391 c.Assert(err, chk.IsNil)
392
393 type test struct{ service, expected string }
394 tests := []test{
395 {blobServiceName, "http://127.0.0.1:10000"},
396 {tableServiceName, "http://127.0.0.1:10002"},
397 {queueServiceName, "http://127.0.0.1:10001"},
398 }
399 for _, i := range tests {
400 baseURL := cli.getBaseURL(i.service)
401 c.Assert(baseURL.String(), chk.Equals, i.expected)
402 }
403 }
404
405 func (s *StorageClientSuite) TestGetEndpoint_None(c *chk.C) {
406 cli, err := NewBasicClient(dummyStorageAccount, "YmFy")
407 c.Assert(err, chk.IsNil)
408 output := cli.getEndpoint(blobServiceName, "", url.Values{})
409 c.Assert(output, chk.Equals, "https://golangrocksonazure.blob.core.windows.net/")
410 }
411
412 func (s *StorageClientSuite) TestGetEndpoint_PathOnly(c *chk.C) {
413 cli, err := NewBasicClient(dummyStorageAccount, "YmFy")
414 c.Assert(err, chk.IsNil)
415 output := cli.getEndpoint(blobServiceName, "path", url.Values{})
416 c.Assert(output, chk.Equals, "https://golangrocksonazure.blob.core.windows.net/path")
417 }
418
419 func (s *StorageClientSuite) TestGetEndpoint_ParamsOnly(c *chk.C) {
420 cli, err := NewBasicClient(dummyStorageAccount, "YmFy")
421 c.Assert(err, chk.IsNil)
422 params := url.Values{}
423 params.Set("a", "b")
424 params.Set("c", "d")
425 output := cli.getEndpoint(blobServiceName, "", params)
426 c.Assert(output, chk.Equals, "https://golangrocksonazure.blob.core.windows.net/?a=b&c=d")
427 }
428
429 func (s *StorageClientSuite) TestGetEndpoint_Mixed(c *chk.C) {
430 cli, err := NewBasicClient(dummyStorageAccount, "YmFy")
431 c.Assert(err, chk.IsNil)
432 params := url.Values{}
433 params.Set("a", "b")
434 params.Set("c", "d")
435 output := cli.getEndpoint(blobServiceName, "path", params)
436 c.Assert(output, chk.Equals, "https://golangrocksonazure.blob.core.windows.net/path?a=b&c=d")
437 }
438
439 func (s *StorageClientSuite) TestGetEndpoint_StorageEmulator(c *chk.C) {
440 cli, err := NewBasicClient(StorageEmulatorAccountName, StorageEmulatorAccountKey)
441 c.Assert(err, chk.IsNil)
442
443 type test struct{ service, expected string }
444 tests := []test{
445 {blobServiceName, "http://127.0.0.1:10000/devstoreaccount1/"},
446 {tableServiceName, "http://127.0.0.1:10002/devstoreaccount1/"},
447 {queueServiceName, "http://127.0.0.1:10001/devstoreaccount1/"},
448 }
449 for _, i := range tests {
450 endpoint := cli.getEndpoint(i.service, "", url.Values{})
451 c.Assert(endpoint, chk.Equals, i.expected)
452 }
453 }
454
455 func (s *StorageClientSuite) Test_getStandardHeaders(c *chk.C) {
456 cli, err := NewBasicClient(dummyStorageAccount, "YmFy")
457 c.Assert(err, chk.IsNil)
458
459 headers := cli.getStandardHeaders()
460 c.Assert(len(headers), chk.Equals, 3)
461 c.Assert(headers["x-ms-version"], chk.Equals, cli.apiVersion)
462 if _, ok := headers["x-ms-date"]; !ok {
463 c.Fatal("Missing date header")
464 }
465 c.Assert(headers[userAgentHeader], chk.Equals, cli.getDefaultUserAgent())
466 }
467
468 func (s *StorageClientSuite) TestReturnsStorageServiceError(c *chk.C) {
469
470 cli := getBasicClient(c)
471 rec := cli.appendRecorder(c)
472 defer rec.Stop()
473
474
475 blobCli := cli.GetBlobService()
476 cnt := blobCli.GetContainerReference(containerName(c))
477 err := cnt.Delete(nil)
478 c.Assert(err, chk.NotNil)
479
480 v, ok := err.(AzureStorageServiceError)
481 c.Check(ok, chk.Equals, true)
482 c.Assert(v.StatusCode, chk.Equals, 404)
483 c.Assert(v.Code, chk.Equals, "ContainerNotFound")
484 c.Assert(v.RequestID, chk.Not(chk.Equals), "")
485 c.Assert(v.Date, chk.Not(chk.Equals), "")
486 c.Assert(v.APIVersion, chk.Not(chk.Equals), "")
487
488
489 tableCli := cli.GetTableService()
490 table := tableCli.GetTableReference(tableName(c))
491 err = table.Delete(30, nil)
492 c.Assert(err, chk.NotNil)
493
494 v, ok = err.(AzureStorageServiceError)
495 c.Check(ok, chk.Equals, true)
496 c.Assert(v.StatusCode, chk.Equals, 404)
497 c.Assert(v.Code, chk.Equals, "ResourceNotFound")
498 c.Assert(v.RequestID, chk.Not(chk.Equals), "")
499 c.Assert(v.Date, chk.Not(chk.Equals), "")
500 c.Assert(v.APIVersion, chk.Not(chk.Equals), "")
501 }
502
503 func (s *StorageClientSuite) TestReturnsStorageServiceError_withoutResponseBody(c *chk.C) {
504
505 cli := getBlobClient(c)
506 rec := cli.client.appendRecorder(c)
507 defer rec.Stop()
508
509 cnt := cli.GetContainerReference("non-existing-container")
510 b := cnt.GetBlobReference("non-existing-blob")
511 err := b.GetProperties(nil)
512
513 c.Assert(err, chk.NotNil)
514 c.Assert(err, chk.FitsTypeOf, AzureStorageServiceError{})
515
516 v, ok := err.(AzureStorageServiceError)
517 c.Check(ok, chk.Equals, true)
518 c.Assert(v.StatusCode, chk.Equals, http.StatusNotFound)
519 c.Assert(v.Code, chk.Equals, "404 The specified container does not exist.")
520 c.Assert(v.RequestID, chk.Not(chk.Equals), "")
521 c.Assert(v.Message, chk.Equals, "no response body was available for error status code")
522 }
523
524 func (s *StorageClientSuite) Test_createServiceClients(c *chk.C) {
525 cli, err := NewBasicClient(dummyStorageAccount, "YmFy")
526 c.Assert(err, chk.IsNil)
527
528 ua := cli.getDefaultUserAgent()
529
530 headers := cli.getStandardHeaders()
531 c.Assert(headers[userAgentHeader], chk.Equals, ua)
532 c.Assert(cli.userAgent, chk.Equals, ua)
533
534 b := cli.GetBlobService()
535 c.Assert(b.client.userAgent, chk.Equals, ua+" "+blobServiceName)
536 c.Assert(cli.userAgent, chk.Equals, ua)
537
538 t := cli.GetTableService()
539 c.Assert(t.client.userAgent, chk.Equals, ua+" "+tableServiceName)
540 c.Assert(cli.userAgent, chk.Equals, ua)
541
542 q := cli.GetQueueService()
543 c.Assert(q.client.userAgent, chk.Equals, ua+" "+queueServiceName)
544 c.Assert(cli.userAgent, chk.Equals, ua)
545
546 f := cli.GetFileService()
547 c.Assert(f.client.userAgent, chk.Equals, ua+" "+fileServiceName)
548 c.Assert(cli.userAgent, chk.Equals, ua)
549 }
550
551 func (s *StorageClientSuite) TestAddToUserAgent(c *chk.C) {
552 cli, err := NewBasicClient(dummyStorageAccount, "YmFy")
553 c.Assert(err, chk.IsNil)
554
555 ua := cli.getDefaultUserAgent()
556
557 err = cli.AddToUserAgent("rofl")
558 c.Assert(err, chk.IsNil)
559 c.Assert(cli.userAgent, chk.Equals, ua+" rofl")
560
561 err = cli.AddToUserAgent("")
562 c.Assert(err, chk.NotNil)
563 }
564
565 func (s *StorageClientSuite) Test_protectUserAgent(c *chk.C) {
566 extraheaders := map[string]string{
567 "1": "one",
568 "2": "two",
569 "3": "three",
570 userAgentHeader: "four",
571 }
572
573 cli, err := NewBasicClient(dummyStorageAccount, "YmFy")
574 c.Assert(err, chk.IsNil)
575
576 ua := cli.getDefaultUserAgent()
577
578 got := cli.protectUserAgent(extraheaders)
579 c.Assert(cli.userAgent, chk.Equals, ua+" four")
580 c.Assert(got, chk.HasLen, 3)
581 c.Assert(got, chk.DeepEquals, map[string]string{
582 "1": "one",
583 "2": "two",
584 "3": "three",
585 })
586 }
587
588 func (s *StorageClientSuite) Test_doRetry(c *chk.C) {
589 cli := getBasicClient(c)
590 rec := cli.appendRecorder(c)
591 defer rec.Stop()
592
593
594 uri, err := url.Parse(cli.getEndpoint(tableServiceName, "(retry)", url.Values{"timeout": {strconv.Itoa(30)}}))
595 c.Assert(err, chk.IsNil)
596 req := http.Request{
597 Method: http.MethodDelete,
598 URL: uri,
599 Header: http.Header{
600 "Accept": {"application/json;odata=nometadata"},
601 "Prefer": {"return-no-content"},
602 "X-Ms-Version": {"2016-05-31"},
603 },
604 }
605
606 ds, ok := cli.Sender.(*DefaultSender)
607 c.Assert(ok, chk.Equals, true)
608
609 ds.RetryAttempts = 3
610 ds.RetryDuration = time.Second
611
612 ds.ValidStatusCodes = []int{http.StatusNotFound}
613 cli.Sender = ds
614
615 now := time.Now()
616 resp, err := cli.Sender.Send(cli, &req)
617 afterRetries := time.Since(now)
618 c.Assert(err, chk.IsNil)
619 c.Assert(resp.StatusCode, chk.Equals, http.StatusNotFound)
620
621
622 c.Assert(cli.Sender.(*DefaultSender).attempts, chk.Equals, ds.RetryAttempts)
623
624
625 sum := 0
626 for i := 0; i < ds.RetryAttempts; i++ {
627 sum += int(ds.RetryDuration.Seconds() * math.Pow(2, float64(i)))
628 }
629 c.Assert(int(afterRetries.Seconds()), chk.Equals, sum)
630
631
632 blobCli := getBlobClient(c)
633 cnt := blobCli.GetContainerReference(containerName(c))
634 sasuriOptions := ContainerSASOptions{}
635 sasuriOptions.Expiry = fixedTime
636 sasuriOptions.Read = true
637 sasuriOptions.Add = true
638 sasuriOptions.Create = true
639 sasuriOptions.Write = true
640 sasuriOptions.Delete = true
641 sasuriOptions.List = true
642
643 sasuriString, err := cnt.GetSASURI(sasuriOptions)
644 c.Assert(err, chk.IsNil)
645
646 sasuri, err := url.Parse(sasuriString)
647 c.Assert(err, chk.IsNil)
648
649 cntServiceSAS, err := GetContainerReferenceFromSASURI(*sasuri)
650 c.Assert(err, chk.IsNil)
651 cntServiceSAS.Client().HTTPClient = cli.HTTPClient
652
653
654 ds.ValidStatusCodes = []int{http.StatusForbidden}
655 cntServiceSAS.Client().Sender = ds
656
657 now = time.Now()
658 _, err = cntServiceSAS.Exists()
659 afterRetries = time.Since(now)
660 c.Assert(err, chk.NotNil)
661
662 c.Assert(cntServiceSAS.Client().Sender.(*DefaultSender).attempts, chk.Equals, ds.RetryAttempts)
663 c.Assert(int(afterRetries.Seconds()), chk.Equals, sum)
664
665
666 token, err := cli.GetAccountSASToken(accountSASOptions)
667 c.Assert(err, chk.IsNil)
668
669 SAScli := NewAccountSASClient(cli.accountName, token, azure.PublicCloud).GetBlobService()
670 cntAccountSAS := SAScli.GetContainerReference(cnt.Name)
671 cntAccountSAS.Client().HTTPClient = cli.HTTPClient
672
673 ds.ValidStatusCodes = []int{http.StatusNotFound}
674 cntAccountSAS.Client().Sender = ds
675
676 now = time.Now()
677 _, err = cntAccountSAS.Exists()
678 afterRetries = time.Since(now)
679 c.Assert(err, chk.IsNil)
680
681 c.Assert(cntAccountSAS.Client().Sender.(*DefaultSender).attempts, chk.Equals, ds.RetryAttempts)
682 c.Assert(int(afterRetries.Seconds()), chk.Equals, sum)
683 }
684
View as plain text