github.com/npaton/distribution@v2.3.1-rc.0+incompatible/registry/storage/driver/testsuites/testsuites.go (about) 1 package testsuites 2 3 import ( 4 "bytes" 5 "crypto/sha1" 6 "io" 7 "io/ioutil" 8 "math/rand" 9 "net/http" 10 "os" 11 "path" 12 "sort" 13 "strings" 14 "sync" 15 "testing" 16 "time" 17 18 "github.com/docker/distribution/context" 19 storagedriver "github.com/docker/distribution/registry/storage/driver" 20 "gopkg.in/check.v1" 21 ) 22 23 // Test hooks up gocheck into the "go test" runner. 24 func Test(t *testing.T) { check.TestingT(t) } 25 26 // RegisterSuite registers an in-process storage driver test suite with 27 // the go test runner. 28 func RegisterSuite(driverConstructor DriverConstructor, skipCheck SkipCheck) { 29 check.Suite(&DriverSuite{ 30 Constructor: driverConstructor, 31 SkipCheck: skipCheck, 32 ctx: context.Background(), 33 }) 34 } 35 36 // SkipCheck is a function used to determine if a test suite should be skipped. 37 // If a SkipCheck returns a non-empty skip reason, the suite is skipped with 38 // the given reason. 39 type SkipCheck func() (reason string) 40 41 // NeverSkip is a default SkipCheck which never skips the suite. 42 var NeverSkip SkipCheck = func() string { return "" } 43 44 // DriverConstructor is a function which returns a new 45 // storagedriver.StorageDriver. 46 type DriverConstructor func() (storagedriver.StorageDriver, error) 47 48 // DriverTeardown is a function which cleans up a suite's 49 // storagedriver.StorageDriver. 50 type DriverTeardown func() error 51 52 // DriverSuite is a gocheck test suite designed to test a 53 // storagedriver.StorageDriver. The intended way to create a DriverSuite is 54 // with RegisterSuite. 55 type DriverSuite struct { 56 Constructor DriverConstructor 57 Teardown DriverTeardown 58 SkipCheck 59 storagedriver.StorageDriver 60 ctx context.Context 61 } 62 63 // SetUpSuite sets up the gocheck test suite. 64 func (suite *DriverSuite) SetUpSuite(c *check.C) { 65 if reason := suite.SkipCheck(); reason != "" { 66 c.Skip(reason) 67 } 68 d, err := suite.Constructor() 69 c.Assert(err, check.IsNil) 70 suite.StorageDriver = d 71 } 72 73 // TearDownSuite tears down the gocheck test suite. 74 func (suite *DriverSuite) TearDownSuite(c *check.C) { 75 if suite.Teardown != nil { 76 err := suite.Teardown() 77 c.Assert(err, check.IsNil) 78 } 79 } 80 81 // TearDownTest tears down the gocheck test. 82 // This causes the suite to abort if any files are left around in the storage 83 // driver. 84 func (suite *DriverSuite) TearDownTest(c *check.C) { 85 files, _ := suite.StorageDriver.List(suite.ctx, "/") 86 if len(files) > 0 { 87 c.Fatalf("Storage driver did not clean up properly. Offending files: %#v", files) 88 } 89 } 90 91 // TestRootExists ensures that all storage drivers have a root path by default. 92 func (suite *DriverSuite) TestRootExists(c *check.C) { 93 _, err := suite.StorageDriver.List(suite.ctx, "/") 94 if err != nil { 95 c.Fatalf(`the root path "/" should always exist: %v`, err) 96 } 97 } 98 99 // TestValidPaths checks that various valid file paths are accepted by the 100 // storage driver. 101 func (suite *DriverSuite) TestValidPaths(c *check.C) { 102 contents := randomContents(64) 103 validFiles := []string{ 104 "/a", 105 "/2", 106 "/aa", 107 "/a.a", 108 "/0-9/abcdefg", 109 "/abcdefg/z.75", 110 "/abc/1.2.3.4.5-6_zyx/123.z/4", 111 "/docker/docker-registry", 112 "/123.abc", 113 "/abc./abc", 114 "/.abc", 115 "/a--b", 116 "/a-.b", 117 "/_.abc", 118 "/Docker/docker-registry", 119 "/Abc/Cba"} 120 121 for _, filename := range validFiles { 122 err := suite.StorageDriver.PutContent(suite.ctx, filename, contents) 123 defer suite.deletePath(c, firstPart(filename)) 124 c.Assert(err, check.IsNil) 125 126 received, err := suite.StorageDriver.GetContent(suite.ctx, filename) 127 c.Assert(err, check.IsNil) 128 c.Assert(received, check.DeepEquals, contents) 129 } 130 } 131 132 func (suite *DriverSuite) deletePath(c *check.C, path string) { 133 for tries := 2; tries > 0; tries-- { 134 err := suite.StorageDriver.Delete(suite.ctx, path) 135 if _, ok := err.(storagedriver.PathNotFoundError); ok { 136 err = nil 137 } 138 c.Assert(err, check.IsNil) 139 paths, err := suite.StorageDriver.List(suite.ctx, path) 140 if len(paths) == 0 { 141 break 142 } 143 time.Sleep(time.Second * 2) 144 } 145 } 146 147 // TestInvalidPaths checks that various invalid file paths are rejected by the 148 // storage driver. 149 func (suite *DriverSuite) TestInvalidPaths(c *check.C) { 150 contents := randomContents(64) 151 invalidFiles := []string{ 152 "", 153 "/", 154 "abc", 155 "123.abc", 156 "//bcd", 157 "/abc_123/"} 158 159 for _, filename := range invalidFiles { 160 err := suite.StorageDriver.PutContent(suite.ctx, filename, contents) 161 // only delete if file was succesfully written 162 if err == nil { 163 defer suite.deletePath(c, firstPart(filename)) 164 } 165 c.Assert(err, check.NotNil) 166 c.Assert(err, check.FitsTypeOf, storagedriver.InvalidPathError{}) 167 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 168 169 _, err = suite.StorageDriver.GetContent(suite.ctx, filename) 170 c.Assert(err, check.NotNil) 171 c.Assert(err, check.FitsTypeOf, storagedriver.InvalidPathError{}) 172 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 173 } 174 } 175 176 // TestWriteRead1 tests a simple write-read workflow. 177 func (suite *DriverSuite) TestWriteRead1(c *check.C) { 178 filename := randomPath(32) 179 contents := []byte("a") 180 suite.writeReadCompare(c, filename, contents) 181 } 182 183 // TestWriteRead2 tests a simple write-read workflow with unicode data. 184 func (suite *DriverSuite) TestWriteRead2(c *check.C) { 185 filename := randomPath(32) 186 contents := []byte("\xc3\x9f") 187 suite.writeReadCompare(c, filename, contents) 188 } 189 190 // TestWriteRead3 tests a simple write-read workflow with a small string. 191 func (suite *DriverSuite) TestWriteRead3(c *check.C) { 192 filename := randomPath(32) 193 contents := randomContents(32) 194 suite.writeReadCompare(c, filename, contents) 195 } 196 197 // TestWriteRead4 tests a simple write-read workflow with 1MB of data. 198 func (suite *DriverSuite) TestWriteRead4(c *check.C) { 199 filename := randomPath(32) 200 contents := randomContents(1024 * 1024) 201 suite.writeReadCompare(c, filename, contents) 202 } 203 204 // TestWriteReadNonUTF8 tests that non-utf8 data may be written to the storage 205 // driver safely. 206 func (suite *DriverSuite) TestWriteReadNonUTF8(c *check.C) { 207 filename := randomPath(32) 208 contents := []byte{0x80, 0x80, 0x80, 0x80} 209 suite.writeReadCompare(c, filename, contents) 210 } 211 212 // TestTruncate tests that putting smaller contents than an original file does 213 // remove the excess contents. 214 func (suite *DriverSuite) TestTruncate(c *check.C) { 215 filename := randomPath(32) 216 contents := randomContents(1024 * 1024) 217 suite.writeReadCompare(c, filename, contents) 218 219 contents = randomContents(1024) 220 suite.writeReadCompare(c, filename, contents) 221 } 222 223 // TestReadNonexistent tests reading content from an empty path. 224 func (suite *DriverSuite) TestReadNonexistent(c *check.C) { 225 filename := randomPath(32) 226 _, err := suite.StorageDriver.GetContent(suite.ctx, filename) 227 c.Assert(err, check.NotNil) 228 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 229 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 230 } 231 232 // TestWriteReadStreams1 tests a simple write-read streaming workflow. 233 func (suite *DriverSuite) TestWriteReadStreams1(c *check.C) { 234 filename := randomPath(32) 235 contents := []byte("a") 236 suite.writeReadCompareStreams(c, filename, contents) 237 } 238 239 // TestWriteReadStreams2 tests a simple write-read streaming workflow with 240 // unicode data. 241 func (suite *DriverSuite) TestWriteReadStreams2(c *check.C) { 242 filename := randomPath(32) 243 contents := []byte("\xc3\x9f") 244 suite.writeReadCompareStreams(c, filename, contents) 245 } 246 247 // TestWriteReadStreams3 tests a simple write-read streaming workflow with a 248 // small amount of data. 249 func (suite *DriverSuite) TestWriteReadStreams3(c *check.C) { 250 filename := randomPath(32) 251 contents := randomContents(32) 252 suite.writeReadCompareStreams(c, filename, contents) 253 } 254 255 // TestWriteReadStreams4 tests a simple write-read streaming workflow with 1MB 256 // of data. 257 func (suite *DriverSuite) TestWriteReadStreams4(c *check.C) { 258 filename := randomPath(32) 259 contents := randomContents(1024 * 1024) 260 suite.writeReadCompareStreams(c, filename, contents) 261 } 262 263 // TestWriteReadStreamsNonUTF8 tests that non-utf8 data may be written to the 264 // storage driver safely. 265 func (suite *DriverSuite) TestWriteReadStreamsNonUTF8(c *check.C) { 266 filename := randomPath(32) 267 contents := []byte{0x80, 0x80, 0x80, 0x80} 268 suite.writeReadCompareStreams(c, filename, contents) 269 } 270 271 // TestWriteReadLargeStreams tests that a 5GB file may be written to the storage 272 // driver safely. 273 func (suite *DriverSuite) TestWriteReadLargeStreams(c *check.C) { 274 if testing.Short() { 275 c.Skip("Skipping test in short mode") 276 } 277 278 filename := randomPath(32) 279 defer suite.deletePath(c, firstPart(filename)) 280 281 checksum := sha1.New() 282 var fileSize int64 = 5 * 1024 * 1024 * 1024 283 284 contents := newRandReader(fileSize) 285 written, err := suite.StorageDriver.WriteStream(suite.ctx, filename, 0, io.TeeReader(contents, checksum)) 286 c.Assert(err, check.IsNil) 287 c.Assert(written, check.Equals, fileSize) 288 289 reader, err := suite.StorageDriver.ReadStream(suite.ctx, filename, 0) 290 c.Assert(err, check.IsNil) 291 defer reader.Close() 292 293 writtenChecksum := sha1.New() 294 io.Copy(writtenChecksum, reader) 295 296 c.Assert(writtenChecksum.Sum(nil), check.DeepEquals, checksum.Sum(nil)) 297 } 298 299 // TestReadStreamWithOffset tests that the appropriate data is streamed when 300 // reading with a given offset. 301 func (suite *DriverSuite) TestReadStreamWithOffset(c *check.C) { 302 filename := randomPath(32) 303 defer suite.deletePath(c, firstPart(filename)) 304 305 chunkSize := int64(32) 306 307 contentsChunk1 := randomContents(chunkSize) 308 contentsChunk2 := randomContents(chunkSize) 309 contentsChunk3 := randomContents(chunkSize) 310 311 err := suite.StorageDriver.PutContent(suite.ctx, filename, append(append(contentsChunk1, contentsChunk2...), contentsChunk3...)) 312 c.Assert(err, check.IsNil) 313 314 reader, err := suite.StorageDriver.ReadStream(suite.ctx, filename, 0) 315 c.Assert(err, check.IsNil) 316 defer reader.Close() 317 318 readContents, err := ioutil.ReadAll(reader) 319 c.Assert(err, check.IsNil) 320 321 c.Assert(readContents, check.DeepEquals, append(append(contentsChunk1, contentsChunk2...), contentsChunk3...)) 322 323 reader, err = suite.StorageDriver.ReadStream(suite.ctx, filename, chunkSize) 324 c.Assert(err, check.IsNil) 325 defer reader.Close() 326 327 readContents, err = ioutil.ReadAll(reader) 328 c.Assert(err, check.IsNil) 329 330 c.Assert(readContents, check.DeepEquals, append(contentsChunk2, contentsChunk3...)) 331 332 reader, err = suite.StorageDriver.ReadStream(suite.ctx, filename, chunkSize*2) 333 c.Assert(err, check.IsNil) 334 defer reader.Close() 335 336 readContents, err = ioutil.ReadAll(reader) 337 c.Assert(err, check.IsNil) 338 c.Assert(readContents, check.DeepEquals, contentsChunk3) 339 340 // Ensure we get invalid offest for negative offsets. 341 reader, err = suite.StorageDriver.ReadStream(suite.ctx, filename, -1) 342 c.Assert(err, check.FitsTypeOf, storagedriver.InvalidOffsetError{}) 343 c.Assert(err.(storagedriver.InvalidOffsetError).Offset, check.Equals, int64(-1)) 344 c.Assert(err.(storagedriver.InvalidOffsetError).Path, check.Equals, filename) 345 c.Assert(reader, check.IsNil) 346 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 347 348 // Read past the end of the content and make sure we get a reader that 349 // returns 0 bytes and io.EOF 350 reader, err = suite.StorageDriver.ReadStream(suite.ctx, filename, chunkSize*3) 351 c.Assert(err, check.IsNil) 352 defer reader.Close() 353 354 buf := make([]byte, chunkSize) 355 n, err := reader.Read(buf) 356 c.Assert(err, check.Equals, io.EOF) 357 c.Assert(n, check.Equals, 0) 358 359 // Check the N-1 boundary condition, ensuring we get 1 byte then io.EOF. 360 reader, err = suite.StorageDriver.ReadStream(suite.ctx, filename, chunkSize*3-1) 361 c.Assert(err, check.IsNil) 362 defer reader.Close() 363 364 n, err = reader.Read(buf) 365 c.Assert(n, check.Equals, 1) 366 367 // We don't care whether the io.EOF comes on the this read or the first 368 // zero read, but the only error acceptable here is io.EOF. 369 if err != nil { 370 c.Assert(err, check.Equals, io.EOF) 371 } 372 373 // Any more reads should result in zero bytes and io.EOF 374 n, err = reader.Read(buf) 375 c.Assert(n, check.Equals, 0) 376 c.Assert(err, check.Equals, io.EOF) 377 } 378 379 // TestContinueStreamAppendLarge tests that a stream write can be appended to without 380 // corrupting the data with a large chunk size. 381 func (suite *DriverSuite) TestContinueStreamAppendLarge(c *check.C) { 382 suite.testContinueStreamAppend(c, int64(10*1024*1024)) 383 } 384 385 // TestContinueStreamAppendSmall is the same as TestContinueStreamAppendLarge, but only 386 // with a tiny chunk size in order to test corner cases for some cloud storage drivers. 387 func (suite *DriverSuite) TestContinueStreamAppendSmall(c *check.C) { 388 suite.testContinueStreamAppend(c, int64(32)) 389 } 390 391 func (suite *DriverSuite) testContinueStreamAppend(c *check.C, chunkSize int64) { 392 filename := randomPath(32) 393 defer suite.deletePath(c, firstPart(filename)) 394 395 contentsChunk1 := randomContents(chunkSize) 396 contentsChunk2 := randomContents(chunkSize) 397 contentsChunk3 := randomContents(chunkSize) 398 contentsChunk4 := randomContents(chunkSize) 399 zeroChunk := make([]byte, int64(chunkSize)) 400 401 fullContents := append(append(contentsChunk1, contentsChunk2...), contentsChunk3...) 402 403 nn, err := suite.StorageDriver.WriteStream(suite.ctx, filename, 0, bytes.NewReader(contentsChunk1)) 404 c.Assert(err, check.IsNil) 405 c.Assert(nn, check.Equals, int64(len(contentsChunk1))) 406 407 fi, err := suite.StorageDriver.Stat(suite.ctx, filename) 408 c.Assert(err, check.IsNil) 409 c.Assert(fi, check.NotNil) 410 c.Assert(fi.Size(), check.Equals, int64(len(contentsChunk1))) 411 412 nn, err = suite.StorageDriver.WriteStream(suite.ctx, filename, fi.Size(), bytes.NewReader(contentsChunk2)) 413 c.Assert(err, check.IsNil) 414 c.Assert(nn, check.Equals, int64(len(contentsChunk2))) 415 416 fi, err = suite.StorageDriver.Stat(suite.ctx, filename) 417 c.Assert(err, check.IsNil) 418 c.Assert(fi, check.NotNil) 419 c.Assert(fi.Size(), check.Equals, 2*chunkSize) 420 421 // Test re-writing the last chunk 422 nn, err = suite.StorageDriver.WriteStream(suite.ctx, filename, fi.Size()-chunkSize, bytes.NewReader(contentsChunk2)) 423 c.Assert(err, check.IsNil) 424 c.Assert(nn, check.Equals, int64(len(contentsChunk2))) 425 426 fi, err = suite.StorageDriver.Stat(suite.ctx, filename) 427 c.Assert(err, check.IsNil) 428 c.Assert(fi, check.NotNil) 429 c.Assert(fi.Size(), check.Equals, 2*chunkSize) 430 431 nn, err = suite.StorageDriver.WriteStream(suite.ctx, filename, fi.Size(), bytes.NewReader(fullContents[fi.Size():])) 432 c.Assert(err, check.IsNil) 433 c.Assert(nn, check.Equals, int64(len(fullContents[fi.Size():]))) 434 435 received, err := suite.StorageDriver.GetContent(suite.ctx, filename) 436 c.Assert(err, check.IsNil) 437 c.Assert(received, check.DeepEquals, fullContents) 438 439 // Writing past size of file extends file (no offset error). We would like 440 // to write chunk 4 one chunk length past chunk 3. It should be successful 441 // and the resulting file will be 5 chunks long, with a chunk of all 442 // zeros. 443 444 fullContents = append(fullContents, zeroChunk...) 445 fullContents = append(fullContents, contentsChunk4...) 446 447 nn, err = suite.StorageDriver.WriteStream(suite.ctx, filename, int64(len(fullContents))-chunkSize, bytes.NewReader(contentsChunk4)) 448 c.Assert(err, check.IsNil) 449 c.Assert(nn, check.Equals, chunkSize) 450 451 fi, err = suite.StorageDriver.Stat(suite.ctx, filename) 452 c.Assert(err, check.IsNil) 453 c.Assert(fi, check.NotNil) 454 c.Assert(fi.Size(), check.Equals, int64(len(fullContents))) 455 456 received, err = suite.StorageDriver.GetContent(suite.ctx, filename) 457 c.Assert(err, check.IsNil) 458 c.Assert(len(received), check.Equals, len(fullContents)) 459 c.Assert(received[chunkSize*3:chunkSize*4], check.DeepEquals, zeroChunk) 460 c.Assert(received[chunkSize*4:chunkSize*5], check.DeepEquals, contentsChunk4) 461 c.Assert(received, check.DeepEquals, fullContents) 462 463 // Ensure that negative offsets return correct error. 464 nn, err = suite.StorageDriver.WriteStream(suite.ctx, filename, -1, bytes.NewReader(zeroChunk)) 465 c.Assert(err, check.NotNil) 466 c.Assert(err, check.FitsTypeOf, storagedriver.InvalidOffsetError{}) 467 c.Assert(err.(storagedriver.InvalidOffsetError).Path, check.Equals, filename) 468 c.Assert(err.(storagedriver.InvalidOffsetError).Offset, check.Equals, int64(-1)) 469 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 470 } 471 472 // TestReadNonexistentStream tests that reading a stream for a nonexistent path 473 // fails. 474 func (suite *DriverSuite) TestReadNonexistentStream(c *check.C) { 475 filename := randomPath(32) 476 477 _, err := suite.StorageDriver.ReadStream(suite.ctx, filename, 0) 478 c.Assert(err, check.NotNil) 479 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 480 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 481 482 _, err = suite.StorageDriver.ReadStream(suite.ctx, filename, 64) 483 c.Assert(err, check.NotNil) 484 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 485 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 486 } 487 488 // TestList checks the returned list of keys after populating a directory tree. 489 func (suite *DriverSuite) TestList(c *check.C) { 490 rootDirectory := "/" + randomFilename(int64(8+rand.Intn(8))) 491 defer suite.deletePath(c, rootDirectory) 492 493 doesnotexist := path.Join(rootDirectory, "nonexistent") 494 _, err := suite.StorageDriver.List(suite.ctx, doesnotexist) 495 c.Assert(err, check.Equals, storagedriver.PathNotFoundError{ 496 Path: doesnotexist, 497 DriverName: suite.StorageDriver.Name(), 498 }) 499 500 parentDirectory := rootDirectory + "/" + randomFilename(int64(8+rand.Intn(8))) 501 childFiles := make([]string, 50) 502 for i := 0; i < len(childFiles); i++ { 503 childFile := parentDirectory + "/" + randomFilename(int64(8+rand.Intn(8))) 504 childFiles[i] = childFile 505 err := suite.StorageDriver.PutContent(suite.ctx, childFile, randomContents(32)) 506 c.Assert(err, check.IsNil) 507 } 508 sort.Strings(childFiles) 509 510 keys, err := suite.StorageDriver.List(suite.ctx, "/") 511 c.Assert(err, check.IsNil) 512 c.Assert(keys, check.DeepEquals, []string{rootDirectory}) 513 514 keys, err = suite.StorageDriver.List(suite.ctx, rootDirectory) 515 c.Assert(err, check.IsNil) 516 c.Assert(keys, check.DeepEquals, []string{parentDirectory}) 517 518 keys, err = suite.StorageDriver.List(suite.ctx, parentDirectory) 519 c.Assert(err, check.IsNil) 520 521 sort.Strings(keys) 522 c.Assert(keys, check.DeepEquals, childFiles) 523 524 // A few checks to add here (check out #819 for more discussion on this): 525 // 1. Ensure that all paths are absolute. 526 // 2. Ensure that listings only include direct children. 527 // 3. Ensure that we only respond to directory listings that end with a slash (maybe?). 528 } 529 530 // TestMove checks that a moved object no longer exists at the source path and 531 // does exist at the destination. 532 func (suite *DriverSuite) TestMove(c *check.C) { 533 contents := randomContents(32) 534 sourcePath := randomPath(32) 535 destPath := randomPath(32) 536 537 defer suite.deletePath(c, firstPart(sourcePath)) 538 defer suite.deletePath(c, firstPart(destPath)) 539 540 err := suite.StorageDriver.PutContent(suite.ctx, sourcePath, contents) 541 c.Assert(err, check.IsNil) 542 543 err = suite.StorageDriver.Move(suite.ctx, sourcePath, destPath) 544 c.Assert(err, check.IsNil) 545 546 received, err := suite.StorageDriver.GetContent(suite.ctx, destPath) 547 c.Assert(err, check.IsNil) 548 c.Assert(received, check.DeepEquals, contents) 549 550 _, err = suite.StorageDriver.GetContent(suite.ctx, sourcePath) 551 c.Assert(err, check.NotNil) 552 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 553 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 554 } 555 556 // TestMoveOverwrite checks that a moved object no longer exists at the source 557 // path and overwrites the contents at the destination. 558 func (suite *DriverSuite) TestMoveOverwrite(c *check.C) { 559 sourcePath := randomPath(32) 560 destPath := randomPath(32) 561 sourceContents := randomContents(32) 562 destContents := randomContents(64) 563 564 defer suite.deletePath(c, firstPart(sourcePath)) 565 defer suite.deletePath(c, firstPart(destPath)) 566 567 err := suite.StorageDriver.PutContent(suite.ctx, sourcePath, sourceContents) 568 c.Assert(err, check.IsNil) 569 570 err = suite.StorageDriver.PutContent(suite.ctx, destPath, destContents) 571 c.Assert(err, check.IsNil) 572 573 err = suite.StorageDriver.Move(suite.ctx, sourcePath, destPath) 574 c.Assert(err, check.IsNil) 575 576 received, err := suite.StorageDriver.GetContent(suite.ctx, destPath) 577 c.Assert(err, check.IsNil) 578 c.Assert(received, check.DeepEquals, sourceContents) 579 580 _, err = suite.StorageDriver.GetContent(suite.ctx, sourcePath) 581 c.Assert(err, check.NotNil) 582 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 583 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 584 } 585 586 // TestMoveNonexistent checks that moving a nonexistent key fails and does not 587 // delete the data at the destination path. 588 func (suite *DriverSuite) TestMoveNonexistent(c *check.C) { 589 contents := randomContents(32) 590 sourcePath := randomPath(32) 591 destPath := randomPath(32) 592 593 defer suite.deletePath(c, firstPart(destPath)) 594 595 err := suite.StorageDriver.PutContent(suite.ctx, destPath, contents) 596 c.Assert(err, check.IsNil) 597 598 err = suite.StorageDriver.Move(suite.ctx, sourcePath, destPath) 599 c.Assert(err, check.NotNil) 600 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 601 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 602 603 received, err := suite.StorageDriver.GetContent(suite.ctx, destPath) 604 c.Assert(err, check.IsNil) 605 c.Assert(received, check.DeepEquals, contents) 606 } 607 608 // TestMoveInvalid provides various checks for invalid moves. 609 func (suite *DriverSuite) TestMoveInvalid(c *check.C) { 610 contents := randomContents(32) 611 612 // Create a regular file. 613 err := suite.StorageDriver.PutContent(suite.ctx, "/notadir", contents) 614 c.Assert(err, check.IsNil) 615 defer suite.deletePath(c, "/notadir") 616 617 // Now try to move a non-existent file under it. 618 err = suite.StorageDriver.Move(suite.ctx, "/notadir/foo", "/notadir/bar") 619 c.Assert(err, check.NotNil) // non-nil error 620 } 621 622 // TestDelete checks that the delete operation removes data from the storage 623 // driver 624 func (suite *DriverSuite) TestDelete(c *check.C) { 625 filename := randomPath(32) 626 contents := randomContents(32) 627 628 defer suite.deletePath(c, firstPart(filename)) 629 630 err := suite.StorageDriver.PutContent(suite.ctx, filename, contents) 631 c.Assert(err, check.IsNil) 632 633 err = suite.StorageDriver.Delete(suite.ctx, filename) 634 c.Assert(err, check.IsNil) 635 636 _, err = suite.StorageDriver.GetContent(suite.ctx, filename) 637 c.Assert(err, check.NotNil) 638 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 639 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 640 } 641 642 // TestURLFor checks that the URLFor method functions properly, but only if it 643 // is implemented 644 func (suite *DriverSuite) TestURLFor(c *check.C) { 645 filename := randomPath(32) 646 contents := randomContents(32) 647 648 defer suite.deletePath(c, firstPart(filename)) 649 650 err := suite.StorageDriver.PutContent(suite.ctx, filename, contents) 651 c.Assert(err, check.IsNil) 652 653 url, err := suite.StorageDriver.URLFor(suite.ctx, filename, nil) 654 if _, ok := err.(storagedriver.ErrUnsupportedMethod); ok { 655 return 656 } 657 c.Assert(err, check.IsNil) 658 659 response, err := http.Get(url) 660 c.Assert(err, check.IsNil) 661 defer response.Body.Close() 662 663 read, err := ioutil.ReadAll(response.Body) 664 c.Assert(err, check.IsNil) 665 c.Assert(read, check.DeepEquals, contents) 666 667 url, err = suite.StorageDriver.URLFor(suite.ctx, filename, map[string]interface{}{"method": "HEAD"}) 668 if _, ok := err.(storagedriver.ErrUnsupportedMethod); ok { 669 return 670 } 671 c.Assert(err, check.IsNil) 672 673 response, err = http.Head(url) 674 c.Assert(response.StatusCode, check.Equals, 200) 675 c.Assert(response.ContentLength, check.Equals, int64(32)) 676 } 677 678 // TestDeleteNonexistent checks that removing a nonexistent key fails. 679 func (suite *DriverSuite) TestDeleteNonexistent(c *check.C) { 680 filename := randomPath(32) 681 err := suite.StorageDriver.Delete(suite.ctx, filename) 682 c.Assert(err, check.NotNil) 683 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 684 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 685 } 686 687 // TestDeleteFolder checks that deleting a folder removes all child elements. 688 func (suite *DriverSuite) TestDeleteFolder(c *check.C) { 689 dirname := randomPath(32) 690 filename1 := randomPath(32) 691 filename2 := randomPath(32) 692 filename3 := randomPath(32) 693 contents := randomContents(32) 694 695 defer suite.deletePath(c, firstPart(dirname)) 696 697 err := suite.StorageDriver.PutContent(suite.ctx, path.Join(dirname, filename1), contents) 698 c.Assert(err, check.IsNil) 699 700 err = suite.StorageDriver.PutContent(suite.ctx, path.Join(dirname, filename2), contents) 701 c.Assert(err, check.IsNil) 702 703 err = suite.StorageDriver.PutContent(suite.ctx, path.Join(dirname, filename3), contents) 704 c.Assert(err, check.IsNil) 705 706 err = suite.StorageDriver.Delete(suite.ctx, path.Join(dirname, filename1)) 707 c.Assert(err, check.IsNil) 708 709 _, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename1)) 710 c.Assert(err, check.NotNil) 711 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 712 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 713 714 _, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename2)) 715 c.Assert(err, check.IsNil) 716 717 _, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename3)) 718 c.Assert(err, check.IsNil) 719 720 err = suite.StorageDriver.Delete(suite.ctx, dirname) 721 c.Assert(err, check.IsNil) 722 723 _, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename1)) 724 c.Assert(err, check.NotNil) 725 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 726 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 727 728 _, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename2)) 729 c.Assert(err, check.NotNil) 730 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 731 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 732 733 _, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename3)) 734 c.Assert(err, check.NotNil) 735 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 736 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 737 } 738 739 // TestStatCall runs verifies the implementation of the storagedriver's Stat call. 740 func (suite *DriverSuite) TestStatCall(c *check.C) { 741 content := randomContents(4096) 742 dirPath := randomPath(32) 743 fileName := randomFilename(32) 744 filePath := path.Join(dirPath, fileName) 745 746 defer suite.deletePath(c, firstPart(dirPath)) 747 748 // Call on non-existent file/dir, check error. 749 fi, err := suite.StorageDriver.Stat(suite.ctx, dirPath) 750 c.Assert(err, check.NotNil) 751 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 752 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 753 c.Assert(fi, check.IsNil) 754 755 fi, err = suite.StorageDriver.Stat(suite.ctx, filePath) 756 c.Assert(err, check.NotNil) 757 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{}) 758 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true) 759 c.Assert(fi, check.IsNil) 760 761 err = suite.StorageDriver.PutContent(suite.ctx, filePath, content) 762 c.Assert(err, check.IsNil) 763 764 // Call on regular file, check results 765 fi, err = suite.StorageDriver.Stat(suite.ctx, filePath) 766 c.Assert(err, check.IsNil) 767 c.Assert(fi, check.NotNil) 768 c.Assert(fi.Path(), check.Equals, filePath) 769 c.Assert(fi.Size(), check.Equals, int64(len(content))) 770 c.Assert(fi.IsDir(), check.Equals, false) 771 createdTime := fi.ModTime() 772 773 // Sleep and modify the file 774 time.Sleep(time.Second * 10) 775 content = randomContents(4096) 776 err = suite.StorageDriver.PutContent(suite.ctx, filePath, content) 777 c.Assert(err, check.IsNil) 778 fi, err = suite.StorageDriver.Stat(suite.ctx, filePath) 779 c.Assert(err, check.IsNil) 780 c.Assert(fi, check.NotNil) 781 time.Sleep(time.Second * 5) // allow changes to propagate (eventual consistency) 782 783 // Check if the modification time is after the creation time. 784 // In case of cloud storage services, storage frontend nodes might have 785 // time drift between them, however that should be solved with sleeping 786 // before update. 787 modTime := fi.ModTime() 788 if !modTime.After(createdTime) { 789 c.Errorf("modtime (%s) is before the creation time (%s)", modTime, createdTime) 790 } 791 792 // Call on directory (do not check ModTime as dirs don't need to support it) 793 fi, err = suite.StorageDriver.Stat(suite.ctx, dirPath) 794 c.Assert(err, check.IsNil) 795 c.Assert(fi, check.NotNil) 796 c.Assert(fi.Path(), check.Equals, dirPath) 797 c.Assert(fi.Size(), check.Equals, int64(0)) 798 c.Assert(fi.IsDir(), check.Equals, true) 799 } 800 801 // TestPutContentMultipleTimes checks that if storage driver can overwrite the content 802 // in the subsequent puts. Validates that PutContent does not have to work 803 // with an offset like WriteStream does and overwrites the file entirely 804 // rather than writing the data to the [0,len(data)) of the file. 805 func (suite *DriverSuite) TestPutContentMultipleTimes(c *check.C) { 806 filename := randomPath(32) 807 contents := randomContents(4096) 808 809 defer suite.deletePath(c, firstPart(filename)) 810 err := suite.StorageDriver.PutContent(suite.ctx, filename, contents) 811 c.Assert(err, check.IsNil) 812 813 contents = randomContents(2048) // upload a different, smaller file 814 err = suite.StorageDriver.PutContent(suite.ctx, filename, contents) 815 c.Assert(err, check.IsNil) 816 817 readContents, err := suite.StorageDriver.GetContent(suite.ctx, filename) 818 c.Assert(err, check.IsNil) 819 c.Assert(readContents, check.DeepEquals, contents) 820 } 821 822 // TestConcurrentStreamReads checks that multiple clients can safely read from 823 // the same file simultaneously with various offsets. 824 func (suite *DriverSuite) TestConcurrentStreamReads(c *check.C) { 825 var filesize int64 = 128 * 1024 * 1024 826 827 if testing.Short() { 828 filesize = 10 * 1024 * 1024 829 c.Log("Reducing file size to 10MB for short mode") 830 } 831 832 filename := randomPath(32) 833 contents := randomContents(filesize) 834 835 defer suite.deletePath(c, firstPart(filename)) 836 837 err := suite.StorageDriver.PutContent(suite.ctx, filename, contents) 838 c.Assert(err, check.IsNil) 839 840 var wg sync.WaitGroup 841 842 readContents := func() { 843 defer wg.Done() 844 offset := rand.Int63n(int64(len(contents))) 845 reader, err := suite.StorageDriver.ReadStream(suite.ctx, filename, offset) 846 c.Assert(err, check.IsNil) 847 848 readContents, err := ioutil.ReadAll(reader) 849 c.Assert(err, check.IsNil) 850 c.Assert(readContents, check.DeepEquals, contents[offset:]) 851 } 852 853 wg.Add(10) 854 for i := 0; i < 10; i++ { 855 go readContents() 856 } 857 wg.Wait() 858 } 859 860 // TestConcurrentFileStreams checks that multiple *os.File objects can be passed 861 // in to WriteStream concurrently without hanging. 862 func (suite *DriverSuite) TestConcurrentFileStreams(c *check.C) { 863 numStreams := 32 864 865 if testing.Short() { 866 numStreams = 8 867 c.Log("Reducing number of streams to 8 for short mode") 868 } 869 870 var wg sync.WaitGroup 871 872 testStream := func(size int64) { 873 defer wg.Done() 874 suite.testFileStreams(c, size) 875 } 876 877 wg.Add(numStreams) 878 for i := numStreams; i > 0; i-- { 879 go testStream(int64(numStreams) * 1024 * 1024) 880 } 881 882 wg.Wait() 883 } 884 885 // TestEventualConsistency checks that if stat says that a file is a certain size, then 886 // you can freely read from the file (this is the only guarantee that the driver needs to provide) 887 func (suite *DriverSuite) TestEventualConsistency(c *check.C) { 888 if testing.Short() { 889 c.Skip("Skipping test in short mode") 890 } 891 892 filename := randomPath(32) 893 defer suite.deletePath(c, firstPart(filename)) 894 895 var offset int64 896 var misswrites int 897 var chunkSize int64 = 32 898 899 for i := 0; i < 1024; i++ { 900 contents := randomContents(chunkSize) 901 read, err := suite.StorageDriver.WriteStream(suite.ctx, filename, offset, bytes.NewReader(contents)) 902 c.Assert(err, check.IsNil) 903 904 fi, err := suite.StorageDriver.Stat(suite.ctx, filename) 905 c.Assert(err, check.IsNil) 906 907 // We are most concerned with being able to read data as soon as Stat declares 908 // it is uploaded. This is the strongest guarantee that some drivers (that guarantee 909 // at best eventual consistency) absolutely need to provide. 910 if fi.Size() == offset+chunkSize { 911 reader, err := suite.StorageDriver.ReadStream(suite.ctx, filename, offset) 912 c.Assert(err, check.IsNil) 913 914 readContents, err := ioutil.ReadAll(reader) 915 c.Assert(err, check.IsNil) 916 917 c.Assert(readContents, check.DeepEquals, contents) 918 919 reader.Close() 920 offset += read 921 } else { 922 misswrites++ 923 } 924 } 925 926 if misswrites > 0 { 927 c.Log("There were " + string(misswrites) + " occurences of a write not being instantly available.") 928 } 929 930 c.Assert(misswrites, check.Not(check.Equals), 1024) 931 } 932 933 // BenchmarkPutGetEmptyFiles benchmarks PutContent/GetContent for 0B files 934 func (suite *DriverSuite) BenchmarkPutGetEmptyFiles(c *check.C) { 935 suite.benchmarkPutGetFiles(c, 0) 936 } 937 938 // BenchmarkPutGet1KBFiles benchmarks PutContent/GetContent for 1KB files 939 func (suite *DriverSuite) BenchmarkPutGet1KBFiles(c *check.C) { 940 suite.benchmarkPutGetFiles(c, 1024) 941 } 942 943 // BenchmarkPutGet1MBFiles benchmarks PutContent/GetContent for 1MB files 944 func (suite *DriverSuite) BenchmarkPutGet1MBFiles(c *check.C) { 945 suite.benchmarkPutGetFiles(c, 1024*1024) 946 } 947 948 // BenchmarkPutGet1GBFiles benchmarks PutContent/GetContent for 1GB files 949 func (suite *DriverSuite) BenchmarkPutGet1GBFiles(c *check.C) { 950 suite.benchmarkPutGetFiles(c, 1024*1024*1024) 951 } 952 953 func (suite *DriverSuite) benchmarkPutGetFiles(c *check.C, size int64) { 954 c.SetBytes(size) 955 parentDir := randomPath(8) 956 defer func() { 957 c.StopTimer() 958 suite.StorageDriver.Delete(suite.ctx, firstPart(parentDir)) 959 }() 960 961 for i := 0; i < c.N; i++ { 962 filename := path.Join(parentDir, randomPath(32)) 963 err := suite.StorageDriver.PutContent(suite.ctx, filename, randomContents(size)) 964 c.Assert(err, check.IsNil) 965 966 _, err = suite.StorageDriver.GetContent(suite.ctx, filename) 967 c.Assert(err, check.IsNil) 968 } 969 } 970 971 // BenchmarkStreamEmptyFiles benchmarks WriteStream/ReadStream for 0B files 972 func (suite *DriverSuite) BenchmarkStreamEmptyFiles(c *check.C) { 973 suite.benchmarkStreamFiles(c, 0) 974 } 975 976 // BenchmarkStream1KBFiles benchmarks WriteStream/ReadStream for 1KB files 977 func (suite *DriverSuite) BenchmarkStream1KBFiles(c *check.C) { 978 suite.benchmarkStreamFiles(c, 1024) 979 } 980 981 // BenchmarkStream1MBFiles benchmarks WriteStream/ReadStream for 1MB files 982 func (suite *DriverSuite) BenchmarkStream1MBFiles(c *check.C) { 983 suite.benchmarkStreamFiles(c, 1024*1024) 984 } 985 986 // BenchmarkStream1GBFiles benchmarks WriteStream/ReadStream for 1GB files 987 func (suite *DriverSuite) BenchmarkStream1GBFiles(c *check.C) { 988 suite.benchmarkStreamFiles(c, 1024*1024*1024) 989 } 990 991 func (suite *DriverSuite) benchmarkStreamFiles(c *check.C, size int64) { 992 c.SetBytes(size) 993 parentDir := randomPath(8) 994 defer func() { 995 c.StopTimer() 996 suite.StorageDriver.Delete(suite.ctx, firstPart(parentDir)) 997 }() 998 999 for i := 0; i < c.N; i++ { 1000 filename := path.Join(parentDir, randomPath(32)) 1001 written, err := suite.StorageDriver.WriteStream(suite.ctx, filename, 0, bytes.NewReader(randomContents(size))) 1002 c.Assert(err, check.IsNil) 1003 c.Assert(written, check.Equals, size) 1004 1005 rc, err := suite.StorageDriver.ReadStream(suite.ctx, filename, 0) 1006 c.Assert(err, check.IsNil) 1007 rc.Close() 1008 } 1009 } 1010 1011 // BenchmarkList5Files benchmarks List for 5 small files 1012 func (suite *DriverSuite) BenchmarkList5Files(c *check.C) { 1013 suite.benchmarkListFiles(c, 5) 1014 } 1015 1016 // BenchmarkList50Files benchmarks List for 50 small files 1017 func (suite *DriverSuite) BenchmarkList50Files(c *check.C) { 1018 suite.benchmarkListFiles(c, 50) 1019 } 1020 1021 func (suite *DriverSuite) benchmarkListFiles(c *check.C, numFiles int64) { 1022 parentDir := randomPath(8) 1023 defer func() { 1024 c.StopTimer() 1025 suite.StorageDriver.Delete(suite.ctx, firstPart(parentDir)) 1026 }() 1027 1028 for i := int64(0); i < numFiles; i++ { 1029 err := suite.StorageDriver.PutContent(suite.ctx, path.Join(parentDir, randomPath(32)), nil) 1030 c.Assert(err, check.IsNil) 1031 } 1032 1033 c.ResetTimer() 1034 for i := 0; i < c.N; i++ { 1035 files, err := suite.StorageDriver.List(suite.ctx, parentDir) 1036 c.Assert(err, check.IsNil) 1037 c.Assert(int64(len(files)), check.Equals, numFiles) 1038 } 1039 } 1040 1041 // BenchmarkDelete5Files benchmarks Delete for 5 small files 1042 func (suite *DriverSuite) BenchmarkDelete5Files(c *check.C) { 1043 suite.benchmarkDeleteFiles(c, 5) 1044 } 1045 1046 // BenchmarkDelete50Files benchmarks Delete for 50 small files 1047 func (suite *DriverSuite) BenchmarkDelete50Files(c *check.C) { 1048 suite.benchmarkDeleteFiles(c, 50) 1049 } 1050 1051 func (suite *DriverSuite) benchmarkDeleteFiles(c *check.C, numFiles int64) { 1052 for i := 0; i < c.N; i++ { 1053 parentDir := randomPath(8) 1054 defer suite.deletePath(c, firstPart(parentDir)) 1055 1056 c.StopTimer() 1057 for j := int64(0); j < numFiles; j++ { 1058 err := suite.StorageDriver.PutContent(suite.ctx, path.Join(parentDir, randomPath(32)), nil) 1059 c.Assert(err, check.IsNil) 1060 } 1061 c.StartTimer() 1062 1063 // This is the operation we're benchmarking 1064 err := suite.StorageDriver.Delete(suite.ctx, firstPart(parentDir)) 1065 c.Assert(err, check.IsNil) 1066 } 1067 } 1068 1069 func (suite *DriverSuite) testFileStreams(c *check.C, size int64) { 1070 tf, err := ioutil.TempFile("", "tf") 1071 c.Assert(err, check.IsNil) 1072 defer os.Remove(tf.Name()) 1073 defer tf.Close() 1074 1075 filename := randomPath(32) 1076 defer suite.deletePath(c, firstPart(filename)) 1077 1078 contents := randomContents(size) 1079 1080 _, err = tf.Write(contents) 1081 c.Assert(err, check.IsNil) 1082 1083 tf.Sync() 1084 tf.Seek(0, os.SEEK_SET) 1085 1086 nn, err := suite.StorageDriver.WriteStream(suite.ctx, filename, 0, tf) 1087 c.Assert(err, check.IsNil) 1088 c.Assert(nn, check.Equals, size) 1089 1090 reader, err := suite.StorageDriver.ReadStream(suite.ctx, filename, 0) 1091 c.Assert(err, check.IsNil) 1092 defer reader.Close() 1093 1094 readContents, err := ioutil.ReadAll(reader) 1095 c.Assert(err, check.IsNil) 1096 1097 c.Assert(readContents, check.DeepEquals, contents) 1098 } 1099 1100 func (suite *DriverSuite) writeReadCompare(c *check.C, filename string, contents []byte) { 1101 defer suite.deletePath(c, firstPart(filename)) 1102 1103 err := suite.StorageDriver.PutContent(suite.ctx, filename, contents) 1104 c.Assert(err, check.IsNil) 1105 1106 readContents, err := suite.StorageDriver.GetContent(suite.ctx, filename) 1107 c.Assert(err, check.IsNil) 1108 1109 c.Assert(readContents, check.DeepEquals, contents) 1110 } 1111 1112 func (suite *DriverSuite) writeReadCompareStreams(c *check.C, filename string, contents []byte) { 1113 defer suite.deletePath(c, firstPart(filename)) 1114 1115 nn, err := suite.StorageDriver.WriteStream(suite.ctx, filename, 0, bytes.NewReader(contents)) 1116 c.Assert(err, check.IsNil) 1117 c.Assert(nn, check.Equals, int64(len(contents))) 1118 1119 reader, err := suite.StorageDriver.ReadStream(suite.ctx, filename, 0) 1120 c.Assert(err, check.IsNil) 1121 defer reader.Close() 1122 1123 readContents, err := ioutil.ReadAll(reader) 1124 c.Assert(err, check.IsNil) 1125 1126 c.Assert(readContents, check.DeepEquals, contents) 1127 } 1128 1129 var filenameChars = []byte("abcdefghijklmnopqrstuvwxyz0123456789") 1130 var separatorChars = []byte("._-") 1131 1132 func randomPath(length int64) string { 1133 path := "/" 1134 for int64(len(path)) < length { 1135 chunkLength := rand.Int63n(length-int64(len(path))) + 1 1136 chunk := randomFilename(chunkLength) 1137 path += chunk 1138 remaining := length - int64(len(path)) 1139 if remaining == 1 { 1140 path += randomFilename(1) 1141 } else if remaining > 1 { 1142 path += "/" 1143 } 1144 } 1145 return path 1146 } 1147 1148 func randomFilename(length int64) string { 1149 b := make([]byte, length) 1150 wasSeparator := true 1151 for i := range b { 1152 if !wasSeparator && i < len(b)-1 && rand.Intn(4) == 0 { 1153 b[i] = separatorChars[rand.Intn(len(separatorChars))] 1154 wasSeparator = true 1155 } else { 1156 b[i] = filenameChars[rand.Intn(len(filenameChars))] 1157 wasSeparator = false 1158 } 1159 } 1160 return string(b) 1161 } 1162 1163 // randomBytes pre-allocates all of the memory sizes needed for the test. If 1164 // anything panics while accessing randomBytes, just make this number bigger. 1165 var randomBytes = make([]byte, 128<<20) 1166 1167 func init() { 1168 // increase the random bytes to the required maximum 1169 for i := range randomBytes { 1170 randomBytes[i] = byte(rand.Intn(2 << 8)) 1171 } 1172 } 1173 1174 func randomContents(length int64) []byte { 1175 return randomBytes[:length] 1176 } 1177 1178 type randReader struct { 1179 r int64 1180 m sync.Mutex 1181 } 1182 1183 func (rr *randReader) Read(p []byte) (n int, err error) { 1184 rr.m.Lock() 1185 defer rr.m.Unlock() 1186 1187 n = copy(p, randomContents(int64(len(p)))) 1188 rr.r -= int64(n) 1189 1190 if rr.r <= 0 { 1191 err = io.EOF 1192 } 1193 1194 return 1195 } 1196 1197 func newRandReader(n int64) *randReader { 1198 return &randReader{r: n} 1199 } 1200 1201 func firstPart(filePath string) string { 1202 if filePath == "" { 1203 return "/" 1204 } 1205 for { 1206 if filePath[len(filePath)-1] == '/' { 1207 filePath = filePath[:len(filePath)-1] 1208 } 1209 1210 dir, file := path.Split(filePath) 1211 if dir == "" && file == "" { 1212 return "/" 1213 } 1214 if dir == "/" || dir == "" { 1215 return "/" + file 1216 } 1217 if file == "" { 1218 return dir 1219 } 1220 filePath = dir 1221 } 1222 }