1 package testsuites
2
3 import (
4 "bytes"
5 "context"
6 crand "crypto/rand"
7 "crypto/sha1"
8 "io"
9 "io/ioutil"
10 "math/rand"
11 "net/http"
12 "os"
13 "path"
14 "sort"
15 "strings"
16 "sync"
17 "testing"
18 "time"
19
20 storagedriver "github.com/docker/distribution/registry/storage/driver"
21 "gopkg.in/check.v1"
22 )
23
24
25 func Test(t *testing.T) { check.TestingT(t) }
26
27
28
29 func RegisterSuite(driverConstructor DriverConstructor, skipCheck SkipCheck) {
30 check.Suite(&DriverSuite{
31 Constructor: driverConstructor,
32 SkipCheck: skipCheck,
33 ctx: context.Background(),
34 })
35 }
36
37
38
39
40 type SkipCheck func() (reason string)
41
42
43 var NeverSkip SkipCheck = func() string { return "" }
44
45
46
47 type DriverConstructor func() (storagedriver.StorageDriver, error)
48
49
50
51 type DriverTeardown func() error
52
53
54
55
56 type DriverSuite struct {
57 Constructor DriverConstructor
58 Teardown DriverTeardown
59 SkipCheck
60 storagedriver.StorageDriver
61 ctx context.Context
62 }
63
64
65 func (suite *DriverSuite) SetUpSuite(c *check.C) {
66 if reason := suite.SkipCheck(); reason != "" {
67 c.Skip(reason)
68 }
69 d, err := suite.Constructor()
70 c.Assert(err, check.IsNil)
71 suite.StorageDriver = d
72 }
73
74
75 func (suite *DriverSuite) TearDownSuite(c *check.C) {
76 if suite.Teardown != nil {
77 err := suite.Teardown()
78 c.Assert(err, check.IsNil)
79 }
80 }
81
82
83
84
85 func (suite *DriverSuite) TearDownTest(c *check.C) {
86 files, _ := suite.StorageDriver.List(suite.ctx, "/")
87 if len(files) > 0 {
88 c.Fatalf("Storage driver did not clean up properly. Offending files: %#v", files)
89 }
90 }
91
92
93 func (suite *DriverSuite) TestRootExists(c *check.C) {
94 _, err := suite.StorageDriver.List(suite.ctx, "/")
95 if err != nil {
96 c.Fatalf(`the root path "/" should always exist: %v`, err)
97 }
98 }
99
100
101
102 func (suite *DriverSuite) TestValidPaths(c *check.C) {
103 contents := randomContents(64)
104 validFiles := []string{
105 "/a",
106 "/2",
107 "/aa",
108 "/a.a",
109 "/0-9/abcdefg",
110 "/abcdefg/z.75",
111 "/abc/1.2.3.4.5-6_zyx/123.z/4",
112 "/docker/docker-registry",
113 "/123.abc",
114 "/abc./abc",
115 "/.abc",
116 "/a--b",
117 "/a-.b",
118 "/_.abc",
119 "/Docker/docker-registry",
120 "/Abc/Cba"}
121
122 for _, filename := range validFiles {
123 err := suite.StorageDriver.PutContent(suite.ctx, filename, contents)
124 defer suite.deletePath(c, firstPart(filename))
125 c.Assert(err, check.IsNil)
126
127 received, err := suite.StorageDriver.GetContent(suite.ctx, filename)
128 c.Assert(err, check.IsNil)
129 c.Assert(received, check.DeepEquals, contents)
130 }
131 }
132
133 func (suite *DriverSuite) deletePath(c *check.C, path string) {
134 for tries := 2; tries > 0; tries-- {
135 err := suite.StorageDriver.Delete(suite.ctx, path)
136 if _, ok := err.(storagedriver.PathNotFoundError); ok {
137 err = nil
138 }
139 c.Assert(err, check.IsNil)
140 paths, _ := suite.StorageDriver.List(suite.ctx, path)
141 if len(paths) == 0 {
142 break
143 }
144 time.Sleep(time.Second * 2)
145 }
146 }
147
148
149
150 func (suite *DriverSuite) TestInvalidPaths(c *check.C) {
151 contents := randomContents(64)
152 invalidFiles := []string{
153 "",
154 "/",
155 "abc",
156 "123.abc",
157 "//bcd",
158 "/abc_123/"}
159
160 for _, filename := range invalidFiles {
161 err := suite.StorageDriver.PutContent(suite.ctx, filename, contents)
162
163 if err == nil {
164 defer suite.deletePath(c, firstPart(filename))
165 }
166 c.Assert(err, check.NotNil)
167 c.Assert(err, check.FitsTypeOf, storagedriver.InvalidPathError{})
168 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
169
170 _, err = suite.StorageDriver.GetContent(suite.ctx, filename)
171 c.Assert(err, check.NotNil)
172 c.Assert(err, check.FitsTypeOf, storagedriver.InvalidPathError{})
173 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
174 }
175 }
176
177
178 func (suite *DriverSuite) TestWriteRead1(c *check.C) {
179 filename := randomPath(32)
180 contents := []byte("a")
181 suite.writeReadCompare(c, filename, contents)
182 }
183
184
185 func (suite *DriverSuite) TestWriteRead2(c *check.C) {
186 filename := randomPath(32)
187 contents := []byte("\xc3\x9f")
188 suite.writeReadCompare(c, filename, contents)
189 }
190
191
192 func (suite *DriverSuite) TestWriteRead3(c *check.C) {
193 filename := randomPath(32)
194 contents := randomContents(32)
195 suite.writeReadCompare(c, filename, contents)
196 }
197
198
199 func (suite *DriverSuite) TestWriteRead4(c *check.C) {
200 filename := randomPath(32)
201 contents := randomContents(1024 * 1024)
202 suite.writeReadCompare(c, filename, contents)
203 }
204
205
206
207 func (suite *DriverSuite) TestWriteReadNonUTF8(c *check.C) {
208 filename := randomPath(32)
209 contents := []byte{0x80, 0x80, 0x80, 0x80}
210 suite.writeReadCompare(c, filename, contents)
211 }
212
213
214
215 func (suite *DriverSuite) TestTruncate(c *check.C) {
216 filename := randomPath(32)
217 contents := randomContents(1024 * 1024)
218 suite.writeReadCompare(c, filename, contents)
219
220 contents = randomContents(1024)
221 suite.writeReadCompare(c, filename, contents)
222 }
223
224
225 func (suite *DriverSuite) TestReadNonexistent(c *check.C) {
226 filename := randomPath(32)
227 _, err := suite.StorageDriver.GetContent(suite.ctx, filename)
228 c.Assert(err, check.NotNil)
229 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
230 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
231 }
232
233
234 func (suite *DriverSuite) TestWriteReadStreams1(c *check.C) {
235 filename := randomPath(32)
236 contents := []byte("a")
237 suite.writeReadCompareStreams(c, filename, contents)
238 }
239
240
241
242 func (suite *DriverSuite) TestWriteReadStreams2(c *check.C) {
243 filename := randomPath(32)
244 contents := []byte("\xc3\x9f")
245 suite.writeReadCompareStreams(c, filename, contents)
246 }
247
248
249
250 func (suite *DriverSuite) TestWriteReadStreams3(c *check.C) {
251 filename := randomPath(32)
252 contents := randomContents(32)
253 suite.writeReadCompareStreams(c, filename, contents)
254 }
255
256
257
258 func (suite *DriverSuite) TestWriteReadStreams4(c *check.C) {
259 filename := randomPath(32)
260 contents := randomContents(1024 * 1024)
261 suite.writeReadCompareStreams(c, filename, contents)
262 }
263
264
265
266 func (suite *DriverSuite) TestWriteReadStreamsNonUTF8(c *check.C) {
267 filename := randomPath(32)
268 contents := []byte{0x80, 0x80, 0x80, 0x80}
269 suite.writeReadCompareStreams(c, filename, contents)
270 }
271
272
273
274 func (suite *DriverSuite) TestWriteReadLargeStreams(c *check.C) {
275 if testing.Short() {
276 c.Skip("Skipping test in short mode")
277 }
278
279 filename := randomPath(32)
280 defer suite.deletePath(c, firstPart(filename))
281
282 checksum := sha1.New()
283 var fileSize int64 = 5 * 1024 * 1024 * 1024
284
285 contents := newRandReader(fileSize)
286
287 writer, err := suite.StorageDriver.Writer(suite.ctx, filename, false)
288 c.Assert(err, check.IsNil)
289 written, err := io.Copy(writer, io.TeeReader(contents, checksum))
290 c.Assert(err, check.IsNil)
291 c.Assert(written, check.Equals, fileSize)
292
293 err = writer.Commit()
294 c.Assert(err, check.IsNil)
295 err = writer.Close()
296 c.Assert(err, check.IsNil)
297
298 reader, err := suite.StorageDriver.Reader(suite.ctx, filename, 0)
299 c.Assert(err, check.IsNil)
300 defer reader.Close()
301
302 writtenChecksum := sha1.New()
303 io.Copy(writtenChecksum, reader)
304
305 c.Assert(writtenChecksum.Sum(nil), check.DeepEquals, checksum.Sum(nil))
306 }
307
308
309
310 func (suite *DriverSuite) TestReaderWithOffset(c *check.C) {
311 filename := randomPath(32)
312 defer suite.deletePath(c, firstPart(filename))
313
314 chunkSize := int64(32)
315
316 contentsChunk1 := randomContents(chunkSize)
317 contentsChunk2 := randomContents(chunkSize)
318 contentsChunk3 := randomContents(chunkSize)
319
320 err := suite.StorageDriver.PutContent(suite.ctx, filename, append(append(contentsChunk1, contentsChunk2...), contentsChunk3...))
321 c.Assert(err, check.IsNil)
322
323 reader, err := suite.StorageDriver.Reader(suite.ctx, filename, 0)
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(append(contentsChunk1, contentsChunk2...), contentsChunk3...))
331
332 reader, err = suite.StorageDriver.Reader(suite.ctx, filename, chunkSize)
333 c.Assert(err, check.IsNil)
334 defer reader.Close()
335
336 readContents, err = ioutil.ReadAll(reader)
337 c.Assert(err, check.IsNil)
338
339 c.Assert(readContents, check.DeepEquals, append(contentsChunk2, contentsChunk3...))
340
341 reader, err = suite.StorageDriver.Reader(suite.ctx, filename, chunkSize*2)
342 c.Assert(err, check.IsNil)
343 defer reader.Close()
344
345 readContents, err = ioutil.ReadAll(reader)
346 c.Assert(err, check.IsNil)
347 c.Assert(readContents, check.DeepEquals, contentsChunk3)
348
349
350 reader, err = suite.StorageDriver.Reader(suite.ctx, filename, -1)
351 c.Assert(err, check.FitsTypeOf, storagedriver.InvalidOffsetError{})
352 c.Assert(err.(storagedriver.InvalidOffsetError).Offset, check.Equals, int64(-1))
353 c.Assert(err.(storagedriver.InvalidOffsetError).Path, check.Equals, filename)
354 c.Assert(reader, check.IsNil)
355 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
356
357
358
359 reader, err = suite.StorageDriver.Reader(suite.ctx, filename, chunkSize*3)
360 c.Assert(err, check.IsNil)
361 defer reader.Close()
362
363 buf := make([]byte, chunkSize)
364 n, err := reader.Read(buf)
365 c.Assert(err, check.Equals, io.EOF)
366 c.Assert(n, check.Equals, 0)
367
368
369 reader, err = suite.StorageDriver.Reader(suite.ctx, filename, chunkSize*3-1)
370 c.Assert(err, check.IsNil)
371 defer reader.Close()
372
373 n, err = reader.Read(buf)
374 c.Assert(n, check.Equals, 1)
375
376
377
378 if err != nil {
379 c.Assert(err, check.Equals, io.EOF)
380 }
381
382
383 n, err = reader.Read(buf)
384 c.Assert(n, check.Equals, 0)
385 c.Assert(err, check.Equals, io.EOF)
386 }
387
388
389
390 func (suite *DriverSuite) TestContinueStreamAppendLarge(c *check.C) {
391 suite.testContinueStreamAppend(c, int64(10*1024*1024))
392 }
393
394
395
396 func (suite *DriverSuite) TestContinueStreamAppendSmall(c *check.C) {
397 suite.testContinueStreamAppend(c, int64(32))
398 }
399
400 func (suite *DriverSuite) testContinueStreamAppend(c *check.C, chunkSize int64) {
401 filename := randomPath(32)
402 defer suite.deletePath(c, firstPart(filename))
403
404 contentsChunk1 := randomContents(chunkSize)
405 contentsChunk2 := randomContents(chunkSize)
406 contentsChunk3 := randomContents(chunkSize)
407
408 fullContents := append(append(contentsChunk1, contentsChunk2...), contentsChunk3...)
409
410 writer, err := suite.StorageDriver.Writer(suite.ctx, filename, false)
411 c.Assert(err, check.IsNil)
412 nn, err := io.Copy(writer, bytes.NewReader(contentsChunk1))
413 c.Assert(err, check.IsNil)
414 c.Assert(nn, check.Equals, int64(len(contentsChunk1)))
415
416 err = writer.Close()
417 c.Assert(err, check.IsNil)
418
419 curSize := writer.Size()
420 c.Assert(curSize, check.Equals, int64(len(contentsChunk1)))
421
422 writer, err = suite.StorageDriver.Writer(suite.ctx, filename, true)
423 c.Assert(err, check.IsNil)
424 c.Assert(writer.Size(), check.Equals, curSize)
425
426 nn, err = io.Copy(writer, bytes.NewReader(contentsChunk2))
427 c.Assert(err, check.IsNil)
428 c.Assert(nn, check.Equals, int64(len(contentsChunk2)))
429
430 err = writer.Close()
431 c.Assert(err, check.IsNil)
432
433 curSize = writer.Size()
434 c.Assert(curSize, check.Equals, 2*chunkSize)
435
436 writer, err = suite.StorageDriver.Writer(suite.ctx, filename, true)
437 c.Assert(err, check.IsNil)
438 c.Assert(writer.Size(), check.Equals, curSize)
439
440 nn, err = io.Copy(writer, bytes.NewReader(fullContents[curSize:]))
441 c.Assert(err, check.IsNil)
442 c.Assert(nn, check.Equals, int64(len(fullContents[curSize:])))
443
444 err = writer.Commit()
445 c.Assert(err, check.IsNil)
446 err = writer.Close()
447 c.Assert(err, check.IsNil)
448
449 received, err := suite.StorageDriver.GetContent(suite.ctx, filename)
450 c.Assert(err, check.IsNil)
451 c.Assert(received, check.DeepEquals, fullContents)
452 }
453
454
455
456 func (suite *DriverSuite) TestReadNonexistentStream(c *check.C) {
457 filename := randomPath(32)
458
459 _, err := suite.StorageDriver.Reader(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.Reader(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
471 func (suite *DriverSuite) TestList(c *check.C) {
472 rootDirectory := "/" + randomFilename(int64(8+rand.Intn(8)))
473 defer suite.deletePath(c, 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
507
508
509
510 }
511
512
513
514 func (suite *DriverSuite) TestMove(c *check.C) {
515 contents := randomContents(32)
516 sourcePath := randomPath(32)
517 destPath := randomPath(32)
518
519 defer suite.deletePath(c, firstPart(sourcePath))
520 defer suite.deletePath(c, 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
539
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.deletePath(c, firstPart(sourcePath))
547 defer suite.deletePath(c, 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
569
570 func (suite *DriverSuite) TestMoveNonexistent(c *check.C) {
571 contents := randomContents(32)
572 sourcePath := randomPath(32)
573 destPath := randomPath(32)
574
575 defer suite.deletePath(c, 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
591 func (suite *DriverSuite) TestMoveInvalid(c *check.C) {
592 contents := randomContents(32)
593
594
595 err := suite.StorageDriver.PutContent(suite.ctx, "/notadir", contents)
596 c.Assert(err, check.IsNil)
597 defer suite.deletePath(c, "/notadir")
598
599
600 err = suite.StorageDriver.Move(suite.ctx, "/notadir/foo", "/notadir/bar")
601 c.Assert(err, check.NotNil)
602 }
603
604
605
606 func (suite *DriverSuite) TestDelete(c *check.C) {
607 filename := randomPath(32)
608 contents := randomContents(32)
609
610 defer suite.deletePath(c, 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
625
626 func (suite *DriverSuite) TestURLFor(c *check.C) {
627 filename := randomPath(32)
628 contents := randomContents(32)
629
630 defer suite.deletePath(c, 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, _ = http.Head(url)
656 c.Assert(response.StatusCode, check.Equals, 200)
657 c.Assert(response.ContentLength, check.Equals, int64(32))
658 }
659
660
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
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.deletePath(c, 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
722
723
724
725 func (suite *DriverSuite) TestDeleteOnlyDeletesSubpaths(c *check.C) {
726 dirname := randomPath(32)
727 filename := randomPath(32)
728 contents := randomContents(32)
729
730 defer suite.deletePath(c, firstPart(dirname))
731
732 err := suite.StorageDriver.PutContent(suite.ctx, path.Join(dirname, filename), contents)
733 c.Assert(err, check.IsNil)
734
735 err = suite.StorageDriver.PutContent(suite.ctx, path.Join(dirname, filename+"suffix"), contents)
736 c.Assert(err, check.IsNil)
737
738 err = suite.StorageDriver.PutContent(suite.ctx, path.Join(dirname, dirname, filename), contents)
739 c.Assert(err, check.IsNil)
740
741 err = suite.StorageDriver.PutContent(suite.ctx, path.Join(dirname, dirname+"suffix", filename), contents)
742 c.Assert(err, check.IsNil)
743
744 err = suite.StorageDriver.Delete(suite.ctx, path.Join(dirname, filename))
745 c.Assert(err, check.IsNil)
746
747 _, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename))
748 c.Assert(err, check.NotNil)
749 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
750 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
751
752 _, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename+"suffix"))
753 c.Assert(err, check.IsNil)
754
755 err = suite.StorageDriver.Delete(suite.ctx, path.Join(dirname, dirname))
756 c.Assert(err, check.IsNil)
757
758 _, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, dirname, filename))
759 c.Assert(err, check.NotNil)
760 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
761 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
762
763 _, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, dirname+"suffix", filename))
764 c.Assert(err, check.IsNil)
765 }
766
767
768 func (suite *DriverSuite) TestStatCall(c *check.C) {
769 content := randomContents(4096)
770 dirPath := randomPath(32)
771 fileName := randomFilename(32)
772 filePath := path.Join(dirPath, fileName)
773
774 defer suite.deletePath(c, firstPart(dirPath))
775
776
777 fi, err := suite.StorageDriver.Stat(suite.ctx, dirPath)
778 c.Assert(err, check.NotNil)
779 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
780 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
781 c.Assert(fi, check.IsNil)
782
783 fi, err = suite.StorageDriver.Stat(suite.ctx, filePath)
784 c.Assert(err, check.NotNil)
785 c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
786 c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
787 c.Assert(fi, check.IsNil)
788
789 err = suite.StorageDriver.PutContent(suite.ctx, filePath, content)
790 c.Assert(err, check.IsNil)
791
792
793 fi, err = suite.StorageDriver.Stat(suite.ctx, filePath)
794 c.Assert(err, check.IsNil)
795 c.Assert(fi, check.NotNil)
796 c.Assert(fi.Path(), check.Equals, filePath)
797 c.Assert(fi.Size(), check.Equals, int64(len(content)))
798 c.Assert(fi.IsDir(), check.Equals, false)
799 createdTime := fi.ModTime()
800
801
802 time.Sleep(time.Second * 10)
803 content = randomContents(4096)
804 err = suite.StorageDriver.PutContent(suite.ctx, filePath, content)
805 c.Assert(err, check.IsNil)
806 fi, err = suite.StorageDriver.Stat(suite.ctx, filePath)
807 c.Assert(err, check.IsNil)
808 c.Assert(fi, check.NotNil)
809 time.Sleep(time.Second * 5)
810
811
812
813
814
815 modTime := fi.ModTime()
816 if !modTime.After(createdTime) {
817 c.Errorf("modtime (%s) is before the creation time (%s)", modTime, createdTime)
818 }
819
820
821 fi, err = suite.StorageDriver.Stat(suite.ctx, dirPath)
822 c.Assert(err, check.IsNil)
823 c.Assert(fi, check.NotNil)
824 c.Assert(fi.Path(), check.Equals, dirPath)
825 c.Assert(fi.Size(), check.Equals, int64(0))
826 c.Assert(fi.IsDir(), check.Equals, true)
827 }
828
829
830
831
832
833 func (suite *DriverSuite) TestPutContentMultipleTimes(c *check.C) {
834 filename := randomPath(32)
835 contents := randomContents(4096)
836
837 defer suite.deletePath(c, firstPart(filename))
838 err := suite.StorageDriver.PutContent(suite.ctx, filename, contents)
839 c.Assert(err, check.IsNil)
840
841 contents = randomContents(2048)
842 err = suite.StorageDriver.PutContent(suite.ctx, filename, contents)
843 c.Assert(err, check.IsNil)
844
845 readContents, err := suite.StorageDriver.GetContent(suite.ctx, filename)
846 c.Assert(err, check.IsNil)
847 c.Assert(readContents, check.DeepEquals, contents)
848 }
849
850
851
852 func (suite *DriverSuite) TestConcurrentStreamReads(c *check.C) {
853 var filesize int64 = 128 * 1024 * 1024
854
855 if testing.Short() {
856 filesize = 10 * 1024 * 1024
857 c.Log("Reducing file size to 10MB for short mode")
858 }
859
860 filename := randomPath(32)
861 contents := randomContents(filesize)
862
863 defer suite.deletePath(c, firstPart(filename))
864
865 err := suite.StorageDriver.PutContent(suite.ctx, filename, contents)
866 c.Assert(err, check.IsNil)
867
868 var wg sync.WaitGroup
869
870 readContents := func() {
871 defer wg.Done()
872 offset := rand.Int63n(int64(len(contents)))
873 reader, err := suite.StorageDriver.Reader(suite.ctx, filename, offset)
874 c.Assert(err, check.IsNil)
875
876 readContents, err := ioutil.ReadAll(reader)
877 c.Assert(err, check.IsNil)
878 c.Assert(readContents, check.DeepEquals, contents[offset:])
879 }
880
881 wg.Add(10)
882 for i := 0; i < 10; i++ {
883 go readContents()
884 }
885 wg.Wait()
886 }
887
888
889
890 func (suite *DriverSuite) TestConcurrentFileStreams(c *check.C) {
891 numStreams := 32
892
893 if testing.Short() {
894 numStreams = 8
895 c.Log("Reducing number of streams to 8 for short mode")
896 }
897
898 var wg sync.WaitGroup
899
900 testStream := func(size int64) {
901 defer wg.Done()
902 suite.testFileStreams(c, size)
903 }
904
905 wg.Add(numStreams)
906 for i := numStreams; i > 0; i-- {
907 go testStream(int64(numStreams) * 1024 * 1024)
908 }
909
910 wg.Wait()
911 }
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963 func (suite *DriverSuite) BenchmarkPutGetEmptyFiles(c *check.C) {
964 suite.benchmarkPutGetFiles(c, 0)
965 }
966
967
968 func (suite *DriverSuite) BenchmarkPutGet1KBFiles(c *check.C) {
969 suite.benchmarkPutGetFiles(c, 1024)
970 }
971
972
973 func (suite *DriverSuite) BenchmarkPutGet1MBFiles(c *check.C) {
974 suite.benchmarkPutGetFiles(c, 1024*1024)
975 }
976
977
978 func (suite *DriverSuite) BenchmarkPutGet1GBFiles(c *check.C) {
979 suite.benchmarkPutGetFiles(c, 1024*1024*1024)
980 }
981
982 func (suite *DriverSuite) benchmarkPutGetFiles(c *check.C, size int64) {
983 c.SetBytes(size)
984 parentDir := randomPath(8)
985 defer func() {
986 c.StopTimer()
987 suite.StorageDriver.Delete(suite.ctx, firstPart(parentDir))
988 }()
989
990 for i := 0; i < c.N; i++ {
991 filename := path.Join(parentDir, randomPath(32))
992 err := suite.StorageDriver.PutContent(suite.ctx, filename, randomContents(size))
993 c.Assert(err, check.IsNil)
994
995 _, err = suite.StorageDriver.GetContent(suite.ctx, filename)
996 c.Assert(err, check.IsNil)
997 }
998 }
999
1000
1001 func (suite *DriverSuite) BenchmarkStreamEmptyFiles(c *check.C) {
1002 suite.benchmarkStreamFiles(c, 0)
1003 }
1004
1005
1006 func (suite *DriverSuite) BenchmarkStream1KBFiles(c *check.C) {
1007 suite.benchmarkStreamFiles(c, 1024)
1008 }
1009
1010
1011 func (suite *DriverSuite) BenchmarkStream1MBFiles(c *check.C) {
1012 suite.benchmarkStreamFiles(c, 1024*1024)
1013 }
1014
1015
1016 func (suite *DriverSuite) BenchmarkStream1GBFiles(c *check.C) {
1017 suite.benchmarkStreamFiles(c, 1024*1024*1024)
1018 }
1019
1020 func (suite *DriverSuite) benchmarkStreamFiles(c *check.C, size int64) {
1021 c.SetBytes(size)
1022 parentDir := randomPath(8)
1023 defer func() {
1024 c.StopTimer()
1025 suite.StorageDriver.Delete(suite.ctx, firstPart(parentDir))
1026 }()
1027
1028 for i := 0; i < c.N; i++ {
1029 filename := path.Join(parentDir, randomPath(32))
1030 writer, err := suite.StorageDriver.Writer(suite.ctx, filename, false)
1031 c.Assert(err, check.IsNil)
1032 written, err := io.Copy(writer, bytes.NewReader(randomContents(size)))
1033 c.Assert(err, check.IsNil)
1034 c.Assert(written, check.Equals, size)
1035
1036 err = writer.Commit()
1037 c.Assert(err, check.IsNil)
1038 err = writer.Close()
1039 c.Assert(err, check.IsNil)
1040
1041 rc, err := suite.StorageDriver.Reader(suite.ctx, filename, 0)
1042 c.Assert(err, check.IsNil)
1043 rc.Close()
1044 }
1045 }
1046
1047
1048 func (suite *DriverSuite) BenchmarkList5Files(c *check.C) {
1049 suite.benchmarkListFiles(c, 5)
1050 }
1051
1052
1053 func (suite *DriverSuite) BenchmarkList50Files(c *check.C) {
1054 suite.benchmarkListFiles(c, 50)
1055 }
1056
1057 func (suite *DriverSuite) benchmarkListFiles(c *check.C, numFiles int64) {
1058 parentDir := randomPath(8)
1059 defer func() {
1060 c.StopTimer()
1061 suite.StorageDriver.Delete(suite.ctx, firstPart(parentDir))
1062 }()
1063
1064 for i := int64(0); i < numFiles; i++ {
1065 err := suite.StorageDriver.PutContent(suite.ctx, path.Join(parentDir, randomPath(32)), nil)
1066 c.Assert(err, check.IsNil)
1067 }
1068
1069 c.ResetTimer()
1070 for i := 0; i < c.N; i++ {
1071 files, err := suite.StorageDriver.List(suite.ctx, parentDir)
1072 c.Assert(err, check.IsNil)
1073 c.Assert(int64(len(files)), check.Equals, numFiles)
1074 }
1075 }
1076
1077
1078 func (suite *DriverSuite) BenchmarkDelete5Files(c *check.C) {
1079 suite.benchmarkDeleteFiles(c, 5)
1080 }
1081
1082
1083 func (suite *DriverSuite) BenchmarkDelete50Files(c *check.C) {
1084 suite.benchmarkDeleteFiles(c, 50)
1085 }
1086
1087 func (suite *DriverSuite) benchmarkDeleteFiles(c *check.C, numFiles int64) {
1088 for i := 0; i < c.N; i++ {
1089 parentDir := randomPath(8)
1090 defer suite.deletePath(c, firstPart(parentDir))
1091
1092 c.StopTimer()
1093 for j := int64(0); j < numFiles; j++ {
1094 err := suite.StorageDriver.PutContent(suite.ctx, path.Join(parentDir, randomPath(32)), nil)
1095 c.Assert(err, check.IsNil)
1096 }
1097 c.StartTimer()
1098
1099
1100 err := suite.StorageDriver.Delete(suite.ctx, firstPart(parentDir))
1101 c.Assert(err, check.IsNil)
1102 }
1103 }
1104
1105 func (suite *DriverSuite) testFileStreams(c *check.C, size int64) {
1106 tf, err := ioutil.TempFile("", "tf")
1107 c.Assert(err, check.IsNil)
1108 defer os.Remove(tf.Name())
1109 defer tf.Close()
1110
1111 filename := randomPath(32)
1112 defer suite.deletePath(c, firstPart(filename))
1113
1114 contents := randomContents(size)
1115
1116 _, err = tf.Write(contents)
1117 c.Assert(err, check.IsNil)
1118
1119 tf.Sync()
1120 tf.Seek(0, io.SeekStart)
1121
1122 writer, err := suite.StorageDriver.Writer(suite.ctx, filename, false)
1123 c.Assert(err, check.IsNil)
1124 nn, err := io.Copy(writer, tf)
1125 c.Assert(err, check.IsNil)
1126 c.Assert(nn, check.Equals, size)
1127
1128 err = writer.Commit()
1129 c.Assert(err, check.IsNil)
1130 err = writer.Close()
1131 c.Assert(err, check.IsNil)
1132
1133 reader, err := suite.StorageDriver.Reader(suite.ctx, filename, 0)
1134 c.Assert(err, check.IsNil)
1135 defer reader.Close()
1136
1137 readContents, err := ioutil.ReadAll(reader)
1138 c.Assert(err, check.IsNil)
1139
1140 c.Assert(readContents, check.DeepEquals, contents)
1141 }
1142
1143 func (suite *DriverSuite) writeReadCompare(c *check.C, filename string, contents []byte) {
1144 defer suite.deletePath(c, firstPart(filename))
1145
1146 err := suite.StorageDriver.PutContent(suite.ctx, filename, contents)
1147 c.Assert(err, check.IsNil)
1148
1149 readContents, err := suite.StorageDriver.GetContent(suite.ctx, filename)
1150 c.Assert(err, check.IsNil)
1151
1152 c.Assert(readContents, check.DeepEquals, contents)
1153 }
1154
1155 func (suite *DriverSuite) writeReadCompareStreams(c *check.C, filename string, contents []byte) {
1156 defer suite.deletePath(c, firstPart(filename))
1157
1158 writer, err := suite.StorageDriver.Writer(suite.ctx, filename, false)
1159 c.Assert(err, check.IsNil)
1160 nn, err := io.Copy(writer, bytes.NewReader(contents))
1161 c.Assert(err, check.IsNil)
1162 c.Assert(nn, check.Equals, int64(len(contents)))
1163
1164 err = writer.Commit()
1165 c.Assert(err, check.IsNil)
1166 err = writer.Close()
1167 c.Assert(err, check.IsNil)
1168
1169 reader, err := suite.StorageDriver.Reader(suite.ctx, filename, 0)
1170 c.Assert(err, check.IsNil)
1171 defer reader.Close()
1172
1173 readContents, err := ioutil.ReadAll(reader)
1174 c.Assert(err, check.IsNil)
1175
1176 c.Assert(readContents, check.DeepEquals, contents)
1177 }
1178
1179 var filenameChars = []byte("abcdefghijklmnopqrstuvwxyz0123456789")
1180 var separatorChars = []byte("._-")
1181
1182 func randomPath(length int64) string {
1183 path := "/"
1184 for int64(len(path)) < length {
1185 chunkLength := rand.Int63n(length-int64(len(path))) + 1
1186 chunk := randomFilename(chunkLength)
1187 path += chunk
1188 remaining := length - int64(len(path))
1189 if remaining == 1 {
1190 path += randomFilename(1)
1191 } else if remaining > 1 {
1192 path += "/"
1193 }
1194 }
1195 return path
1196 }
1197
1198 func randomFilename(length int64) string {
1199 b := make([]byte, length)
1200 wasSeparator := true
1201 for i := range b {
1202 if !wasSeparator && i < len(b)-1 && rand.Intn(4) == 0 {
1203 b[i] = separatorChars[rand.Intn(len(separatorChars))]
1204 wasSeparator = true
1205 } else {
1206 b[i] = filenameChars[rand.Intn(len(filenameChars))]
1207 wasSeparator = false
1208 }
1209 }
1210 return string(b)
1211 }
1212
1213
1214
1215 var randomBytes = make([]byte, 128<<20)
1216
1217 func init() {
1218 _, _ = crand.Read(randomBytes)
1219 }
1220
1221 func randomContents(length int64) []byte {
1222 return randomBytes[:length]
1223 }
1224
1225 type randReader struct {
1226 r int64
1227 m sync.Mutex
1228 }
1229
1230 func (rr *randReader) Read(p []byte) (n int, err error) {
1231 rr.m.Lock()
1232 defer rr.m.Unlock()
1233
1234 toread := int64(len(p))
1235 if toread > rr.r {
1236 toread = rr.r
1237 }
1238 n = copy(p, randomContents(toread))
1239 rr.r -= int64(n)
1240
1241 if rr.r <= 0 {
1242 err = io.EOF
1243 }
1244
1245 return
1246 }
1247
1248 func newRandReader(n int64) *randReader {
1249 return &randReader{r: n}
1250 }
1251
1252 func firstPart(filePath string) string {
1253 if filePath == "" {
1254 return "/"
1255 }
1256 for {
1257 if filePath[len(filePath)-1] == '/' {
1258 filePath = filePath[:len(filePath)-1]
1259 }
1260
1261 dir, file := path.Split(filePath)
1262 if dir == "" && file == "" {
1263 return "/"
1264 }
1265 if dir == "/" || dir == "" {
1266 return "/" + file
1267 }
1268 if file == "" {
1269 return dir
1270 }
1271 filePath = dir
1272 }
1273 }
1274
View as plain text