1package azblob 2 3import ( 4 "context" 5 "encoding/base64" 6 "encoding/binary" 7 "fmt" 8 "io/ioutil" 9 "math" 10 "time" 11 12 "crypto/md5" 13 14 "bytes" 15 "strings" 16 17 guuid "github.com/google/uuid" 18 chk "gopkg.in/check.v1" // go get gopkg.in/check.v1 19) 20 21func (s *aztestsSuite) TestStageGetBlocks(c *chk.C) { 22 bsu := getBSU() 23 container, _ := createNewContainer(c, bsu) 24 defer delContainer(c, container) 25 26 blob := container.NewBlockBlobURL(generateBlobName()) 27 28 blockID := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%6d", 0))) 29 30 putResp, err := blob.StageBlock(context.Background(), blockID, getReaderToRandomBytes(1024), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 31 c.Assert(err, chk.IsNil) 32 c.Assert(putResp.Response().StatusCode, chk.Equals, 201) 33 c.Assert(putResp.ContentMD5(), chk.Not(chk.Equals), "") 34 c.Assert(putResp.RequestID(), chk.Not(chk.Equals), "") 35 c.Assert(putResp.Version(), chk.Not(chk.Equals), "") 36 c.Assert(putResp.Date().IsZero(), chk.Equals, false) 37 38 blockList, err := blob.GetBlockList(context.Background(), BlockListAll, LeaseAccessConditions{}) 39 c.Assert(err, chk.IsNil) 40 c.Assert(blockList.Response().StatusCode, chk.Equals, 200) 41 c.Assert(blockList.LastModified().IsZero(), chk.Equals, true) 42 c.Assert(blockList.ETag(), chk.Equals, ETagNone) 43 c.Assert(blockList.ContentType(), chk.Not(chk.Equals), "") 44 c.Assert(blockList.BlobContentLength(), chk.Equals, int64(-1)) 45 c.Assert(blockList.RequestID(), chk.Not(chk.Equals), "") 46 c.Assert(blockList.Version(), chk.Not(chk.Equals), "") 47 c.Assert(blockList.Date().IsZero(), chk.Equals, false) 48 c.Assert(blockList.CommittedBlocks, chk.HasLen, 0) 49 c.Assert(blockList.UncommittedBlocks, chk.HasLen, 1) 50 51 listResp, err := blob.CommitBlockList(context.Background(), []string{blockID}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 52 c.Assert(err, chk.IsNil) 53 c.Assert(listResp.Response().StatusCode, chk.Equals, 201) 54 c.Assert(listResp.LastModified().IsZero(), chk.Equals, false) 55 c.Assert(listResp.ETag(), chk.Not(chk.Equals), ETagNone) 56 c.Assert(listResp.ContentMD5(), chk.Not(chk.Equals), "") 57 c.Assert(listResp.RequestID(), chk.Not(chk.Equals), "") 58 c.Assert(listResp.Version(), chk.Not(chk.Equals), "") 59 c.Assert(listResp.Date().IsZero(), chk.Equals, false) 60 61 blockList, err = blob.GetBlockList(context.Background(), BlockListAll, LeaseAccessConditions{}) 62 c.Assert(err, chk.IsNil) 63 c.Assert(blockList.Response().StatusCode, chk.Equals, 200) 64 c.Assert(blockList.LastModified().IsZero(), chk.Equals, false) 65 c.Assert(blockList.ETag(), chk.Not(chk.Equals), ETagNone) 66 c.Assert(blockList.ContentType(), chk.Not(chk.Equals), "") 67 c.Assert(blockList.BlobContentLength(), chk.Equals, int64(1024)) 68 c.Assert(blockList.RequestID(), chk.Not(chk.Equals), "") 69 c.Assert(blockList.Version(), chk.Not(chk.Equals), "") 70 c.Assert(blockList.Date().IsZero(), chk.Equals, false) 71 c.Assert(blockList.CommittedBlocks, chk.HasLen, 1) 72 c.Assert(blockList.UncommittedBlocks, chk.HasLen, 0) 73} 74 75func (s *aztestsSuite) TestStageBlockFromURL(c *chk.C) { 76 bsu := getBSU() 77 credential, err := getGenericCredential("") 78 if err != nil { 79 c.Fatal("Invalid credential") 80 } 81 container, _ := createNewContainer(c, bsu) 82 defer delContainer(c, container) 83 84 testSize := 8 * 1024 * 1024 // 8MB 85 r, sourceData := getRandomDataAndReader(testSize) 86 ctx := context.Background() // Use default Background context 87 srcBlob := container.NewBlockBlobURL(generateBlobName()) 88 destBlob := container.NewBlockBlobURL(generateBlobName()) 89 90 // Prepare source blob for copy. 91 uploadSrcResp, err := srcBlob.Upload(ctx, r, BlobHTTPHeaders{}, Metadata{}, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 92 c.Assert(err, chk.IsNil) 93 c.Assert(uploadSrcResp.Response().StatusCode, chk.Equals, 201) 94 95 // Get source blob URL with SAS for StageFromURL. 96 srcBlobParts := NewBlobURLParts(srcBlob.URL()) 97 98 srcBlobParts.SAS, err = BlobSASSignatureValues{ 99 Protocol: SASProtocolHTTPS, // Users MUST use HTTPS (not HTTP) 100 ExpiryTime: time.Now().UTC().Add(48 * time.Hour), // 48-hours before expiration 101 ContainerName: srcBlobParts.ContainerName, 102 BlobName: srcBlobParts.BlobName, 103 Permissions: BlobSASPermissions{Read: true}.String(), 104 }.NewSASQueryParameters(credential) 105 if err != nil { 106 c.Fatal(err) 107 } 108 109 srcBlobURLWithSAS := srcBlobParts.URL() 110 111 // Stage blocks from URL. 112 blockID1, blockID2 := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%6d", 0))), base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%6d", 1))) 113 stageResp1, err := destBlob.StageBlockFromURL(ctx, blockID1, srcBlobURLWithSAS, 0, 4*1024*1024, LeaseAccessConditions{}, ModifiedAccessConditions{}, ClientProvidedKeyOptions{}) 114 c.Assert(err, chk.IsNil) 115 c.Assert(stageResp1.Response().StatusCode, chk.Equals, 201) 116 c.Assert(stageResp1.ContentMD5(), chk.Not(chk.Equals), "") 117 c.Assert(stageResp1.RequestID(), chk.Not(chk.Equals), "") 118 c.Assert(stageResp1.Version(), chk.Not(chk.Equals), "") 119 c.Assert(stageResp1.Date().IsZero(), chk.Equals, false) 120 121 stageResp2, err := destBlob.StageBlockFromURL(ctx, blockID2, srcBlobURLWithSAS, 4*1024*1024, CountToEnd, LeaseAccessConditions{}, ModifiedAccessConditions{}, ClientProvidedKeyOptions{}) 122 c.Assert(err, chk.IsNil) 123 c.Assert(stageResp2.Response().StatusCode, chk.Equals, 201) 124 c.Assert(stageResp2.ContentMD5(), chk.Not(chk.Equals), "") 125 c.Assert(stageResp2.RequestID(), chk.Not(chk.Equals), "") 126 c.Assert(stageResp2.Version(), chk.Not(chk.Equals), "") 127 c.Assert(stageResp2.Date().IsZero(), chk.Equals, false) 128 129 // Check block list. 130 blockList, err := destBlob.GetBlockList(context.Background(), BlockListAll, LeaseAccessConditions{}) 131 c.Assert(err, chk.IsNil) 132 c.Assert(blockList.Response().StatusCode, chk.Equals, 200) 133 c.Assert(blockList.CommittedBlocks, chk.HasLen, 0) 134 c.Assert(blockList.UncommittedBlocks, chk.HasLen, 2) 135 136 // Commit block list. 137 listResp, err := destBlob.CommitBlockList(context.Background(), []string{blockID1, blockID2}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 138 c.Assert(err, chk.IsNil) 139 c.Assert(listResp.Response().StatusCode, chk.Equals, 201) 140 141 // Check data integrity through downloading. 142 downloadResp, err := destBlob.BlobURL.Download(ctx, 0, CountToEnd, BlobAccessConditions{}, false, ClientProvidedKeyOptions{}) 143 c.Assert(err, chk.IsNil) 144 destData, err := ioutil.ReadAll(downloadResp.Body(RetryReaderOptions{})) 145 c.Assert(err, chk.IsNil) 146 c.Assert(destData, chk.DeepEquals, sourceData) 147} 148 149func (s *aztestsSuite) TestCopyBlockBlobFromURL(c *chk.C) { 150 bsu := getBSU() 151 credential, err := getGenericCredential("") 152 if err != nil { 153 c.Fatal("Invalid credential") 154 } 155 container, _ := createNewContainer(c, bsu) 156 defer delContainer(c, container) 157 158 testSize := 8 * 1024 * 1024 // 8MB 159 r, sourceData := getRandomDataAndReader(testSize) 160 sourceDataMD5Value := md5.Sum(sourceData) 161 ctx := context.Background() // Use default Background context 162 srcBlob := container.NewBlockBlobURL(generateBlobName()) 163 destBlob := container.NewBlockBlobURL(generateBlobName()) 164 165 // Prepare source blob for copy. 166 uploadSrcResp, err := srcBlob.Upload(ctx, r, BlobHTTPHeaders{}, Metadata{}, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 167 c.Assert(err, chk.IsNil) 168 c.Assert(uploadSrcResp.Response().StatusCode, chk.Equals, 201) 169 170 // Get source blob URL with SAS for StageFromURL. 171 srcBlobParts := NewBlobURLParts(srcBlob.URL()) 172 173 srcBlobParts.SAS, err = BlobSASSignatureValues{ 174 Protocol: SASProtocolHTTPS, // Users MUST use HTTPS (not HTTP) 175 ExpiryTime: time.Now().UTC().Add(48 * time.Hour), // 48-hours before expiration 176 ContainerName: srcBlobParts.ContainerName, 177 BlobName: srcBlobParts.BlobName, 178 Permissions: BlobSASPermissions{Read: true}.String(), 179 }.NewSASQueryParameters(credential) 180 if err != nil { 181 c.Fatal(err) 182 } 183 184 srcBlobURLWithSAS := srcBlobParts.URL() 185 186 // Invoke copy blob from URL. 187 resp, err := destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{"foo": "bar"}, ModifiedAccessConditions{}, BlobAccessConditions{}, sourceDataMD5Value[:], DefaultAccessTier, nil) 188 c.Assert(err, chk.IsNil) 189 c.Assert(resp.Response().StatusCode, chk.Equals, 202) 190 c.Assert(resp.ETag(), chk.Not(chk.Equals), "") 191 c.Assert(resp.RequestID(), chk.Not(chk.Equals), "") 192 c.Assert(resp.Version(), chk.Not(chk.Equals), "") 193 c.Assert(resp.Date().IsZero(), chk.Equals, false) 194 c.Assert(resp.CopyID(), chk.Not(chk.Equals), "") 195 c.Assert(resp.ContentMD5(), chk.DeepEquals, sourceDataMD5Value[:]) 196 c.Assert(string(resp.CopyStatus()), chk.DeepEquals, "success") 197 198 // Check data integrity through downloading. 199 downloadResp, err := destBlob.BlobURL.Download(ctx, 0, CountToEnd, BlobAccessConditions{}, false, ClientProvidedKeyOptions{}) 200 c.Assert(err, chk.IsNil) 201 destData, err := ioutil.ReadAll(downloadResp.Body(RetryReaderOptions{})) 202 c.Assert(err, chk.IsNil) 203 c.Assert(destData, chk.DeepEquals, sourceData) 204 205 // Make sure the metadata got copied over 206 c.Assert(len(downloadResp.NewMetadata()), chk.Equals, 1) 207 208 // Edge case 1: Provide bad MD5 and make sure the copy fails 209 _, badMD5 := getRandomDataAndReader(16) 210 _, err = destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{}, ModifiedAccessConditions{}, BlobAccessConditions{}, badMD5, DefaultAccessTier, nil) 211 c.Assert(err, chk.NotNil) 212 213 // Edge case 2: Not providing any source MD5 should see the CRC getting returned instead 214 resp, err = destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{}, ModifiedAccessConditions{}, BlobAccessConditions{}, nil, DefaultAccessTier, nil) 215 c.Assert(err, chk.IsNil) 216 c.Assert(resp.Response().StatusCode, chk.Equals, 202) 217 c.Assert(resp.XMsContentCrc64(), chk.Not(chk.Equals), "") 218} 219 220func (s *aztestsSuite) TestBlobSASQueryParamOverrideResponseHeaders(c *chk.C) { 221 bsu := getBSU() 222 credential, err := getGenericCredential("") 223 if err != nil { 224 c.Fatal("Invalid credential") 225 } 226 container, _ := createNewContainer(c, bsu) 227 defer delContainer(c, container) 228 229 testSize := 8 * 1024 * 1024 // 8MB 230 r, _ := getRandomDataAndReader(testSize) 231 ctx := context.Background() // Use default Background context 232 blob := container.NewBlockBlobURL(generateBlobName()) 233 234 uploadResp, err := blob.Upload(ctx, r, BlobHTTPHeaders{}, Metadata{}, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 235 c.Assert(err, chk.IsNil) 236 c.Assert(uploadResp.Response().StatusCode, chk.Equals, 201) 237 238 // Get blob URL with SAS. 239 blobParts := NewBlobURLParts(blob.URL()) 240 241 cacheControlVal := "cache-control-override" 242 contentDispositionVal := "content-disposition-override" 243 contentEncodingVal := "content-encoding-override" 244 contentLanguageVal := "content-language-override" 245 contentTypeVal := "content-type-override" 246 247 blobParts.SAS, err = BlobSASSignatureValues{ 248 Protocol: SASProtocolHTTPS, // Users MUST use HTTPS (not HTTP) 249 ExpiryTime: time.Now().UTC().Add(48 * time.Hour), // 48-hours before expiration 250 ContainerName: blobParts.ContainerName, 251 BlobName: blobParts.BlobName, 252 Permissions: BlobSASPermissions{Read: true}.String(), 253 CacheControl: cacheControlVal, 254 ContentDisposition: contentDispositionVal, 255 ContentEncoding: contentEncodingVal, 256 ContentLanguage: contentLanguageVal, 257 ContentType: contentTypeVal, 258 }.NewSASQueryParameters(credential) 259 if err != nil { 260 c.Fatal(err) 261 } 262 263 blobURL := NewBlobURL(blobParts.URL(), NewPipeline(NewAnonymousCredential(), PipelineOptions{})) 264 265 gResp, err := blobURL.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 266 c.Assert(err, chk.IsNil) 267 c.Assert(gResp.CacheControl(), chk.Equals, cacheControlVal) 268 c.Assert(gResp.ContentDisposition(), chk.Equals, contentDispositionVal) 269 c.Assert(gResp.ContentEncoding(), chk.Equals, contentEncodingVal) 270 c.Assert(gResp.ContentLanguage(), chk.Equals, contentLanguageVal) 271 c.Assert(gResp.ContentType(), chk.Equals, contentTypeVal) 272} 273 274func (s *aztestsSuite) TestStageBlockWithMD5(c *chk.C) { 275 bsu := getBSU() 276 container, _ := createNewContainer(c, bsu) 277 defer delContainer(c, container) 278 279 blob := container.NewBlockBlobURL(generateBlobName()) 280 blockID := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%6d", 0))) 281 282 // test put block with valid MD5 value 283 readerToBody, body := getRandomDataAndReader(1024) 284 md5Value := md5.Sum(body) 285 putResp, err := blob.StageBlock(context.Background(), blockID, readerToBody, LeaseAccessConditions{}, md5Value[:], ClientProvidedKeyOptions{}) 286 c.Assert(err, chk.IsNil) 287 c.Assert(putResp.Response().StatusCode, chk.Equals, 201) 288 c.Assert(putResp.ContentMD5(), chk.DeepEquals, md5Value[:]) 289 c.Assert(putResp.RequestID(), chk.Not(chk.Equals), "") 290 c.Assert(putResp.Version(), chk.Not(chk.Equals), "") 291 c.Assert(putResp.Date().IsZero(), chk.Equals, false) 292 293 // test put block with bad MD5 value 294 readerToBody, body = getRandomDataAndReader(1024) 295 _, badMD5 := getRandomDataAndReader(16) 296 putResp, err = blob.StageBlock(context.Background(), blockID, readerToBody, LeaseAccessConditions{}, badMD5[:], ClientProvidedKeyOptions{}) 297 validateStorageError(c, err, ServiceCodeMd5Mismatch) 298} 299 300func (s *aztestsSuite) TestBlobPutBlobNonEmptyBody(c *chk.C) { 301 bsu := getBSU() 302 containerURL, _ := createNewContainer(c, bsu) 303 defer deleteContainer(c, containerURL) 304 blobURL, _ := getBlockBlobURL(c, containerURL) 305 306 _, err := blobURL.Upload(ctx, strings.NewReader(blockBlobDefaultData), BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 307 c.Assert(err, chk.IsNil) 308 309 resp, err := blobURL.Download(ctx, 0, 0, BlobAccessConditions{}, false, ClientProvidedKeyOptions{}) 310 c.Assert(err, chk.IsNil) 311 data, err := ioutil.ReadAll(resp.Response().Body) 312 c.Assert(string(data), chk.Equals, blockBlobDefaultData) 313} 314 315func (s *aztestsSuite) TestBlobPutBlobHTTPHeaders(c *chk.C) { 316 bsu := getBSU() 317 containerURL, _ := createNewContainer(c, bsu) 318 defer deleteContainer(c, containerURL) 319 blobURL, _ := getBlockBlobURL(c, containerURL) 320 321 _, err := blobURL.Upload(ctx, bytes.NewReader(nil), basicHeaders, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 322 c.Assert(err, chk.IsNil) 323 324 resp, err := blobURL.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 325 c.Assert(err, chk.IsNil) 326 h := resp.NewHTTPHeaders() 327 h.ContentMD5 = nil // the service generates a MD5 value, omit before comparing 328 c.Assert(h, chk.DeepEquals, basicHeaders) 329} 330 331func (s *aztestsSuite) TestBlobPutBlobMetadataNotEmpty(c *chk.C) { 332 bsu := getBSU() 333 containerURL, _ := createNewContainer(c, bsu) 334 defer deleteContainer(c, containerURL) 335 blobURL, _ := getBlockBlobURL(c, containerURL) 336 337 _, err := blobURL.Upload(ctx, bytes.NewReader(nil), BlobHTTPHeaders{}, basicMetadata, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 338 c.Assert(err, chk.IsNil) 339 340 resp, err := blobURL.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 341 c.Assert(err, chk.IsNil) 342 c.Assert(resp.NewMetadata(), chk.DeepEquals, basicMetadata) 343} 344 345func (s *aztestsSuite) TestBlobPutBlobMetadataEmpty(c *chk.C) { 346 bsu := getBSU() 347 containerURL, _ := createNewContainer(c, bsu) 348 defer deleteContainer(c, containerURL) 349 blobURL, _ := getBlockBlobURL(c, containerURL) 350 351 _, err := blobURL.Upload(ctx, bytes.NewReader(nil), BlobHTTPHeaders{}, Metadata{}, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 352 c.Assert(err, chk.IsNil) 353 354 resp, err := blobURL.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 355 c.Assert(err, chk.IsNil) 356 c.Assert(resp.NewMetadata(), chk.HasLen, 0) 357} 358 359func (s *aztestsSuite) TestBlobPutBlobMetadataInvalid(c *chk.C) { 360 bsu := getBSU() 361 containerURL, _ := createNewContainer(c, bsu) 362 defer deleteContainer(c, containerURL) 363 blobURL, _ := getBlockBlobURL(c, containerURL) 364 365 _, err := blobURL.Upload(ctx, nil, BlobHTTPHeaders{}, Metadata{"In valid!": "bar"}, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 366 c.Assert(strings.Contains(err.Error(), validationErrorSubstring), chk.Equals, true) 367} 368 369func (s *aztestsSuite) TestBlobPutBlobIfModifiedSinceTrue(c *chk.C) { 370 bsu := getBSU() 371 containerURL, _ := createNewContainer(c, bsu) 372 defer deleteContainer(c, containerURL) 373 blobURL, _ := createNewBlockBlob(c, containerURL) 374 375 currentTime := getRelativeTimeGMT(-10) 376 377 _, err := blobURL.Upload(ctx, bytes.NewReader(nil), BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfModifiedSince: currentTime}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 378 c.Assert(err, chk.IsNil) 379 380 validateUpload(c, blobURL) 381} 382 383func (s *aztestsSuite) TestBlobPutBlobIfModifiedSinceFalse(c *chk.C) { 384 bsu := getBSU() 385 containerURL, _ := createNewContainer(c, bsu) 386 defer deleteContainer(c, containerURL) 387 blobURL, _ := createNewBlockBlob(c, containerURL) 388 389 currentTime := getRelativeTimeGMT(10) 390 391 _, err := blobURL.Upload(ctx, bytes.NewReader(nil), BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfModifiedSince: currentTime}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 392 validateStorageError(c, err, ServiceCodeConditionNotMet) 393} 394 395func (s *aztestsSuite) TestBlobPutBlobIfUnmodifiedSinceTrue(c *chk.C) { 396 bsu := getBSU() 397 containerURL, _ := createNewContainer(c, bsu) 398 defer deleteContainer(c, containerURL) 399 blobURL, _ := createNewBlockBlob(c, containerURL) 400 401 currentTime := getRelativeTimeGMT(10) 402 403 _, err := blobURL.Upload(ctx, bytes.NewReader(nil), BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfUnmodifiedSince: currentTime}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 404 c.Assert(err, chk.IsNil) 405 406 validateUpload(c, blobURL) 407} 408 409func (s *aztestsSuite) TestBlobPutBlobIfUnmodifiedSinceFalse(c *chk.C) { 410 bsu := getBSU() 411 containerURL, _ := createNewContainer(c, bsu) 412 defer deleteContainer(c, containerURL) 413 blobURL, _ := createNewBlockBlob(c, containerURL) 414 415 currentTime := getRelativeTimeGMT(-10) 416 417 _, err := blobURL.Upload(ctx, bytes.NewReader(nil), BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfUnmodifiedSince: currentTime}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 418 validateStorageError(c, err, ServiceCodeConditionNotMet) 419} 420 421func (s *aztestsSuite) TestBlobPutBlobIfMatchTrue(c *chk.C) { 422 bsu := getBSU() 423 containerURL, _ := createNewContainer(c, bsu) 424 defer deleteContainer(c, containerURL) 425 blobURL, _ := createNewBlockBlob(c, containerURL) 426 427 resp, err := blobURL.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 428 c.Assert(err, chk.IsNil) 429 430 _, err = blobURL.Upload(ctx, bytes.NewReader(nil), BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfMatch: resp.ETag()}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 431 c.Assert(err, chk.IsNil) 432 433 validateUpload(c, blobURL) 434} 435 436func (s *aztestsSuite) TestBlobPutBlobIfMatchFalse(c *chk.C) { 437 bsu := getBSU() 438 containerURL, _ := createNewContainer(c, bsu) 439 defer deleteContainer(c, containerURL) 440 blobURL, _ := createNewBlockBlob(c, containerURL) 441 442 _, err := blobURL.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 443 c.Assert(err, chk.IsNil) 444 445 _, err = blobURL.Upload(ctx, bytes.NewReader(nil), BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfMatch: ETag("garbage")}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 446 validateStorageError(c, err, ServiceCodeConditionNotMet) 447} 448 449func (s *aztestsSuite) TestBlobPutBlobIfNoneMatchTrue(c *chk.C) { 450 bsu := getBSU() 451 containerURL, _ := createNewContainer(c, bsu) 452 defer deleteContainer(c, containerURL) 453 blobURL, _ := createNewBlockBlob(c, containerURL) 454 455 _, err := blobURL.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 456 c.Assert(err, chk.IsNil) 457 458 _, err = blobURL.Upload(ctx, bytes.NewReader(nil), BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfNoneMatch: ETag("garbage")}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 459 c.Assert(err, chk.IsNil) 460 461 validateUpload(c, blobURL) 462} 463 464func (s *aztestsSuite) TestBlobPutBlobIfNoneMatchFalse(c *chk.C) { 465 bsu := getBSU() 466 containerURL, _ := createNewContainer(c, bsu) 467 defer deleteContainer(c, containerURL) 468 blobURL, _ := createNewBlockBlob(c, containerURL) 469 470 resp, err := blobURL.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 471 c.Assert(err, chk.IsNil) 472 473 _, err = blobURL.Upload(ctx, bytes.NewReader(nil), BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfNoneMatch: resp.ETag()}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 474 validateStorageError(c, err, ServiceCodeConditionNotMet) 475} 476 477var blockID string // a single blockID used in tests when only a single ID is needed 478 479func init() { 480 u := [64]byte{} 481 binary.BigEndian.PutUint32(u[len(guuid.UUID{}):], math.MaxUint32) 482 blockID = base64.StdEncoding.EncodeToString(u[:]) 483} 484 485func (s *aztestsSuite) TestBlobGetBlockListNone(c *chk.C) { 486 bsu := getBSU() 487 containerURL, _ := createNewContainer(c, bsu) 488 defer deleteContainer(c, containerURL) 489 blobURL, _ := getBlockBlobURL(c, containerURL) 490 491 _, err := blobURL.StageBlock(ctx, blockID, strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 492 c.Assert(err, chk.IsNil) 493 494 resp, err := blobURL.GetBlockList(ctx, BlockListNone, LeaseAccessConditions{}) 495 c.Assert(err, chk.IsNil) 496 c.Assert(resp.CommittedBlocks, chk.HasLen, 0) 497 c.Assert(resp.UncommittedBlocks, chk.HasLen, 0) // Not specifying a block list type should default to only returning committed blocks 498} 499 500func (s *aztestsSuite) TestBlobGetBlockListUncommitted(c *chk.C) { 501 bsu := getBSU() 502 containerURL, _ := createNewContainer(c, bsu) 503 defer deleteContainer(c, containerURL) 504 blobURL, _ := getBlockBlobURL(c, containerURL) 505 506 _, err := blobURL.StageBlock(ctx, blockID, strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 507 c.Assert(err, chk.IsNil) 508 509 resp, err := blobURL.GetBlockList(ctx, BlockListUncommitted, LeaseAccessConditions{}) 510 c.Assert(err, chk.IsNil) 511 c.Assert(resp.CommittedBlocks, chk.HasLen, 0) 512 c.Assert(resp.UncommittedBlocks, chk.HasLen, 1) 513} 514 515func (s *aztestsSuite) TestBlobGetBlockListCommitted(c *chk.C) { 516 bsu := getBSU() 517 containerURL, _ := createNewContainer(c, bsu) 518 defer deleteContainer(c, containerURL) 519 blobURL, _ := getBlockBlobURL(c, containerURL) 520 521 _, err := blobURL.StageBlock(ctx, blockID, strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 522 c.Assert(err, chk.IsNil) 523 524 _, err = blobURL.CommitBlockList(ctx, []string{blockID}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 525 526 resp, err := blobURL.GetBlockList(ctx, BlockListCommitted, LeaseAccessConditions{}) 527 c.Assert(err, chk.IsNil) 528 c.Assert(resp.CommittedBlocks, chk.HasLen, 1) 529 c.Assert(resp.UncommittedBlocks, chk.HasLen, 0) 530} 531 532func (s *aztestsSuite) TestBlobGetBlockListCommittedEmpty(c *chk.C) { 533 bsu := getBSU() 534 containerURL, _ := createNewContainer(c, bsu) 535 defer deleteContainer(c, containerURL) 536 blobURL, _ := getBlockBlobURL(c, containerURL) 537 538 _, err := blobURL.StageBlock(ctx, blockID, strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 539 c.Assert(err, chk.IsNil) 540 541 resp, err := blobURL.GetBlockList(ctx, BlockListCommitted, LeaseAccessConditions{}) 542 c.Assert(err, chk.IsNil) 543 c.Assert(resp.CommittedBlocks, chk.HasLen, 0) 544 c.Assert(resp.UncommittedBlocks, chk.HasLen, 0) 545} 546 547func (s *aztestsSuite) TestBlobGetBlockListBothEmpty(c *chk.C) { 548 bsu := getBSU() 549 containerURL, _ := createNewContainer(c, bsu) 550 defer deleteContainer(c, containerURL) 551 blobURL, _ := getBlockBlobURL(c, containerURL) 552 553 _, err := blobURL.GetBlockList(ctx, BlockListAll, LeaseAccessConditions{}) 554 validateStorageError(c, err, ServiceCodeBlobNotFound) 555} 556 557func (s *aztestsSuite) TestBlobGetBlockListBothNotEmpty(c *chk.C) { 558 bsu := getBSU() 559 containerURL, _ := createNewContainer(c, bsu) 560 defer deleteContainer(c, containerURL) 561 blobURL, _ := getBlockBlobURL(c, containerURL) 562 563 id := newID() 564 565 // Put and commit two blocks 566 _, err := blobURL.StageBlock(ctx, id.next(), strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 567 c.Assert(err, chk.IsNil) 568 _, err = blobURL.StageBlock(ctx, id.next(), strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 569 c.Assert(err, chk.IsNil) 570 _, err = blobURL.CommitBlockList(ctx, id.issued(), BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 571 c.Assert(err, chk.IsNil) 572 573 // Put two uncommitted blocks 574 _, err = blobURL.StageBlock(ctx, id.next(), strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 575 c.Assert(err, chk.IsNil) 576 _, err = blobURL.StageBlock(ctx, id.next(), strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 577 c.Assert(err, chk.IsNil) 578 579 resp, err := blobURL.GetBlockList(ctx, BlockListAll, LeaseAccessConditions{}) 580 c.Assert(err, chk.IsNil) 581 c.Assert(resp.CommittedBlocks[0].Name, chk.Equals, id.issued()[0]) 582 c.Assert(resp.CommittedBlocks[1].Name, chk.Equals, id.issued()[1]) // Committed blocks are returned in the order they are committed (in the commit list) 583 c.Assert(resp.UncommittedBlocks[0].Name, chk.Equals, id.issued()[2]) // Uncommitted blocks are returned in alphabetical order 584 c.Assert(resp.UncommittedBlocks[1].Name, chk.Equals, id.issued()[3]) 585} 586 587func (s *aztestsSuite) TestBlobGetBlockListInvalidType(c *chk.C) { 588 bsu := getBSU() 589 containerURL, _ := createNewContainer(c, bsu) 590 defer deleteContainer(c, containerURL) 591 blobURL, _ := getBlockBlobURL(c, containerURL) 592 593 _, err := blobURL.StageBlock(ctx, blockID, strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 594 c.Assert(err, chk.IsNil) 595 596 _, err = blobURL.GetBlockList(ctx, BlockListType("garbage"), LeaseAccessConditions{}) 597 validateStorageError(c, err, ServiceCodeInvalidQueryParameterValue) 598} 599 600func (s *aztestsSuite) TestBlobGetBlockListSnapshot(c *chk.C) { 601 bsu := getBSU() 602 containerURL, _ := createNewContainer(c, bsu) 603 defer deleteContainer(c, containerURL) 604 blobURL, _ := getBlockBlobURL(c, containerURL) 605 606 _, err := blobURL.StageBlock(ctx, blockID, strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 607 c.Assert(err, chk.IsNil) 608 _, err = blobURL.CommitBlockList(ctx, []string{blockID}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 609 c.Assert(err, chk.IsNil) 610 611 resp, err := blobURL.CreateSnapshot(ctx, nil, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 612 c.Assert(err, chk.IsNil) 613 snapshotURL := blobURL.WithSnapshot(resp.Snapshot()) 614 615 resp2, err := snapshotURL.GetBlockList(ctx, BlockListAll, LeaseAccessConditions{}) 616 c.Assert(err, chk.IsNil) 617 c.Assert(resp2.CommittedBlocks, chk.HasLen, 1) 618} 619 620func (s *aztestsSuite) TestBlobPutBlockIDInvalidCharacters(c *chk.C) { 621 bsu := getBSU() 622 containerURL, _ := createNewContainer(c, bsu) 623 defer deleteContainer(c, containerURL) 624 blobURL, _ := getBlockBlobURL(c, containerURL) 625 626 _, err := blobURL.StageBlock(ctx, "!!", strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 627 validateStorageError(c, err, ServiceCodeInvalidQueryParameterValue) 628} 629 630func (s *aztestsSuite) TestBlobPutBlockIDInvalidLength(c *chk.C) { 631 bsu := getBSU() 632 containerURL, _ := createNewContainer(c, bsu) 633 defer deleteContainer(c, containerURL) 634 blobURL, _ := getBlockBlobURL(c, containerURL) 635 636 _, err := blobURL.StageBlock(ctx, blockID, strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 637 c.Assert(err, chk.IsNil) 638 _, err = blobURL.StageBlock(ctx, "00000000", strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 639 validateStorageError(c, err, ServiceCodeInvalidBlobOrBlock) 640} 641 642func (s *aztestsSuite) TestBlobPutBlockEmptyBody(c *chk.C) { 643 bsu := getBSU() 644 containerURL, _ := createNewContainer(c, bsu) 645 defer deleteContainer(c, containerURL) 646 blobURL, _ := getBlockBlobURL(c, containerURL) 647 648 _, err := blobURL.StageBlock(ctx, blockID, strings.NewReader(""), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 649 validateStorageError(c, err, ServiceCodeInvalidHeaderValue) 650} 651 652func setupPutBlockListTest(c *chk.C) (containerURL ContainerURL, blobURL BlockBlobURL, id string) { 653 bsu := getBSU() 654 containerURL, _ = createNewContainer(c, bsu) 655 blobURL, _ = getBlockBlobURL(c, containerURL) 656 657 _, err := blobURL.StageBlock(ctx, blockID, strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 658 c.Assert(err, chk.IsNil) 659 return containerURL, blobURL, blockID 660} 661 662func (s *aztestsSuite) TestBlobPutBlockListInvalidID(c *chk.C) { 663 containerURL, blobURL, id := setupPutBlockListTest(c) 664 defer deleteContainer(c, containerURL) 665 666 _, err := blobURL.CommitBlockList(ctx, []string{id[:2]}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 667 validateStorageError(c, err, ServiceCodeInvalidBlockID) 668} 669 670func (s *aztestsSuite) TestBlobPutBlockListDuplicateBlocks(c *chk.C) { 671 containerURL, blobURL, id := setupPutBlockListTest(c) 672 defer deleteContainer(c, containerURL) 673 674 _, err := blobURL.CommitBlockList(ctx, []string{id, id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 675 c.Assert(err, chk.IsNil) 676 677 resp, err := blobURL.GetBlockList(ctx, BlockListAll, LeaseAccessConditions{}) 678 c.Assert(err, chk.IsNil) 679 c.Assert(resp.CommittedBlocks, chk.HasLen, 2) 680} 681 682func (s *aztestsSuite) TestBlobPutBlockListEmptyList(c *chk.C) { 683 containerURL, blobURL, _ := setupPutBlockListTest(c) 684 defer deleteContainer(c, containerURL) 685 686 _, err := blobURL.CommitBlockList(ctx, []string{}, BlobHTTPHeaders{}, Metadata{}, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 687 c.Assert(err, chk.IsNil) 688 689 resp, err := blobURL.GetBlockList(ctx, BlockListAll, LeaseAccessConditions{}) 690 c.Assert(err, chk.IsNil) 691 c.Assert(resp.CommittedBlocks, chk.HasLen, 0) 692} 693 694func (s *aztestsSuite) TestBlobPutBlockListMetadataEmpty(c *chk.C) { 695 containerURL, blobURL, id := setupPutBlockListTest(c) 696 defer deleteContainer(c, containerURL) 697 698 _, err := blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, Metadata{}, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 699 c.Assert(err, chk.IsNil) 700 701 resp, err := blobURL.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 702 c.Assert(err, chk.IsNil) 703 c.Assert(resp.NewMetadata(), chk.HasLen, 0) 704} 705 706func (s *aztestsSuite) TestBlobPutBlockListMetadataNonEmpty(c *chk.C) { 707 containerURL, blobURL, id := setupPutBlockListTest(c) 708 defer deleteContainer(c, containerURL) 709 710 _, err := blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, basicMetadata, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 711 c.Assert(err, chk.IsNil) 712 713 resp, err := blobURL.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 714 c.Assert(err, chk.IsNil) 715 c.Assert(resp.NewMetadata(), chk.DeepEquals, basicMetadata) 716} 717 718func (s *aztestsSuite) TestBlobPutBlockListHTTPHeaders(c *chk.C) { 719 containerURL, blobURL, id := setupPutBlockListTest(c) 720 defer deleteContainer(c, containerURL) 721 722 _, err := blobURL.CommitBlockList(ctx, []string{id}, basicHeaders, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 723 c.Assert(err, chk.IsNil) 724 725 resp, _ := blobURL.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 726 h := resp.NewHTTPHeaders() 727 c.Assert(h, chk.DeepEquals, basicHeaders) 728} 729 730func (s *aztestsSuite) TestBlobPutBlockListHTTPHeadersEmpty(c *chk.C) { 731 containerURL, blobURL, id := setupPutBlockListTest(c) 732 defer deleteContainer(c, containerURL) 733 734 _, err := blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{ContentDisposition: "my_disposition"}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 735 c.Assert(err, chk.IsNil) 736 737 _, err = blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 738 c.Assert(err, chk.IsNil) 739 740 resp, err := blobURL.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 741 c.Assert(err, chk.IsNil) 742 c.Assert(resp.ContentDisposition(), chk.Equals, "") 743} 744 745func validateBlobCommitted(c *chk.C, blobURL BlockBlobURL) { 746 resp, err := blobURL.GetBlockList(ctx, BlockListAll, LeaseAccessConditions{}) 747 c.Assert(err, chk.IsNil) 748 c.Assert(resp.CommittedBlocks, chk.HasLen, 1) 749} 750 751func (s *aztestsSuite) TestBlobPutBlockListIfModifiedSinceTrue(c *chk.C) { 752 containerURL, blobURL, id := setupPutBlockListTest(c) 753 defer deleteContainer(c, containerURL) 754 _, err := blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) // The blob must actually exist to have a modifed time 755 c.Assert(err, chk.IsNil) 756 757 currentTime := getRelativeTimeGMT(-10) 758 759 _, err = blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfModifiedSince: currentTime}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 760 c.Assert(err, chk.IsNil) 761 762 validateBlobCommitted(c, blobURL) 763} 764 765func (s *aztestsSuite) TestBlobPutBlockListIfModifiedSinceFalse(c *chk.C) { 766 containerURL, blobURL, id := setupPutBlockListTest(c) 767 defer deleteContainer(c, containerURL) 768 769 currentTime := getRelativeTimeGMT(10) 770 771 _, err := blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfModifiedSince: currentTime}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 772 validateStorageError(c, err, ServiceCodeConditionNotMet) 773} 774 775func (s *aztestsSuite) TestBlobPutBlockListIfUnmodifiedSinceTrue(c *chk.C) { 776 containerURL, blobURL, id := setupPutBlockListTest(c) 777 defer deleteContainer(c, containerURL) 778 _, err := blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) // The blob must actually exist to have a modifed time 779 c.Assert(err, chk.IsNil) 780 781 currentTime := getRelativeTimeGMT(10) 782 783 _, err = blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfUnmodifiedSince: currentTime}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 784 c.Assert(err, chk.IsNil) 785 786 validateBlobCommitted(c, blobURL) 787} 788 789func (s *aztestsSuite) TestBlobPutBlockListIfUnmodifiedSinceFalse(c *chk.C) { 790 containerURL, blobURL, id := setupPutBlockListTest(c) 791 blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) // The blob must actually exist to have a modifed time 792 defer deleteContainer(c, containerURL) 793 794 currentTime := getRelativeTimeGMT(-10) 795 796 _, err := blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfUnmodifiedSince: currentTime}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 797 798 validateStorageError(c, err, ServiceCodeConditionNotMet) 799} 800 801func (s *aztestsSuite) TestBlobPutBlockListIfMatchTrue(c *chk.C) { 802 containerURL, blobURL, id := setupPutBlockListTest(c) 803 defer deleteContainer(c, containerURL) 804 resp, err := blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) // The blob must actually exist to have a modifed time 805 c.Assert(err, chk.IsNil) 806 807 _, err = blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfMatch: resp.ETag()}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 808 c.Assert(err, chk.IsNil) 809 810 validateBlobCommitted(c, blobURL) 811} 812 813func (s *aztestsSuite) TestBlobPutBlockListIfMatchFalse(c *chk.C) { 814 containerURL, blobURL, id := setupPutBlockListTest(c) 815 defer deleteContainer(c, containerURL) 816 _, err := blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) // The blob must actually exist to have a modifed time 817 c.Assert(err, chk.IsNil) 818 819 _, err = blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfMatch: ETag("garbage")}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 820 821 validateStorageError(c, err, ServiceCodeConditionNotMet) 822} 823 824func (s *aztestsSuite) TestBlobPutBlockListIfNoneMatchTrue(c *chk.C) { 825 containerURL, blobURL, id := setupPutBlockListTest(c) 826 defer deleteContainer(c, containerURL) 827 _, err := blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) // The blob must actually exist to have a modifed time 828 c.Assert(err, chk.IsNil) 829 830 _, err = blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfNoneMatch: ETag("garbage")}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 831 c.Assert(err, chk.IsNil) 832 833 validateBlobCommitted(c, blobURL) 834} 835 836func (s *aztestsSuite) TestBlobPutBlockListIfNoneMatchFalse(c *chk.C) { 837 containerURL, blobURL, id := setupPutBlockListTest(c) 838 defer deleteContainer(c, containerURL) 839 resp, err := blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) // The blob must actually exist to have a modifed time 840 c.Assert(err, chk.IsNil) 841 842 _, err = blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{ModifiedAccessConditions: ModifiedAccessConditions{IfNoneMatch: resp.ETag()}}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 843 844 validateStorageError(c, err, ServiceCodeConditionNotMet) 845} 846 847func (s *aztestsSuite) TestBlobPutBlockListValidateData(c *chk.C) { 848 containerURL, blobURL, id := setupPutBlockListTest(c) 849 defer deleteContainer(c, containerURL) 850 851 _, err := blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 852 853 resp, err := blobURL.Download(ctx, 0, 0, BlobAccessConditions{}, false, ClientProvidedKeyOptions{}) 854 c.Assert(err, chk.IsNil) 855 data, _ := ioutil.ReadAll(resp.Response().Body) 856 c.Assert(string(data), chk.Equals, blockBlobDefaultData) 857} 858 859func (s *aztestsSuite) TestBlobPutBlockListModifyBlob(c *chk.C) { 860 containerURL, blobURL, id := setupPutBlockListTest(c) 861 defer deleteContainer(c, containerURL) 862 863 _, err := blobURL.CommitBlockList(ctx, []string{id}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 864 c.Assert(err, chk.IsNil) 865 866 _, err = blobURL.StageBlock(ctx, "0001", bytes.NewReader([]byte("new data")), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 867 c.Assert(err, chk.IsNil) 868 _, err = blobURL.StageBlock(ctx, "0010", bytes.NewReader([]byte("new data")), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 869 c.Assert(err, chk.IsNil) 870 _, err = blobURL.StageBlock(ctx, "0011", bytes.NewReader([]byte("new data")), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 871 c.Assert(err, chk.IsNil) 872 _, err = blobURL.StageBlock(ctx, "0100", bytes.NewReader([]byte("new data")), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 873 c.Assert(err, chk.IsNil) 874 875 _, err = blobURL.CommitBlockList(ctx, []string{"0001", "0011"}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, DefaultAccessTier, nil, ClientProvidedKeyOptions{}) 876 c.Assert(err, chk.IsNil) 877 878 resp, err := blobURL.GetBlockList(ctx, BlockListAll, LeaseAccessConditions{}) 879 c.Assert(err, chk.IsNil) 880 c.Assert(resp.CommittedBlocks, chk.HasLen, 2) 881 c.Assert(resp.CommittedBlocks[0].Name, chk.Equals, "0001") 882 c.Assert(resp.CommittedBlocks[1].Name, chk.Equals, "0011") 883 c.Assert(resp.UncommittedBlocks, chk.HasLen, 0) 884} 885 886func (s *aztestsSuite) TestSetTierOnBlobUpload(c *chk.C) { 887 bsu := getBSU() 888 containerURL, _ := createNewContainer(c, bsu) 889 defer deleteContainer(c, containerURL) 890 for _, tier := range []AccessTierType{AccessTierArchive, AccessTierCool, AccessTierHot} { 891 blobURL, _ := getBlockBlobURL(c, containerURL) 892 893 _, err := blobURL.Upload(ctx, strings.NewReader("Test Data"), basicHeaders, nil, BlobAccessConditions{}, tier, nil, ClientProvidedKeyOptions{}) 894 c.Assert(err, chk.IsNil) 895 896 resp, err := blobURL.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 897 c.Assert(err, chk.IsNil) 898 c.Assert(resp.AccessTier(), chk.Equals, string(tier)) 899 } 900} 901 902func (s *aztestsSuite) TestBlobSetTierOnCommit(c *chk.C) { 903 bsu := getBSU() 904 containerURL, _ := createNewContainer(c, bsu) 905 defer deleteContainer(c, containerURL) 906 907 for _, tier := range []AccessTierType{AccessTierCool, AccessTierHot} { 908 blobURL, _ := getBlockBlobURL(c, containerURL) 909 910 _, err := blobURL.StageBlock(ctx, blockID, strings.NewReader(blockBlobDefaultData), LeaseAccessConditions{}, nil, ClientProvidedKeyOptions{}) 911 c.Assert(err, chk.IsNil) 912 913 _, err = blobURL.CommitBlockList(ctx, []string{blockID}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, tier, nil, ClientProvidedKeyOptions{}) 914 915 resp, err := blobURL.GetBlockList(ctx, BlockListCommitted, LeaseAccessConditions{}) 916 c.Assert(err, chk.IsNil) 917 c.Assert(resp.CommittedBlocks, chk.HasLen, 1) 918 c.Assert(resp.UncommittedBlocks, chk.HasLen, 0) 919 } 920} 921 922func (s *aztestsSuite) TestSetTierOnCopyBlockBlobFromURL(c *chk.C) { 923 bsu := getBSU() 924 925 container, _ := createNewContainer(c, bsu) 926 defer delContainer(c, container) 927 928 testSize := 1 * 1024 * 1024 929 r, sourceData := getRandomDataAndReader(testSize) 930 sourceDataMD5Value := md5.Sum(sourceData) 931 ctx := context.Background() 932 srcBlob := container.NewBlockBlobURL(generateBlobName()) 933 934 // Setting blob tier as "cool" 935 uploadSrcResp, err := srcBlob.Upload(ctx, r, BlobHTTPHeaders{}, Metadata{}, BlobAccessConditions{}, AccessTierCool, nil, ClientProvidedKeyOptions{}) 936 c.Assert(err, chk.IsNil) 937 c.Assert(uploadSrcResp.Response().StatusCode, chk.Equals, 201) 938 939 // Get source blob URL with SAS for StageFromURL. 940 srcBlobParts := NewBlobURLParts(srcBlob.URL()) 941 942 credential, err := getGenericCredential("") 943 if err != nil { 944 c.Fatal("Invalid credential") 945 } 946 srcBlobParts.SAS, err = BlobSASSignatureValues{ 947 Protocol: SASProtocolHTTPS, 948 ExpiryTime: time.Now().UTC().Add(2 * time.Hour), 949 ContainerName: srcBlobParts.ContainerName, 950 BlobName: srcBlobParts.BlobName, 951 Permissions: BlobSASPermissions{Read: true}.String(), 952 }.NewSASQueryParameters(credential) 953 if err != nil { 954 c.Fatal(err) 955 } 956 957 srcBlobURLWithSAS := srcBlobParts.URL() 958 for _, tier := range []AccessTierType{AccessTierArchive, AccessTierCool, AccessTierHot} { 959 destBlob := container.NewBlockBlobURL(generateBlobName()) 960 resp, err := destBlob.CopyFromURL(ctx, srcBlobURLWithSAS, Metadata{"foo": "bar"}, ModifiedAccessConditions{}, BlobAccessConditions{}, sourceDataMD5Value[:], tier, nil) 961 c.Assert(err, chk.IsNil) 962 c.Assert(resp.Response().StatusCode, chk.Equals, 202) 963 c.Assert(string(resp.CopyStatus()), chk.DeepEquals, "success") 964 965 destBlobPropResp, err := destBlob.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 966 c.Assert(err, chk.IsNil) 967 c.Assert(destBlobPropResp.AccessTier(), chk.Equals, string(tier)) 968 969 } 970} 971 972func (s *aztestsSuite) TestSetTierOnStageBlockFromURL(c *chk.C) { 973 bsu := getBSU() 974 credential, err := getGenericCredential("") 975 if err != nil { 976 c.Fatal("Invalid credential") 977 } 978 container, _ := createNewContainer(c, bsu) 979 defer delContainer(c, container) 980 981 testSize := 8 * 1024 * 1024 // 8MB 982 r, sourceData := getRandomDataAndReader(testSize) 983 ctx := context.Background() // Use default Background context 984 srcBlob := container.NewBlockBlobURL("src" + generateBlobName()) 985 destBlob := container.NewBlockBlobURL("dst" + generateBlobName()) 986 tier := AccessTierCool 987 988 // Prepare source blob for copy. 989 uploadSrcResp, err := srcBlob.Upload(ctx, r, BlobHTTPHeaders{}, Metadata{}, BlobAccessConditions{}, tier, nil, ClientProvidedKeyOptions{}) 990 c.Assert(err, chk.IsNil) 991 c.Assert(uploadSrcResp.Response().StatusCode, chk.Equals, 201) 992 993 // Get source blob URL with SAS for StageFromURL. 994 srcBlobParts := NewBlobURLParts(srcBlob.URL()) 995 996 srcBlobParts.SAS, err = BlobSASSignatureValues{ 997 Protocol: SASProtocolHTTPS, // Users MUST use HTTPS (not HTTP) 998 ExpiryTime: time.Now().UTC().Add(48 * time.Hour), // 48-hours before expiration 999 ContainerName: srcBlobParts.ContainerName, 1000 BlobName: srcBlobParts.BlobName, 1001 Permissions: BlobSASPermissions{Read: true}.String(), 1002 }.NewSASQueryParameters(credential) 1003 if err != nil { 1004 c.Fatal(err) 1005 } 1006 1007 srcBlobURLWithSAS := srcBlobParts.URL() 1008 1009 // Stage blocks from URL. 1010 blockID1, blockID2 := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%6d", 0))), base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%6d", 1))) 1011 stageResp1, err := destBlob.StageBlockFromURL(ctx, blockID1, srcBlobURLWithSAS, 0, 4*1024*1024, LeaseAccessConditions{}, ModifiedAccessConditions{}, ClientProvidedKeyOptions{}) 1012 c.Assert(err, chk.IsNil) 1013 c.Assert(stageResp1.Response().StatusCode, chk.Equals, 201) 1014 c.Assert(stageResp1.ContentMD5(), chk.Not(chk.Equals), "") 1015 c.Assert(stageResp1.RequestID(), chk.Not(chk.Equals), "") 1016 c.Assert(stageResp1.Version(), chk.Not(chk.Equals), "") 1017 c.Assert(stageResp1.Date().IsZero(), chk.Equals, false) 1018 1019 stageResp2, err := destBlob.StageBlockFromURL(ctx, blockID2, srcBlobURLWithSAS, 4*1024*1024, CountToEnd, LeaseAccessConditions{}, ModifiedAccessConditions{}, ClientProvidedKeyOptions{}) 1020 c.Assert(err, chk.IsNil) 1021 c.Assert(stageResp2.Response().StatusCode, chk.Equals, 201) 1022 c.Assert(stageResp2.ContentMD5(), chk.Not(chk.Equals), "") 1023 c.Assert(stageResp2.RequestID(), chk.Not(chk.Equals), "") 1024 c.Assert(stageResp2.Version(), chk.Not(chk.Equals), "") 1025 c.Assert(stageResp2.Date().IsZero(), chk.Equals, false) 1026 1027 // Check block list. 1028 blockList, err := destBlob.GetBlockList(context.Background(), BlockListAll, LeaseAccessConditions{}) 1029 c.Assert(err, chk.IsNil) 1030 c.Assert(blockList.Response().StatusCode, chk.Equals, 200) 1031 c.Assert(blockList.CommittedBlocks, chk.HasLen, 0) 1032 c.Assert(blockList.UncommittedBlocks, chk.HasLen, 2) 1033 1034 // Commit block list. 1035 listResp, err := destBlob.CommitBlockList(context.Background(), []string{blockID1, blockID2}, BlobHTTPHeaders{}, nil, BlobAccessConditions{}, tier, nil, ClientProvidedKeyOptions{}) 1036 c.Assert(err, chk.IsNil) 1037 c.Assert(listResp.Response().StatusCode, chk.Equals, 201) 1038 1039 // Check data integrity through downloading. 1040 downloadResp, err := destBlob.BlobURL.Download(ctx, 0, CountToEnd, BlobAccessConditions{}, false, ClientProvidedKeyOptions{}) 1041 c.Assert(err, chk.IsNil) 1042 destData, err := ioutil.ReadAll(downloadResp.Body(RetryReaderOptions{})) 1043 c.Assert(err, chk.IsNil) 1044 c.Assert(destData, chk.DeepEquals, sourceData) 1045 1046 // Get properties to validate the tier 1047 destBlobPropResp, err := destBlob.GetProperties(ctx, BlobAccessConditions{}, ClientProvidedKeyOptions{}) 1048 c.Assert(err, chk.IsNil) 1049 c.Assert(destBlobPropResp.AccessTier(), chk.Equals, string(tier)) 1050} 1051