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  }