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  }