1package azblob
2
3import (
4	"bytes"
5	"context"
6	"errors"
7	"os"
8	"strconv"
9	"strings"
10	"time"
11
12	chk "gopkg.in/check.v1" // go get gopkg.in/check.v1
13)
14
15func delContainer(c *chk.C, container ContainerURL) {
16	resp, err := container.Delete(context.Background(), ContainerAccessConditions{})
17	c.Assert(err, chk.IsNil)
18	c.Assert(resp.Response().StatusCode, chk.Equals, 202)
19}
20
21func (s *aztestsSuite) TestNewContainerURLValidName(c *chk.C) {
22	bsu := getBSU()
23	testURL := bsu.NewContainerURL(containerPrefix)
24
25	correctURL := "https://" + os.Getenv("ACCOUNT_NAME") + ".blob.core.windows.net/" + containerPrefix
26	temp := testURL.URL()
27	c.Assert(temp.String(), chk.Equals, correctURL)
28}
29
30func (s *aztestsSuite) TestCreateRootContainerURL(c *chk.C) {
31	bsu := getBSU()
32	testURL := bsu.NewContainerURL(ContainerNameRoot)
33
34	correctURL := "https://" + os.Getenv("ACCOUNT_NAME") + ".blob.core.windows.net/$root"
35	temp := testURL.URL()
36	c.Assert(temp.String(), chk.Equals, correctURL)
37}
38
39func (s *aztestsSuite) TestAccountWithPipeline(c *chk.C) {
40	bsu := getBSU()
41	bsu = bsu.WithPipeline(testPipeline{}) // testPipeline returns an identifying message as an error
42	containerURL := bsu.NewContainerURL("name")
43
44	_, err := containerURL.Create(ctx, Metadata{}, PublicAccessBlob)
45
46	c.Assert(err.Error(), chk.Equals, testPipelineMessage)
47}
48
49func (s *aztestsSuite) TestContainerCreateInvalidName(c *chk.C) {
50	bsu := getBSU()
51	containerURL := bsu.NewContainerURL("foo bar")
52
53	_, err := containerURL.Create(ctx, Metadata{}, PublicAccessBlob)
54
55	validateStorageError(c, err, ServiceCodeInvalidResourceName)
56}
57
58func (s *aztestsSuite) TestContainerCreateEmptyName(c *chk.C) {
59	bsu := getBSU()
60	containerURL := bsu.NewContainerURL("")
61
62	_, err := containerURL.Create(ctx, Metadata{}, PublicAccessBlob)
63
64	validateStorageError(c, err, ServiceCodeInvalidQueryParameterValue)
65}
66
67func (s *aztestsSuite) TestContainerCreateNameCollision(c *chk.C) {
68	bsu := getBSU()
69	containerURL, containerName := createNewContainer(c, bsu)
70
71	defer deleteContainer(c, containerURL)
72
73	containerURL = bsu.NewContainerURL(containerName)
74	_, err := containerURL.Create(ctx, Metadata{}, PublicAccessBlob)
75
76	validateStorageError(c, err, ServiceCodeContainerAlreadyExists)
77}
78
79func (s *aztestsSuite) TestContainerCreateInvalidMetadata(c *chk.C) {
80	bsu := getBSU()
81	containerURL, _ := getContainerURL(c, bsu)
82
83	_, err := containerURL.Create(ctx, Metadata{"1 foo": "bar"}, PublicAccessBlob)
84
85	c.Assert(err, chk.NotNil)
86	c.Assert(strings.Contains(err.Error(), invalidHeaderErrorSubstring), chk.Equals, true)
87}
88
89func (s *aztestsSuite) TestContainerCreateNilMetadata(c *chk.C) {
90	bsu := getBSU()
91	containerURL, _ := getContainerURL(c, bsu)
92
93	_, err := containerURL.Create(ctx, nil, PublicAccessBlob)
94	defer deleteContainer(c, containerURL)
95	c.Assert(err, chk.IsNil)
96
97	response, err := containerURL.GetProperties(ctx, LeaseAccessConditions{})
98	c.Assert(err, chk.IsNil)
99	c.Assert(response.NewMetadata(), chk.HasLen, 0)
100}
101
102func (s *aztestsSuite) TestContainerCreateEmptyMetadata(c *chk.C) {
103	bsu := getBSU()
104	containerURL, _ := getContainerURL(c, bsu)
105
106	_, err := containerURL.Create(ctx, Metadata{}, PublicAccessBlob)
107	defer deleteContainer(c, containerURL)
108	c.Assert(err, chk.IsNil)
109
110	response, err := containerURL.GetProperties(ctx, LeaseAccessConditions{})
111	c.Assert(err, chk.IsNil)
112	c.Assert(response.NewMetadata(), chk.HasLen, 0)
113}
114
115// Note that for all tests that create blobs, deleting the container also deletes any blobs within that container, thus we
116// simply delete the whole container after the test
117
118func (s *aztestsSuite) TestContainerCreateAccessContainer(c *chk.C) {
119	bsu := getBSU()
120	containerURL, _ := getContainerURL(c, bsu)
121
122	_, err := containerURL.Create(ctx, nil, PublicAccessContainer)
123	defer deleteContainer(c, containerURL)
124	c.Assert(err, chk.IsNil)
125
126	blobURL := containerURL.NewBlockBlobURL(blobPrefix)
127	blobURL.Upload(ctx, bytes.NewReader([]byte("Content")), BlobHTTPHeaders{}, basicMetadata, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{})
128
129	// Anonymous enumeration should be valid with container access
130	containerURL2 := NewContainerURL(containerURL.URL(), NewPipeline(NewAnonymousCredential(), PipelineOptions{}))
131	response, err := containerURL2.ListBlobsFlatSegment(ctx, Marker{},
132		ListBlobsSegmentOptions{})
133	c.Assert(err, chk.IsNil)
134	c.Assert(response.Segment.BlobItems[0].Name, chk.Equals, blobPrefix)
135
136	// Getting blob data anonymously should still be valid with container access
137	blobURL2 := containerURL2.NewBlockBlobURL(blobPrefix)
138	resp, err := blobURL2.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{})
139	c.Assert(err, chk.IsNil)
140	c.Assert(resp.NewMetadata(), chk.DeepEquals, basicMetadata)
141}
142
143func (s *aztestsSuite) TestContainerCreateAccessBlob(c *chk.C) {
144	bsu := getBSU()
145	containerURL, _ := getContainerURL(c, bsu)
146
147	_, err := containerURL.Create(ctx, nil, PublicAccessBlob)
148	defer deleteContainer(c, containerURL)
149	c.Assert(err, chk.IsNil)
150
151	blobURL := containerURL.NewBlockBlobURL(blobPrefix)
152	blobURL.Upload(ctx, bytes.NewReader([]byte("Content")), BlobHTTPHeaders{}, basicMetadata, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{})
153
154	// Reference the same container URL but with anonymous credentials
155	containerURL2 := NewContainerURL(containerURL.URL(), NewPipeline(NewAnonymousCredential(), PipelineOptions{}))
156	_, err = containerURL2.ListBlobsFlatSegment(ctx, Marker{}, ListBlobsSegmentOptions{})
157	validateStorageError(c, err, ServiceCodeNoAuthenticationInformation) // Listing blobs is not publicly accessible
158
159	// Accessing blob specific data should be public
160	blobURL2 := containerURL2.NewBlockBlobURL(blobPrefix)
161	resp, err := blobURL2.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{})
162	c.Assert(err, chk.IsNil)
163	c.Assert(resp.NewMetadata(), chk.DeepEquals, basicMetadata)
164}
165
166func (s *aztestsSuite) TestContainerCreateAccessNone(c *chk.C) {
167	bsu := getBSU()
168	containerURL, _ := getContainerURL(c, bsu)
169
170	_, err := containerURL.Create(ctx, nil, PublicAccessNone)
171	defer deleteContainer(c, containerURL)
172
173	blobURL := containerURL.NewBlockBlobURL(blobPrefix)
174	blobURL.Upload(ctx, bytes.NewReader([]byte("Content")), BlobHTTPHeaders{}, basicMetadata, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{})
175
176	// Reference the same container URL but with anonymous credentials
177	containerURL2 := NewContainerURL(containerURL.URL(), NewPipeline(NewAnonymousCredential(), PipelineOptions{}))
178	// Listing blobs is not public
179	_, err = containerURL2.ListBlobsFlatSegment(ctx, Marker{}, ListBlobsSegmentOptions{})
180	validateStorageError(c, err, ServiceCodeNoAuthenticationInformation)
181
182	// Blob data is not public
183	blobURL2 := containerURL2.NewBlockBlobURL(blobPrefix)
184	_, err = blobURL2.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{})
185	c.Assert(err, chk.NotNil)
186	serr := err.(StorageError)
187	c.Assert(serr.Response().StatusCode, chk.Equals, 401) // HEAD request does not return a status code
188}
189
190func validateContainerDeleted(c *chk.C, containerURL ContainerURL) {
191	_, err := containerURL.GetAccessPolicy(ctx, LeaseAccessConditions{})
192	validateStorageError(c, err, ServiceCodeContainerNotFound)
193}
194
195func (s *aztestsSuite) TestContainerDelete(c *chk.C) {
196	bsu := getBSU()
197	containerURL, _ := createNewContainer(c, bsu)
198
199	_, err := containerURL.Delete(ctx, ContainerAccessConditions{})
200	c.Assert(err, chk.IsNil)
201
202	validateContainerDeleted(c, containerURL)
203}
204
205func (s *aztestsSuite) TestContainerDeleteNonExistant(c *chk.C) {
206	bsu := getBSU()
207	containerURL, _ := getContainerURL(c, bsu)
208
209	_, err := containerURL.Delete(ctx, ContainerAccessConditions{})
210	validateStorageError(c, err, ServiceCodeContainerNotFound)
211}
212
213func (s *aztestsSuite) TestContainerDeleteIfModifiedSinceTrue(c *chk.C) {
214	currentTime := getRelativeTimeGMT(-10) // Ensure the requests occur at different times
215	bsu := getBSU()
216	containerURL, _ := createNewContainer(c, bsu)
217
218	_, err := containerURL.Delete(ctx,
219		ContainerAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfModifiedSince: currentTime}})
220	c.Assert(err, chk.IsNil)
221	validateContainerDeleted(c, containerURL)
222}
223
224func (s *aztestsSuite) TestContainerDeleteIfModifiedSinceFalse(c *chk.C) {
225	bsu := getBSU()
226	containerURL, _ := createNewContainer(c, bsu)
227
228	defer deleteContainer(c, containerURL)
229
230	currentTime := getRelativeTimeGMT(10)
231
232	_, err := containerURL.Delete(ctx,
233		ContainerAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfModifiedSince: currentTime}})
234	validateStorageError(c, err, ServiceCodeConditionNotMet)
235}
236
237func (s *aztestsSuite) TestContainerDeleteIfUnModifiedSinceTrue(c *chk.C) {
238	bsu := getBSU()
239	containerURL, _ := createNewContainer(c, bsu)
240
241	currentTime := getRelativeTimeGMT(10)
242	_, err := containerURL.Delete(ctx,
243		ContainerAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfUnmodifiedSince: currentTime}})
244	c.Assert(err, chk.IsNil)
245
246	validateContainerDeleted(c, containerURL)
247}
248
249func (s *aztestsSuite) TestContainerDeleteIfUnModifiedSinceFalse(c *chk.C) {
250	currentTime := getRelativeTimeGMT(-10) // Ensure the requests occur at different times
251
252	bsu := getBSU()
253	containerURL, _ := createNewContainer(c, bsu)
254
255	defer deleteContainer(c, containerURL)
256
257	_, err := containerURL.Delete(ctx,
258		ContainerAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfUnmodifiedSince: currentTime}})
259	validateStorageError(c, err, ServiceCodeConditionNotMet)
260}
261
262func (s *aztestsSuite) TestContainerAccessConditionsUnsupportedConditions(c *chk.C) {
263	// This test defines that the library will panic if the user specifies conditional headers
264	// that will be ignored by the service
265	bsu := getBSU()
266	containerURL, _ := createNewContainer(c, bsu)
267	defer deleteContainer(c, containerURL)
268
269	invalidEtag := ETag("invalid")
270	_, err := containerURL.SetMetadata(ctx, basicMetadata,
271		ContainerAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfMatch: invalidEtag}})
272	c.Assert(err, chk.Not(chk.Equals), nil)
273}
274
275func (s *aztestsSuite) TestContainerListBlobsNonexistantPrefix(c *chk.C) {
276	bsu := getBSU()
277	containerURL, _ := createNewContainer(c, bsu)
278	defer deleteContainer(c, containerURL)
279	createNewBlockBlob(c, containerURL)
280
281	resp, err := containerURL.ListBlobsFlatSegment(ctx, Marker{}, ListBlobsSegmentOptions{Prefix: blobPrefix + blobPrefix})
282
283	c.Assert(err, chk.IsNil)
284	c.Assert(resp.Segment.BlobItems, chk.HasLen, 0)
285}
286
287func (s *aztestsSuite) TestContainerListBlobsSpecificValidPrefix(c *chk.C) {
288	bsu := getBSU()
289	containerURL, _ := createNewContainer(c, bsu)
290	defer deleteContainer(c, containerURL)
291	_, blobName := createNewBlockBlob(c, containerURL)
292
293	resp, err := containerURL.ListBlobsFlatSegment(ctx, Marker{}, ListBlobsSegmentOptions{Prefix: blobPrefix})
294
295	c.Assert(err, chk.IsNil)
296	c.Assert(resp.Segment.BlobItems, chk.HasLen, 1)
297	c.Assert(resp.Segment.BlobItems[0].Name, chk.Equals, blobName)
298}
299
300func (s *aztestsSuite) TestContainerListBlobsValidDelimiter(c *chk.C) {
301	bsu := getBSU()
302	containerURL, _ := createNewContainer(c, bsu)
303	defer deleteContainer(c, containerURL)
304	createBlockBlobWithPrefix(c, containerURL, "a/1")
305	createBlockBlobWithPrefix(c, containerURL, "a/2")
306	createBlockBlobWithPrefix(c, containerURL, "b/1")
307	_, blobName := createBlockBlobWithPrefix(c, containerURL, "blob")
308
309	resp, err := containerURL.ListBlobsHierarchySegment(ctx, Marker{}, "/", ListBlobsSegmentOptions{})
310
311	c.Assert(err, chk.IsNil)
312	c.Assert(len(resp.Segment.BlobItems), chk.Equals, 1)
313	c.Assert(len(resp.Segment.BlobPrefixes), chk.Equals, 2)
314	c.Assert(resp.Segment.BlobPrefixes[0].Name, chk.Equals, "a/")
315	c.Assert(resp.Segment.BlobPrefixes[1].Name, chk.Equals, "b/")
316	c.Assert(resp.Segment.BlobItems[0].Name, chk.Equals, blobName)
317}
318
319func (s *aztestsSuite) TestContainerListBlobsWithSnapshots(c *chk.C) {
320	bsu := getBSU()
321	containerURL, _ := createNewContainer(c, bsu)
322	defer deleteContainer(c, containerURL)
323
324	_, err := containerURL.ListBlobsHierarchySegment(ctx, Marker{}, "/", ListBlobsSegmentOptions{Details: BlobListingDetails{Snapshots: true}})
325	c.Assert(err, chk.Not(chk.Equals), nil)
326}
327
328func (s *aztestsSuite) TestContainerListBlobsInvalidDelimiter(c *chk.C) {
329	bsu := getBSU()
330	containerURL, _ := createNewContainer(c, bsu)
331	defer deleteContainer(c, containerURL)
332	createBlockBlobWithPrefix(c, containerURL, "a/1")
333	createBlockBlobWithPrefix(c, containerURL, "a/2")
334	createBlockBlobWithPrefix(c, containerURL, "b/1")
335	createBlockBlobWithPrefix(c, containerURL, "blob")
336
337	resp, err := containerURL.ListBlobsHierarchySegment(ctx, Marker{}, "^", ListBlobsSegmentOptions{})
338
339	c.Assert(err, chk.IsNil)
340	c.Assert(resp.Segment.BlobItems, chk.HasLen, 4)
341}
342
343func (s *aztestsSuite) TestContainerListBlobsIncludeTypeMetadata(c *chk.C) {
344	bsu := getBSU()
345	container, _ := createNewContainer(c, bsu)
346	defer deleteContainer(c, container)
347	_, blobNameNoMetadata := createBlockBlobWithPrefix(c, container, "a")
348	blobMetadata, blobNameMetadata := createBlockBlobWithPrefix(c, container, "b")
349	_, err := blobMetadata.SetMetadata(ctx, Metadata{"field": "value"}, BlobAccessConditions{}, ClientProvidedKeyOptions{})
350	c.Assert(err, chk.IsNil)
351
352	resp, err := container.ListBlobsFlatSegment(ctx, Marker{}, ListBlobsSegmentOptions{Details: BlobListingDetails{Metadata: true}})
353
354	c.Assert(err, chk.IsNil)
355	c.Assert(resp.Segment.BlobItems[0].Name, chk.Equals, blobNameNoMetadata)
356	c.Assert(resp.Segment.BlobItems[0].Metadata, chk.HasLen, 0)
357	c.Assert(resp.Segment.BlobItems[1].Name, chk.Equals, blobNameMetadata)
358	c.Assert(resp.Segment.BlobItems[1].Metadata["field"], chk.Equals, "value")
359}
360
361func (s *aztestsSuite) TestContainerListBlobsIncludeTypeSnapshots(c *chk.C) {
362	bsu := getBSU()
363	containerURL, _ := createNewContainer(c, bsu)
364	defer deleteContainer(c, containerURL)
365	blob, blobName := createNewBlockBlob(c, containerURL)
366	_, err := blob.CreateSnapshot(ctx, Metadata{}, BlobAccessConditions{}, ClientProvidedKeyOptions{})
367	c.Assert(err, chk.IsNil)
368
369	resp, err := containerURL.ListBlobsFlatSegment(ctx, Marker{},
370		ListBlobsSegmentOptions{Details: BlobListingDetails{Snapshots: true}})
371
372	c.Assert(err, chk.IsNil)
373	c.Assert(resp.Segment.BlobItems, chk.HasLen, 2)
374	c.Assert(resp.Segment.BlobItems[0].Name, chk.Equals, blobName)
375	c.Assert(resp.Segment.BlobItems[0].Snapshot, chk.NotNil)
376	c.Assert(resp.Segment.BlobItems[1].Name, chk.Equals, blobName)
377	c.Assert(resp.Segment.BlobItems[1].Snapshot, chk.Equals, "")
378}
379
380func (s *aztestsSuite) TestContainerListBlobsIncludeTypeCopy(c *chk.C) {
381	bsu := getBSU()
382	containerURL, _ := createNewContainer(c, bsu)
383	defer deleteContainer(c, containerURL)
384	blobURL, blobName := createNewBlockBlob(c, containerURL)
385	blobCopyURL, blobCopyName := createBlockBlobWithPrefix(c, containerURL, "copy")
386	_, err := blobCopyURL.StartCopyFromURL(ctx, blobURL.URL(), Metadata{}, ModifiedAccessConditions{}, BlobAccessConditions{}, DefaultAccessTier, nil)
387	c.Assert(err, chk.IsNil)
388
389	resp, err := containerURL.ListBlobsFlatSegment(ctx, Marker{},
390		ListBlobsSegmentOptions{Details: BlobListingDetails{Copy: true}})
391
392	// These are sufficient to show that the blob copy was in fact included
393	c.Assert(err, chk.IsNil)
394	c.Assert(resp.Segment.BlobItems, chk.HasLen, 2)
395	c.Assert(resp.Segment.BlobItems[1].Name, chk.Equals, blobName)
396	c.Assert(resp.Segment.BlobItems[0].Name, chk.Equals, blobCopyName)
397	c.Assert(*resp.Segment.BlobItems[0].Properties.ContentLength, chk.Equals, int64(len(blockBlobDefaultData)))
398	temp := blobURL.URL()
399	c.Assert(*resp.Segment.BlobItems[0].Properties.CopySource, chk.Equals, temp.String())
400	c.Assert(resp.Segment.BlobItems[0].Properties.CopyStatus, chk.Equals, CopyStatusSuccess)
401}
402
403func (s *aztestsSuite) TestContainerListBlobsIncludeTypeUncommitted(c *chk.C) {
404	bsu := getBSU()
405	containerURL, _ := createNewContainer(c, bsu)
406	defer deleteContainer(c, containerURL)
407	blobURL, blobName := getBlockBlobURL(c, containerURL)
408	_, err := blobURL.StageBlock(ctx, blockID, strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{})
409	c.Assert(err, chk.IsNil)
410
411	resp, err := containerURL.ListBlobsFlatSegment(ctx, Marker{},
412		ListBlobsSegmentOptions{Details: BlobListingDetails{UncommittedBlobs: true}})
413
414	c.Assert(err, chk.IsNil)
415	c.Assert(resp.Segment.BlobItems, chk.HasLen, 1)
416	c.Assert(resp.Segment.BlobItems[0].Name, chk.Equals, blobName)
417}
418
419func testContainerListBlobsIncludeTypeDeletedImpl(c *chk.C, bsu ServiceURL) error {
420	containerURL, _ := createNewContainer(c, bsu)
421	defer deleteContainer(c, containerURL)
422	blobURL, _ := createNewBlockBlob(c, containerURL)
423
424	resp, err := containerURL.ListBlobsFlatSegment(ctx, Marker{},
425		ListBlobsSegmentOptions{Details: BlobListingDetails{Versions: true, Deleted: true}})
426	c.Assert(err, chk.IsNil)
427	c.Assert(resp.Segment.BlobItems, chk.HasLen, 1)
428
429	_, err = blobURL.Delete(ctx, DeleteSnapshotsOptionInclude, BlobAccessConditions{})
430	c.Assert(err, chk.IsNil)
431
432	resp, err = containerURL.ListBlobsFlatSegment(ctx, Marker{},
433		ListBlobsSegmentOptions{Details: BlobListingDetails{Versions: true, Deleted: true}})
434	c.Assert(err, chk.IsNil)
435	if len(resp.Segment.BlobItems) != 1 {
436		return errors.New("DeletedBlobNotFound")
437	}
438
439	// TODO: => Write function to enable/disable versioning from code itself.
440	// resp.Segment.BlobItems[0].Deleted == true/false if versioning is disabled/enabled.
441	c.Assert(resp.Segment.BlobItems[0].Deleted, chk.Equals, false)
442	return nil
443}
444
445func (s *aztestsSuite) TestContainerListBlobsIncludeTypeDeleted(c *chk.C) {
446	bsu := getBSU()
447
448	runTestRequiringServiceProperties(c, bsu, "DeletedBlobNotFound", enableSoftDelete,
449		testContainerListBlobsIncludeTypeDeletedImpl, disableSoftDelete)
450}
451
452func testContainerListBlobsIncludeMultipleImpl(c *chk.C, bsu ServiceURL) error {
453	containerURL, _ := createNewContainer(c, bsu)
454	defer deleteContainer(c, containerURL)
455
456	blobURL, _ := createBlockBlobWithPrefix(c, containerURL, "z")
457	_, err := blobURL.CreateSnapshot(ctx, Metadata{}, BlobAccessConditions{}, ClientProvidedKeyOptions{})
458	c.Assert(err, chk.IsNil)
459	blobURL2, _ := createBlockBlobWithPrefix(c, containerURL, "copy")
460	resp2, err := blobURL2.StartCopyFromURL(ctx, blobURL.URL(), Metadata{}, ModifiedAccessConditions{}, BlobAccessConditions{}, DefaultAccessTier, nil)
461	c.Assert(err, chk.IsNil)
462	waitForCopy(c, blobURL2, resp2)
463	blobURL3, _ := createBlockBlobWithPrefix(c, containerURL, "deleted")
464
465	_, err = blobURL3.Delete(ctx, DeleteSnapshotsOptionNone, BlobAccessConditions{})
466
467	resp, err := containerURL.ListBlobsFlatSegment(ctx, Marker{},
468		ListBlobsSegmentOptions{Details: BlobListingDetails{Snapshots: true, Copy: true, Deleted: true, Versions: true}})
469
470	c.Assert(err, chk.IsNil)
471	if len(resp.Segment.BlobItems) != 6 {
472		// If there are fewer blobs in the container than there should be, it will be because one was permanently deleted.
473		return errors.New("DeletedBlobNotFound")
474	}
475
476	//c.Assert(resp.Segment.BlobItems[0].Name, chk.Equals, blobName2)
477	//c.Assert(resp.Segment.BlobItems[1].Name, chk.Equals, blobName) // With soft delete, the overwritten blob will have a backup snapshot
478	//c.Assert(resp.Segment.BlobItems[2].Name, chk.Equals, blobName)
479	return nil
480}
481
482func (s *aztestsSuite) TestContainerListBlobsIncludeMultiple(c *chk.C) {
483	bsu := getBSU()
484
485	runTestRequiringServiceProperties(c, bsu, "DeletedBlobNotFound", enableSoftDelete,
486		testContainerListBlobsIncludeMultipleImpl, disableSoftDelete)
487}
488
489func (s *aztestsSuite) TestContainerListBlobsMaxResultsNegative(c *chk.C) {
490	bsu := getBSU()
491	containerURL, _ := createNewContainer(c, bsu)
492
493	defer deleteContainer(c, containerURL)
494	_, err := containerURL.ListBlobsFlatSegment(ctx, Marker{}, ListBlobsSegmentOptions{MaxResults: -2})
495	c.Assert(err, chk.Not(chk.IsNil))
496}
497
498func (s *aztestsSuite) TestContainerListBlobsMaxResultsZero(c *chk.C) {
499	bsu := getBSU()
500	containerURL, _ := createNewContainer(c, bsu)
501	defer deleteContainer(c, containerURL)
502	createNewBlockBlob(c, containerURL)
503
504	resp, err := containerURL.ListBlobsFlatSegment(ctx, Marker{}, ListBlobsSegmentOptions{MaxResults: 0})
505
506	c.Assert(err, chk.IsNil)
507	c.Assert(resp.Segment.BlobItems, chk.HasLen, 1)
508}
509
510func (s *aztestsSuite) TestContainerListBlobsMaxResultsInsufficient(c *chk.C) {
511	bsu := getBSU()
512	containerURL, _ := createNewContainer(c, bsu)
513	defer deleteContainer(c, containerURL)
514	_, blobName := createBlockBlobWithPrefix(c, containerURL, "a")
515	createBlockBlobWithPrefix(c, containerURL, "b")
516
517	resp, err := containerURL.ListBlobsFlatSegment(ctx, Marker{}, ListBlobsSegmentOptions{MaxResults: 1})
518
519	c.Assert(err, chk.IsNil)
520	c.Assert(resp.Segment.BlobItems, chk.HasLen, 1)
521	c.Assert(resp.Segment.BlobItems[0].Name, chk.Equals, blobName)
522}
523
524func (s *aztestsSuite) TestContainerListBlobsMaxResultsExact(c *chk.C) {
525	bsu := getBSU()
526	containerURL, _ := createNewContainer(c, bsu)
527	defer deleteContainer(c, containerURL)
528	_, blobName := createBlockBlobWithPrefix(c, containerURL, "a")
529	_, blobName2 := createBlockBlobWithPrefix(c, containerURL, "b")
530
531	resp, err := containerURL.ListBlobsFlatSegment(ctx, Marker{}, ListBlobsSegmentOptions{MaxResults: 2})
532
533	c.Assert(err, chk.IsNil)
534	c.Assert(resp.Segment.BlobItems, chk.HasLen, 2)
535	c.Assert(resp.Segment.BlobItems[0].Name, chk.Equals, blobName)
536	c.Assert(resp.Segment.BlobItems[1].Name, chk.Equals, blobName2)
537}
538
539func (s *aztestsSuite) TestContainerListBlobsMaxResultsSufficient(c *chk.C) {
540	bsu := getBSU()
541	containerURL, _ := createNewContainer(c, bsu)
542	defer deleteContainer(c, containerURL)
543	_, blobName := createBlockBlobWithPrefix(c, containerURL, "a")
544	_, blobName2 := createBlockBlobWithPrefix(c, containerURL, "b")
545
546	resp, err := containerURL.ListBlobsFlatSegment(ctx, Marker{}, ListBlobsSegmentOptions{MaxResults: 3})
547
548	c.Assert(err, chk.IsNil)
549	c.Assert(resp.Segment.BlobItems, chk.HasLen, 2)
550	c.Assert(resp.Segment.BlobItems[0].Name, chk.Equals, blobName)
551	c.Assert(resp.Segment.BlobItems[1].Name, chk.Equals, blobName2)
552}
553
554func (s *aztestsSuite) TestContainerListBlobsNonExistentContainer(c *chk.C) {
555	bsu := getBSU()
556	containerURL, _ := getContainerURL(c, bsu)
557
558	_, err := containerURL.ListBlobsFlatSegment(ctx, Marker{}, ListBlobsSegmentOptions{})
559
560	c.Assert(err, chk.NotNil)
561}
562
563func (s *aztestsSuite) TestContainerWithNewPipeline(c *chk.C) {
564	bsu := getBSU()
565	pipeline := testPipeline{}
566	containerURL, _ := getContainerURL(c, bsu)
567	containerURL = containerURL.WithPipeline(pipeline)
568
569	_, err := containerURL.Create(ctx, Metadata{}, PublicAccessBlob)
570
571	c.Assert(err, chk.NotNil)
572	c.Assert(err.Error(), chk.Equals, testPipelineMessage)
573}
574
575func (s *aztestsSuite) TestContainerGetSetPermissionsMultiplePolicies(c *chk.C) {
576	bsu := getBSU()
577	containerURL, _ := createNewContainer(c, bsu)
578
579	defer deleteContainer(c, containerURL)
580
581	// Define the policies
582	start := generateCurrentTimeWithModerateResolution()
583	expiry := start.Add(5 * time.Minute)
584	expiry2 := start.Add(time.Minute)
585	readWrite := AccessPolicyPermission{Read: true, Write: true}.String()
586	readOnly := AccessPolicyPermission{Read: true}.String()
587	permissions := []SignedIdentifier{
588		{ID: "0000",
589			AccessPolicy: AccessPolicy{
590				Start:      &start,
591				Expiry:     &expiry,
592				Permission: &readWrite,
593			},
594		},
595		{ID: "0001",
596			AccessPolicy: AccessPolicy{
597				Start:      &start,
598				Expiry:     &expiry2,
599				Permission: &readOnly,
600			},
601		},
602	}
603
604	_, err := containerURL.SetAccessPolicy(ctx, PublicAccessNone, permissions,
605		ContainerAccessConditions{})
606
607	c.Assert(err, chk.IsNil)
608
609	resp, err := containerURL.GetAccessPolicy(ctx, LeaseAccessConditions{})
610	c.Assert(err, chk.IsNil)
611	c.Assert(resp.Items, chk.DeepEquals, permissions)
612}
613
614func (s *aztestsSuite) TestContainerGetPermissionsPublicAccessNotNone(c *chk.C) {
615	bsu := getBSU()
616	containerURL, _ := getContainerURL(c, bsu)
617	containerURL.Create(ctx, nil, PublicAccessBlob) // We create the container explicitly so we can be sure the access policy is not empty
618
619	defer deleteContainer(c, containerURL)
620
621	resp, err := containerURL.GetAccessPolicy(ctx, LeaseAccessConditions{})
622
623	c.Assert(err, chk.IsNil)
624	c.Assert(resp.BlobPublicAccess(), chk.Equals, PublicAccessBlob)
625}
626
627func (s *aztestsSuite) TestContainerSetPermissionsPublicAccessNone(c *chk.C) {
628	// Test the basic one by making an anonymous request to ensure it's actually doing it and also with GetPermissions
629	// For all the others, can just use GetPermissions since we've validated that it at least registers on the server correctly
630	bsu := getBSU()
631	containerURL, containerName := createNewContainer(c, bsu)
632	defer deleteContainer(c, containerURL)
633	_, blobName := createNewBlockBlob(c, containerURL)
634
635	// Container is created with PublicAccessBlob, so setting it to None will actually test that it is changed through this method
636	_, err := containerURL.SetAccessPolicy(ctx, PublicAccessNone, nil, ContainerAccessConditions{})
637	c.Assert(err, chk.IsNil)
638
639	pipeline := NewPipeline(NewAnonymousCredential(), PipelineOptions{})
640	bsu2 := NewServiceURL(bsu.URL(), pipeline)
641	containerURL2 := bsu2.NewContainerURL(containerName)
642	blobURL2 := containerURL2.NewBlockBlobURL(blobName)
643	_, err = blobURL2.Download(ctx, 0, 0, BlobAccessConditions{}, false, ClientProvidedKeyOptions{})
644
645	// Get permissions via the original container URL so the request succeeds
646	resp, _ := containerURL.GetAccessPolicy(ctx, LeaseAccessConditions{})
647
648	// If we cannot access a blob's data, we will also not be able to enumerate blobs
649	validateStorageError(c, err, ServiceCodeNoAuthenticationInformation)
650	c.Assert(resp.BlobPublicAccess(), chk.Equals, PublicAccessNone)
651}
652
653func (s *aztestsSuite) TestContainerSetPermissionsPublicAccessBlob(c *chk.C) {
654	bsu := getBSU()
655	containerURL, _ := createNewContainer(c, bsu)
656
657	defer deleteContainer(c, containerURL)
658
659	_, err := containerURL.SetAccessPolicy(ctx, PublicAccessBlob, nil, ContainerAccessConditions{})
660	c.Assert(err, chk.IsNil)
661
662	resp, err := containerURL.GetAccessPolicy(ctx, LeaseAccessConditions{})
663	c.Assert(err, chk.IsNil)
664	c.Assert(resp.BlobPublicAccess(), chk.Equals, PublicAccessBlob)
665}
666
667func (s *aztestsSuite) TestContainerSetPermissionsPublicAccessContainer(c *chk.C) {
668	bsu := getBSU()
669	containerURL, _ := createNewContainer(c, bsu)
670
671	defer deleteContainer(c, containerURL)
672
673	_, err := containerURL.SetAccessPolicy(ctx, PublicAccessContainer, nil, ContainerAccessConditions{})
674	c.Assert(err, chk.IsNil)
675
676	resp, err := containerURL.GetAccessPolicy(ctx, LeaseAccessConditions{})
677	c.Assert(err, chk.IsNil)
678	c.Assert(resp.BlobPublicAccess(), chk.Equals, PublicAccessContainer)
679}
680
681func (s *aztestsSuite) TestContainerSetPermissionsACLSinglePolicy(c *chk.C) {
682	bsu := getBSU()
683	credential, err := getGenericCredential("")
684	if err != nil {
685		c.Fatal("Invalid credential")
686	}
687	containerURL, containerName := createNewContainer(c, bsu)
688	defer deleteContainer(c, containerURL)
689	_, blobName := createNewBlockBlob(c, containerURL)
690
691	start := time.Now().UTC().Add(-15 * time.Second)
692	expiry := start.Add(5 * time.Minute).UTC()
693	listOnly := AccessPolicyPermission{List: true}.String()
694	permissions := []SignedIdentifier{{
695		ID: "0000",
696		AccessPolicy: AccessPolicy{
697			Start:      &start,
698			Expiry:     &expiry,
699			Permission: &listOnly,
700		},
701	}}
702	_, err = containerURL.SetAccessPolicy(ctx, PublicAccessNone, permissions, ContainerAccessConditions{})
703	c.Assert(err, chk.IsNil)
704
705	serviceSASValues := BlobSASSignatureValues{Identifier: "0000", ContainerName: containerName}
706	queryParams, err := serviceSASValues.NewSASQueryParameters(credential)
707	if err != nil {
708		c.Fatal(err)
709	}
710
711	sasURL := bsu.URL()
712	sasURL.RawQuery = queryParams.Encode()
713	sasPipeline := NewPipeline(NewAnonymousCredential(), PipelineOptions{})
714	sasBlobServiceURL := NewServiceURL(sasURL, sasPipeline)
715
716	// Verifies that the SAS can access the resource
717	sasContainer := sasBlobServiceURL.NewContainerURL(containerName)
718	resp, err := sasContainer.ListBlobsFlatSegment(ctx, Marker{}, ListBlobsSegmentOptions{})
719	c.Assert(err, chk.IsNil)
720	c.Assert(resp.Segment.BlobItems[0].Name, chk.Equals, blobName)
721
722	// Verifies that successful sas access is not just because it's public
723	anonymousBlobService := NewServiceURL(bsu.URL(), sasPipeline)
724	anonymousContainer := anonymousBlobService.NewContainerURL(containerName)
725	_, err = anonymousContainer.ListBlobsFlatSegment(ctx, Marker{}, ListBlobsSegmentOptions{})
726	validateStorageError(c, err, ServiceCodeNoAuthenticationInformation)
727}
728
729func (s *aztestsSuite) TestContainerSetPermissionsACLMoreThanFive(c *chk.C) {
730	bsu := getBSU()
731	containerURL, _ := createNewContainer(c, bsu)
732
733	defer deleteContainer(c, containerURL)
734
735	start := time.Now().UTC()
736	expiry := start.Add(5 * time.Minute).UTC()
737	permissions := make([]SignedIdentifier, 6, 6)
738	listOnly := AccessPolicyPermission{Read: true}.String()
739	for i := 0; i < 6; i++ {
740		permissions[i] = SignedIdentifier{
741			ID: "000" + strconv.Itoa(i),
742			AccessPolicy: AccessPolicy{
743				Start:      &start,
744				Expiry:     &expiry,
745				Permission: &listOnly,
746			},
747		}
748	}
749
750	_, err := containerURL.SetAccessPolicy(ctx, PublicAccessBlob, permissions, ContainerAccessConditions{})
751	validateStorageError(c, err, ServiceCodeInvalidXMLDocument)
752}
753
754func (s *aztestsSuite) TestContainerSetPermissionsDeleteAndModifyACL(c *chk.C) {
755	bsu := getBSU()
756	containerURL, _ := createNewContainer(c, bsu)
757
758	defer deleteContainer(c, containerURL)
759
760	start := generateCurrentTimeWithModerateResolution()
761	expiry := start.Add(5 * time.Minute).UTC()
762	listOnly := AccessPolicyPermission{Read: true}.String()
763	permissions := make([]SignedIdentifier, 2, 2)
764	for i := 0; i < 2; i++ {
765		permissions[i] = SignedIdentifier{
766			ID: "000" + strconv.Itoa(i),
767			AccessPolicy: AccessPolicy{
768				Start:      &start,
769				Expiry:     &expiry,
770				Permission: &listOnly,
771			},
772		}
773	}
774
775	_, err := containerURL.SetAccessPolicy(ctx, PublicAccessBlob, permissions, ContainerAccessConditions{})
776	c.Assert(err, chk.IsNil)
777
778	resp, err := containerURL.GetAccessPolicy(ctx, LeaseAccessConditions{})
779	c.Assert(err, chk.IsNil)
780	c.Assert(resp.Items, chk.DeepEquals, permissions)
781
782	permissions = resp.Items[:1] // Delete the first policy by removing it from the slice
783	permissions[0].ID = "0004"   // Modify the remaining policy which is at index 0 in the new slice
784	_, err = containerURL.SetAccessPolicy(ctx, PublicAccessBlob, permissions, ContainerAccessConditions{})
785
786	resp, err = containerURL.GetAccessPolicy(ctx, LeaseAccessConditions{})
787	c.Assert(err, chk.IsNil)
788	c.Assert(resp.Items, chk.HasLen, 1)
789	c.Assert(resp.Items, chk.DeepEquals, permissions)
790}
791
792func (s *aztestsSuite) TestContainerSetPermissionsDeleteAllPolicies(c *chk.C) {
793	bsu := getBSU()
794	containerURL, _ := createNewContainer(c, bsu)
795
796	defer deleteContainer(c, containerURL)
797
798	start := time.Now().UTC()
799	expiry := start.Add(5 * time.Minute).UTC()
800	permissions := make([]SignedIdentifier, 2, 2)
801	listOnly := AccessPolicyPermission{Read: true}.String()
802	for i := 0; i < 2; i++ {
803		permissions[i] = SignedIdentifier{
804			ID: "000" + strconv.Itoa(i),
805			AccessPolicy: AccessPolicy{
806				Start:      &start,
807				Expiry:     &expiry,
808				Permission: &listOnly,
809			},
810		}
811	}
812
813	_, err := containerURL.SetAccessPolicy(ctx, PublicAccessBlob, permissions, ContainerAccessConditions{})
814	c.Assert(err, chk.IsNil)
815
816	_, err = containerURL.SetAccessPolicy(ctx, PublicAccessBlob, []SignedIdentifier{}, ContainerAccessConditions{})
817	c.Assert(err, chk.IsNil)
818
819	resp, err := containerURL.GetAccessPolicy(ctx, LeaseAccessConditions{})
820	c.Assert(err, chk.IsNil)
821	c.Assert(resp.Items, chk.HasLen, 0)
822}
823
824func (s *aztestsSuite) TestContainerSetPermissionsInvalidPolicyTimes(c *chk.C) {
825	bsu := getBSU()
826	containerURL, _ := createNewContainer(c, bsu)
827
828	defer deleteContainer(c, containerURL)
829
830	// Swap start and expiry
831	expiry := time.Now().UTC()
832	start := expiry.Add(5 * time.Minute).UTC()
833	permissions := make([]SignedIdentifier, 2, 2)
834	listOnly := AccessPolicyPermission{Read: true}.String()
835	for i := 0; i < 2; i++ {
836		permissions[i] = SignedIdentifier{
837			ID: "000" + strconv.Itoa(i),
838			AccessPolicy: AccessPolicy{
839				Start:      &start,
840				Expiry:     &expiry,
841				Permission: &listOnly,
842			},
843		}
844	}
845
846	_, err := containerURL.SetAccessPolicy(ctx, PublicAccessBlob, permissions, ContainerAccessConditions{})
847	c.Assert(err, chk.IsNil)
848}
849
850func (s *aztestsSuite) TestContainerSetPermissionsNilPolicySlice(c *chk.C) {
851	bsu := getBSU()
852	containerURL, _ := createNewContainer(c, bsu)
853
854	defer deleteContainer(c, containerURL)
855
856	_, err := containerURL.SetAccessPolicy(ctx, PublicAccessBlob, nil, ContainerAccessConditions{})
857	c.Assert(err, chk.IsNil)
858}
859
860func (s *aztestsSuite) TestContainerSetPermissionsSignedIdentifierTooLong(c *chk.C) {
861	bsu := getBSU()
862	containerURL, _ := createNewContainer(c, bsu)
863
864	defer deleteContainer(c, containerURL)
865
866	id := ""
867	for i := 0; i < 65; i++ {
868		id += "a"
869	}
870	expiry := time.Now().UTC()
871	start := expiry.Add(5 * time.Minute).UTC()
872	permissions := make([]SignedIdentifier, 2, 2)
873	listOnly := AccessPolicyPermission{Read: true}.String()
874	for i := 0; i < 2; i++ {
875		permissions[i] = SignedIdentifier{
876			ID: id,
877			AccessPolicy: AccessPolicy{
878				Start:      &start,
879				Expiry:     &expiry,
880				Permission: &listOnly,
881			},
882		}
883	}
884
885	_, err := containerURL.SetAccessPolicy(ctx, PublicAccessBlob, permissions, ContainerAccessConditions{})
886	validateStorageError(c, err, ServiceCodeInvalidXMLDocument)
887}
888
889func (s *aztestsSuite) TestContainerSetPermissionsIfModifiedSinceTrue(c *chk.C) {
890	currentTime := getRelativeTimeGMT(-10)
891	bsu := getBSU()
892	container, _ := createNewContainer(c, bsu)
893
894	defer deleteContainer(c, container)
895
896	_, err := container.SetAccessPolicy(ctx, PublicAccessNone, nil,
897		ContainerAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfModifiedSince: currentTime}})
898	c.Assert(err, chk.IsNil)
899
900	resp, err := container.GetAccessPolicy(ctx, LeaseAccessConditions{})
901	c.Assert(err, chk.IsNil)
902	c.Assert(resp.BlobPublicAccess(), chk.Equals, PublicAccessNone)
903}
904
905func (s *aztestsSuite) TestContainerSetPermissionsIfModifiedSinceFalse(c *chk.C) {
906	bsu := getBSU()
907	containerURL, _ := createNewContainer(c, bsu)
908
909	defer deleteContainer(c, containerURL)
910
911	currentTime := getRelativeTimeGMT(10)
912
913	_, err := containerURL.SetAccessPolicy(ctx, PublicAccessNone, nil,
914		ContainerAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfModifiedSince: currentTime}})
915	validateStorageError(c, err, ServiceCodeConditionNotMet)
916}
917
918func (s *aztestsSuite) TestContainerSetPermissionsIfUnModifiedSinceTrue(c *chk.C) {
919	bsu := getBSU()
920	containerURL, _ := createNewContainer(c, bsu)
921
922	defer deleteContainer(c, containerURL)
923
924	currentTime := getRelativeTimeGMT(10)
925
926	_, err := containerURL.SetAccessPolicy(ctx, PublicAccessNone, nil,
927		ContainerAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfUnmodifiedSince: currentTime}})
928	c.Assert(err, chk.IsNil)
929
930	resp, err := containerURL.GetAccessPolicy(ctx, LeaseAccessConditions{})
931	c.Assert(err, chk.IsNil)
932	c.Assert(resp.BlobPublicAccess(), chk.Equals, PublicAccessNone)
933}
934
935func (s *aztestsSuite) TestContainerSetPermissionsIfUnModifiedSinceFalse(c *chk.C) {
936	currentTime := getRelativeTimeGMT(-10)
937
938	bsu := getBSU()
939	containerURL, _ := createNewContainer(c, bsu)
940
941	defer deleteContainer(c, containerURL)
942
943	_, err := containerURL.SetAccessPolicy(ctx, PublicAccessNone, nil,
944		ContainerAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfUnmodifiedSince: currentTime}})
945	validateStorageError(c, err, ServiceCodeConditionNotMet)
946}
947
948func (s *aztestsSuite) TestContainerGetPropertiesAndMetadataNoMetadata(c *chk.C) {
949	bsu := getBSU()
950	containerURL, _ := createNewContainer(c, bsu)
951
952	defer deleteContainer(c, containerURL)
953
954	resp, err := containerURL.GetProperties(ctx, LeaseAccessConditions{})
955	c.Assert(err, chk.IsNil)
956	c.Assert(resp.NewMetadata(), chk.HasLen, 0)
957}
958
959func (s *aztestsSuite) TestContainerGetPropsAndMetaNonExistantContainer(c *chk.C) {
960	bsu := getBSU()
961	containerURL, _ := getContainerURL(c, bsu)
962
963	_, err := containerURL.GetProperties(ctx, LeaseAccessConditions{})
964	validateStorageError(c, err, ServiceCodeContainerNotFound)
965}
966
967func (s *aztestsSuite) TestContainerSetMetadataEmpty(c *chk.C) {
968	bsu := getBSU()
969	containerURL, _ := getContainerURL(c, bsu)
970	_, err := containerURL.Create(ctx, basicMetadata, PublicAccessBlob)
971
972	defer deleteContainer(c, containerURL)
973
974	_, err = containerURL.SetMetadata(ctx, Metadata{}, ContainerAccessConditions{})
975	c.Assert(err, chk.IsNil)
976
977	resp, err := containerURL.GetProperties(ctx, LeaseAccessConditions{})
978	c.Assert(err, chk.IsNil)
979	c.Assert(resp.NewMetadata(), chk.HasLen, 0)
980}
981
982func (*aztestsSuite) TestContainerSetMetadataNil(c *chk.C) {
983	bsu := getBSU()
984	containerURL, _ := getContainerURL(c, bsu)
985	_, err := containerURL.Create(ctx, basicMetadata, PublicAccessBlob)
986
987	defer deleteContainer(c, containerURL)
988
989	_, err = containerURL.SetMetadata(ctx, nil, ContainerAccessConditions{})
990	c.Assert(err, chk.IsNil)
991
992	resp, err := containerURL.GetProperties(ctx, LeaseAccessConditions{})
993	c.Assert(err, chk.IsNil)
994	c.Assert(resp.NewMetadata(), chk.HasLen, 0)
995}
996
997func (*aztestsSuite) TestContainerSetMetadataInvalidField(c *chk.C) {
998	bsu := getBSU()
999	containerURL, _ := createNewContainer(c, bsu)
1000
1001	defer deleteContainer(c, containerURL)
1002
1003	_, err := containerURL.SetMetadata(ctx, Metadata{"!nval!d Field!@#%": "value"}, ContainerAccessConditions{})
1004	c.Assert(err, chk.NotNil)
1005	c.Assert(strings.Contains(err.Error(), invalidHeaderErrorSubstring), chk.Equals, true)
1006}
1007
1008func (*aztestsSuite) TestContainerSetMetadataNonExistant(c *chk.C) {
1009	bsu := getBSU()
1010	containerURL, _ := getContainerURL(c, bsu)
1011
1012	_, err := containerURL.SetMetadata(ctx, nil, ContainerAccessConditions{})
1013	validateStorageError(c, err, ServiceCodeContainerNotFound)
1014}
1015
1016func (s *aztestsSuite) TestContainerSetMetadataIfModifiedSinceTrue(c *chk.C) {
1017	currentTime := getRelativeTimeGMT(-10)
1018
1019	bsu := getBSU()
1020	containerURL, _ := createNewContainer(c, bsu)
1021
1022	defer deleteContainer(c, containerURL)
1023
1024	_, err := containerURL.SetMetadata(ctx, basicMetadata,
1025		ContainerAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfModifiedSince: currentTime}})
1026	c.Assert(err, chk.IsNil)
1027
1028	resp, err := containerURL.GetProperties(ctx, LeaseAccessConditions{})
1029
1030	c.Assert(err, chk.IsNil)
1031	c.Assert(resp.NewMetadata(), chk.DeepEquals, basicMetadata)
1032
1033}
1034
1035func (s *aztestsSuite) TestContainerSetMetadataIfModifiedSinceFalse(c *chk.C) {
1036	bsu := getBSU()
1037	containerURL, _ := createNewContainer(c, bsu)
1038
1039	defer deleteContainer(c, containerURL)
1040
1041	currentTime := getRelativeTimeGMT(10)
1042
1043	_, err := containerURL.SetMetadata(ctx, basicMetadata,
1044		ContainerAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfModifiedSince: currentTime}})
1045
1046	validateStorageError(c, err, ServiceCodeConditionNotMet)
1047}
1048
1049func (s *aztestsSuite) TestContainerNewBlobURL(c *chk.C) {
1050	bsu := getBSU()
1051	containerURL, _ := getContainerURL(c, bsu)
1052
1053	blobURL := containerURL.NewBlobURL(blobPrefix)
1054	tempBlob := blobURL.URL()
1055	tempContainer := containerURL.URL()
1056	c.Assert(tempBlob.String(), chk.Equals, tempContainer.String()+"/"+blobPrefix)
1057	c.Assert(blobURL, chk.FitsTypeOf, BlobURL{})
1058}
1059
1060func (s *aztestsSuite) TestContainerNewBlockBlobURL(c *chk.C) {
1061	bsu := getBSU()
1062	containerURL, _ := getContainerURL(c, bsu)
1063
1064	blobURL := containerURL.NewBlockBlobURL(blobPrefix)
1065	tempBlob := blobURL.URL()
1066	tempContainer := containerURL.URL()
1067	c.Assert(tempBlob.String(), chk.Equals, tempContainer.String()+"/"+blobPrefix)
1068	c.Assert(blobURL, chk.FitsTypeOf, BlockBlobURL{})
1069}
1070