1package storage 2 3// Copyright 2017 Microsoft Corporation 4// 5// Licensed under the Apache License, Version 2.0 (the "License"); 6// you may not use this file except in compliance with the License. 7// You may obtain a copy of the License at 8// 9// http://www.apache.org/licenses/LICENSE-2.0 10// 11// Unless required by applicable law or agreed to in writing, software 12// distributed under the License is distributed on an "AS IS" BASIS, 13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14// See the License for the specific language governing permissions and 15// limitations under the License. 16 17import ( 18 "bytes" 19 "crypto/md5" 20 "encoding/base64" 21 "io" 22 23 chk "gopkg.in/check.v1" 24) 25 26type StorageFileSuite struct{} 27 28var _ = chk.Suite(&StorageFileSuite{}) 29 30func (s *StorageFileSuite) TestCreateFile(c *chk.C) { 31 cli := getFileClient(c) 32 cli.deleteAllShares() 33 rec := cli.client.appendRecorder(c) 34 defer rec.Stop() 35 36 // create share 37 share := cli.GetShareReference(shareName(c)) 38 c.Assert(share.Create(nil), chk.IsNil) 39 defer share.Delete(nil) 40 root := share.GetRootDirectoryReference() 41 42 // create directory structure 43 dir1 := root.GetDirectoryReference("one") 44 c.Assert(dir1.Create(nil), chk.IsNil) 45 dir2 := dir1.GetDirectoryReference("two") 46 c.Assert(dir2.Create(nil), chk.IsNil) 47 48 // verify file doesn't exist 49 file := dir2.GetFileReference("some.file") 50 exists, err := file.Exists() 51 c.Assert(err, chk.IsNil) 52 c.Assert(exists, chk.Equals, false) 53 54 // create file 55 c.Assert(file.Create(1024, nil), chk.IsNil) 56 57 // delete file and verify 58 c.Assert(file.Delete(nil), chk.IsNil) 59 exists, err = file.Exists() 60 c.Assert(err, chk.IsNil) 61 c.Assert(exists, chk.Equals, false) 62} 63 64func (s *StorageFileSuite) TestGetFile(c *chk.C) { 65 cli := getFileClient(c) 66 rec := cli.client.appendRecorder(c) 67 defer rec.Stop() 68 69 // create share 70 share := cli.GetShareReference(shareName(c)) 71 c.Assert(share.Create(nil), chk.IsNil) 72 defer share.Delete(nil) 73 root := share.GetRootDirectoryReference() 74 75 // create file 76 const size = uint64(1024) 77 byteStream, _ := newByteStream(size) 78 file := root.GetFileReference("some.file") 79 c.Assert(file.Create(size, nil), chk.IsNil) 80 81 // fill file with some data 82 c.Assert(file.WriteRange(byteStream, FileRange{End: size - 1}, nil), chk.IsNil) 83 84 // set some metadata 85 md := map[string]string{ 86 "something": "somethingvalue", 87 "another": "anothervalue", 88 } 89 file.Metadata = md 90 c.Assert(file.SetMetadata(nil), chk.IsNil) 91 92 options := GetFileOptions{ 93 GetContentMD5: false, 94 } 95 // retrieve full file content and verify 96 stream, err := file.DownloadRangeToStream(FileRange{Start: 0, End: size - 1}, &options) 97 c.Assert(err, chk.IsNil) 98 defer stream.Body.Close() 99 var b1 [size]byte 100 count, _ := stream.Body.Read(b1[:]) 101 c.Assert(count, chk.Equals, int(size)) 102 var c1 [size]byte 103 bs, _ := newByteStream(size) 104 bs.Read(c1[:]) 105 c.Assert(b1, chk.DeepEquals, c1) 106 107 // retrieve partial file content and verify 108 stream, err = file.DownloadRangeToStream(FileRange{Start: size / 2, End: size - 1}, &options) 109 c.Assert(err, chk.IsNil) 110 defer stream.Body.Close() 111 var b2 [size / 2]byte 112 count, _ = stream.Body.Read(b2[:]) 113 c.Assert(count, chk.Equals, int(size)/2) 114 var c2 [size / 2]byte 115 bs, _ = newByteStream(size / 2) 116 bs.Read(c2[:]) 117 c.Assert(b2, chk.DeepEquals, c2) 118} 119 120func (s *StorageFileSuite) TestFileRanges(c *chk.C) { 121 cli := getFileClient(c) 122 rec := cli.client.appendRecorder(c) 123 defer rec.Stop() 124 125 share := cli.GetShareReference(shareName(c)) 126 c.Assert(share.Create(nil), chk.IsNil) 127 defer share.Delete(nil) 128 root := share.GetRootDirectoryReference() 129 130 fileSize := uint64(4096) 131 contentBytes := content(int(fileSize)) 132 133 // --- File with no valid ranges 134 file1 := root.GetFileReference("file1.txt") 135 c.Assert(file1.Create(fileSize, nil), chk.IsNil) 136 137 ranges, err := file1.ListRanges(nil) 138 c.Assert(err, chk.IsNil) 139 c.Assert(ranges.ContentLength, chk.Equals, fileSize) 140 c.Assert(ranges.FileRanges, chk.IsNil) 141 142 // --- File after writing a range 143 file2 := root.GetFileReference("file2.txt") 144 c.Assert(file2.Create(fileSize, nil), chk.IsNil) 145 c.Assert(file2.WriteRange(bytes.NewReader(contentBytes), FileRange{End: fileSize - 1}, nil), chk.IsNil) 146 147 ranges, err = file2.ListRanges(nil) 148 c.Assert(err, chk.IsNil) 149 c.Assert(len(ranges.FileRanges), chk.Equals, 1) 150 c.Assert((ranges.FileRanges[0].End-ranges.FileRanges[0].Start)+1, chk.Equals, fileSize) 151 152 // --- File after writing and clearing 153 file3 := root.GetFileReference("file3.txt") 154 c.Assert(file3.Create(fileSize, nil), chk.IsNil) 155 c.Assert(file3.WriteRange(bytes.NewReader(contentBytes), FileRange{End: fileSize - 1}, nil), chk.IsNil) 156 c.Assert(file3.ClearRange(FileRange{End: fileSize - 1}, nil), chk.IsNil) 157 158 ranges, err = file3.ListRanges(nil) 159 c.Assert(err, chk.IsNil) 160 c.Assert(ranges.FileRanges, chk.IsNil) 161 162 // --- File with ranges and subranges 163 file4 := root.GetFileReference("file4.txt") 164 c.Assert(file4.Create(fileSize, nil), chk.IsNil) 165 putRanges := []FileRange{ 166 {End: 511}, 167 {Start: 1024, End: 1535}, 168 {Start: 2048, End: 2559}, 169 {Start: 3072, End: 3583}, 170 } 171 172 for _, r := range putRanges { 173 err = file4.WriteRange(bytes.NewReader(contentBytes[:512]), r, nil) 174 c.Assert(err, chk.IsNil) 175 } 176 177 // validate all ranges 178 ranges, err = file4.ListRanges(nil) 179 c.Assert(err, chk.IsNil) 180 c.Assert(ranges.FileRanges, chk.DeepEquals, putRanges) 181 182 options := ListRangesOptions{ 183 ListRange: &FileRange{ 184 Start: 1000, 185 End: 3000, 186 }, 187 } 188 // validate sub-ranges 189 ranges, err = file4.ListRanges(&options) 190 c.Assert(err, chk.IsNil) 191 c.Assert(ranges.FileRanges, chk.DeepEquals, putRanges[1:3]) 192 193 // --- clear partial range and validate 194 file5 := root.GetFileReference("file5.txt") 195 c.Assert(file5.Create(fileSize, nil), chk.IsNil) 196 c.Assert(file5.WriteRange(bytes.NewReader(contentBytes), FileRange{End: fileSize - 1}, nil), chk.IsNil) 197 c.Assert(file5.ClearRange(putRanges[0], nil), chk.IsNil) 198 c.Assert(file5.ClearRange(putRanges[2], nil), chk.IsNil) 199 200 ranges, err = file5.ListRanges(nil) 201 c.Assert(err, chk.IsNil) 202 expectedtRanges := []FileRange{ 203 {Start: 512, End: 2047}, 204 {Start: 2560, End: 4095}, 205 } 206 c.Assert(ranges.FileRanges, chk.HasLen, 2) 207 c.Assert(ranges.FileRanges[0], chk.DeepEquals, expectedtRanges[0]) 208 c.Assert(ranges.FileRanges[1], chk.DeepEquals, expectedtRanges[1]) 209} 210 211func (s *StorageFileSuite) TestFileProperties(c *chk.C) { 212 cli := getFileClient(c) 213 rec := cli.client.appendRecorder(c) 214 defer rec.Stop() 215 216 // create share 217 share := cli.GetShareReference(shareName(c)) 218 c.Assert(share.Create(nil), chk.IsNil) 219 defer share.Delete(nil) 220 root := share.GetRootDirectoryReference() 221 222 fileSize := uint64(512) 223 file := root.GetFileReference("test.dat") 224 c.Assert(file.Create(fileSize, nil), chk.IsNil) 225 226 // get initial set of properties 227 c.Assert(file.Properties.Length, chk.Equals, fileSize) 228 c.Assert(file.Properties.Etag, chk.NotNil) 229 230 // set some file properties 231 cc := "cachecontrol" 232 ct := "mytype" 233 enc := "noencoding" 234 lang := "neutral" 235 disp := "friendly" 236 file.Properties.CacheControl = cc 237 file.Properties.Type = ct 238 file.Properties.Disposition = disp 239 file.Properties.Encoding = enc 240 file.Properties.Language = lang 241 c.Assert(file.SetProperties(nil), chk.IsNil) 242 243 // retrieve and verify 244 c.Assert(file.FetchAttributes(nil), chk.IsNil) 245 c.Assert(file.Properties.CacheControl, chk.Equals, cc) 246 c.Assert(file.Properties.Type, chk.Equals, ct) 247 c.Assert(file.Properties.Disposition, chk.Equals, disp) 248 c.Assert(file.Properties.Encoding, chk.Equals, enc) 249 c.Assert(file.Properties.Language, chk.Equals, lang) 250} 251 252func (s *StorageFileSuite) TestFileMetadata(c *chk.C) { 253 cli := getFileClient(c) 254 rec := cli.client.appendRecorder(c) 255 defer rec.Stop() 256 257 // create share 258 share := cli.GetShareReference(shareName(c)) 259 c.Assert(share.Create(nil), chk.IsNil) 260 defer share.Delete(nil) 261 root := share.GetRootDirectoryReference() 262 263 fileSize := uint64(512) 264 file := root.GetFileReference("test.dat") 265 c.Assert(file.Create(fileSize, nil), chk.IsNil) 266 267 // get metadata, shouldn't be any 268 c.Assert(file.Metadata, chk.HasLen, 0) 269 270 // set some custom metadata 271 md := map[string]string{ 272 "something": "somethingvalue", 273 "another": "anothervalue", 274 } 275 file.Metadata = md 276 c.Assert(file.SetMetadata(nil), chk.IsNil) 277 278 // retrieve and verify 279 c.Assert(file.FetchAttributes(nil), chk.IsNil) 280 c.Assert(file.Metadata, chk.DeepEquals, md) 281} 282 283func (s *StorageFileSuite) TestFileMD5(c *chk.C) { 284 cli := getFileClient(c) 285 rec := cli.client.appendRecorder(c) 286 defer rec.Stop() 287 288 // create share 289 share := cli.GetShareReference(shareName(c)) 290 c.Assert(share.Create(nil), chk.IsNil) 291 defer share.Delete(nil) 292 root := share.GetRootDirectoryReference() 293 294 // create file 295 const size = uint64(1024) 296 fileSize := uint64(size) 297 file := root.GetFileReference("test.dat") 298 c.Assert(file.Create(fileSize, nil), chk.IsNil) 299 300 // fill file with some data and MD5 hash 301 byteStream, contentMD5 := newByteStream(size) 302 options := WriteRangeOptions{ 303 ContentMD5: contentMD5, 304 } 305 c.Assert(file.WriteRange(byteStream, FileRange{End: size - 1}, &options), chk.IsNil) 306 307 // download file and verify 308 downloadOptions := GetFileOptions{ 309 GetContentMD5: true, 310 } 311 stream, err := file.DownloadRangeToStream(FileRange{Start: 0, End: size - 1}, &downloadOptions) 312 c.Assert(err, chk.IsNil) 313 defer stream.Body.Close() 314 c.Assert(stream.ContentMD5, chk.Equals, contentMD5) 315} 316 317// returns a byte stream along with a base-64 encoded MD5 hash of its contents 318func newByteStream(count uint64) (io.Reader, string) { 319 b := make([]uint8, count) 320 for i := uint64(0); i < count; i++ { 321 b[i] = 0xff 322 } 323 324 // create an MD5 hash of the array 325 hash := md5.Sum(b) 326 327 return bytes.NewReader(b), base64.StdEncoding.EncodeToString(hash[:]) 328} 329 330func (s *StorageFileSuite) TestCopyFileSameAccountNoMetaData(c *chk.C) { 331 cli := getFileClient(c) 332 rec := cli.client.appendRecorder(c) 333 defer rec.Stop() 334 335 // create share 336 share := cli.GetShareReference(shareName(c)) 337 c.Assert(share.Create(nil), chk.IsNil) 338 defer share.Delete(nil) 339 root := share.GetRootDirectoryReference() 340 341 // create directory structure 342 dir1 := root.GetDirectoryReference("one") 343 c.Assert(dir1.Create(nil), chk.IsNil) 344 dir2 := dir1.GetDirectoryReference("two") 345 c.Assert(dir2.Create(nil), chk.IsNil) 346 347 // create file 348 file := dir2.GetFileReference("some.file") 349 c.Assert(file.Create(1024, nil), chk.IsNil) 350 exists, err := file.Exists() 351 c.Assert(err, chk.IsNil) 352 c.Assert(exists, chk.Equals, true) 353 354 otherFile := dir2.GetFileReference("someother.file") 355 356 // copy the file, no timeout parameter 357 err = otherFile.CopyFile(file.URL(), nil) 358 c.Assert(err, chk.IsNil) 359 360 // delete files 361 c.Assert(file.Delete(nil), chk.IsNil) 362 c.Assert(otherFile.Delete(nil), chk.IsNil) 363} 364 365func (s *StorageFileSuite) TestCopyFileSameAccountTimeout(c *chk.C) { 366 cli := getFileClient(c) 367 rec := cli.client.appendRecorder(c) 368 defer rec.Stop() 369 370 // create share 371 share := cli.GetShareReference(shareName(c)) 372 c.Assert(share.Create(nil), chk.IsNil) 373 defer share.Delete(nil) 374 root := share.GetRootDirectoryReference() 375 376 // create directory structure 377 dir1 := root.GetDirectoryReference("one") 378 c.Assert(dir1.Create(nil), chk.IsNil) 379 dir2 := dir1.GetDirectoryReference("two") 380 c.Assert(dir2.Create(nil), chk.IsNil) 381 382 // create file 383 file := dir2.GetFileReference("some.file") 384 c.Assert(file.Create(1024, nil), chk.IsNil) 385 386 // copy the file, 60 second timeout. 387 otherFile := dir2.GetFileReference("someother.file") 388 options := FileRequestOptions{} 389 options.Timeout = 60 390 c.Assert(otherFile.CopyFile(file.URL(), &options), chk.IsNil) 391 392 // delete files 393 c.Assert(file.Delete(nil), chk.IsNil) 394 c.Assert(otherFile.Delete(nil), chk.IsNil) 395} 396 397func (s *StorageFileSuite) TestCopyFileMissingFile(c *chk.C) { 398 cli := getFileClient(c) 399 rec := cli.client.appendRecorder(c) 400 defer rec.Stop() 401 402 // create share 403 share := cli.GetShareReference(shareName(c)) 404 c.Assert(share.Create(nil), chk.IsNil) 405 defer share.Delete(nil) 406 root := share.GetRootDirectoryReference() 407 408 // create directory structure 409 dir1 := root.GetDirectoryReference("one") 410 c.Assert(dir1.Create(nil), chk.IsNil) 411 412 otherFile := dir1.GetFileReference("someother.file") 413 414 // copy the file, no timeout parameter 415 err := otherFile.CopyFile("", nil) 416 c.Assert(err, chk.NotNil) 417} 418