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