func (suite *DriverSuite) BenchmarkPutGetEmptyFiles(c *check.C) {
	suite.benchmarkPutGetFiles(c, 0)
}
TODO (brianbland): evaluate the relevancy of this test
TestEventualConsistency checks that if stat says that a file is a certain size, then
you can freely read from the file (this is the only guarantee that the driver needs to provide)
func (suite *DriverSuite) TestEventualConsistency(c *check.C) {
if testing.Short() {
c.Skip("Skipping test in short mode")
}

filename := randomPath(32)
defer suite.deletePath(c, firstPart(filename))

var offset int64
var misswrites int
var chunkSize int64 = 32

for i := 0; i < 1024; i++ {
contents := randomContents(chunkSize)
read, err := suite.StorageDriver.Writer(suite.ctx, filename, offset, bytes.NewReader(contents))
c.Assert(err, check.IsNil)

fi, err := suite.StorageDriver.Stat(suite.ctx, filename)
c.Assert(err, check.IsNil)

// We are most concerned with being able to read data as soon as Stat declares
// it is uploaded. This is the strongest guarantee that some drivers (that guarantee
// at best eventual consistency) absolutely need to provide.
if fi.Size() == offset+chunkSize {
reader, err := suite.StorageDriver.Reader(suite.ctx, filename, offset)
c.Assert(err, check.IsNil)

readContents, err := ioutil.ReadAll(reader)
c.Assert(err, check.IsNil)

c.Assert(readContents, check.DeepEquals, contents)

reader.Close()
offset += read
} else {
misswrites++
}
}

if misswrites > 0 {
c.Log("There were " + string(misswrites) + " occurrences of a write not being instantly available.")
}

c.Assert(misswrites, check.Not(check.Equals), 1024)
}
BenchmarkPutGetEmptyFiles benchmarks PutContent/GetContent for 0B files
package testsuites
import (
	"bytes"
	"crypto/sha1"
	"io"
	"io/ioutil"
	"math/rand"
	"net/http"
	"os"
	"path"
	"sort"
	"strings"
	"sync"
	"testing"
	"time"
	"github.com/docker/distribution/context"
	storagedriver "github.com/docker/distribution/registry/storage/driver"
	"gopkg.in/check.v1"
)
func Test(t *testing.T) { check.TestingT(t) }
func RegisterSuite(driverConstructor DriverConstructor, skipCheck SkipCheck) {
	check.Suite(&DriverSuite{
		Constructor: driverConstructor,
		SkipCheck:   skipCheck,
		ctx:         context.Background(),
	})
}
type SkipCheck func() (reason string)
var NeverSkip SkipCheck = func() string { return "" }
type DriverConstructor func() (storagedriver.StorageDriver, error)
type DriverTeardown func() error
type DriverSuite struct {
	Constructor DriverConstructor
	Teardown    DriverTeardown
	SkipCheck
	storagedriver.StorageDriver
	ctx context.Context
}
func (suite *DriverSuite) SetUpSuite(c *check.C) {
	if reason := suite.SkipCheck(); reason != "" {
		c.Skip(reason)
	}
	d, err := suite.Constructor()
	c.Assert(err, check.IsNil)
	suite.StorageDriver = d
}
func (suite *DriverSuite) TearDownSuite(c *check.C) {
	if suite.Teardown != nil {
		err := suite.Teardown()
		c.Assert(err, check.IsNil)
	}
}
func (suite *DriverSuite) TearDownTest(c *check.C) {
	files, _ := suite.StorageDriver.List(suite.ctx, "/")
	if len(files) > 0 {
		c.Fatalf("Storage driver did not clean up properly. Offending files: %#v", files)
	}
}
func (suite *DriverSuite) TestRootExists(c *check.C) {
	_, err := suite.StorageDriver.List(suite.ctx, "/")
	if err != nil {
		c.Fatalf(`the root path "/" should always exist: %v`, err)
	}
}
func (suite *DriverSuite) TestValidPaths(c *check.C) {
	contents := randomContents(64)
	validFiles := []string{
		"/a",
		"/2",
		"/aa",
		"/a.a",
		"/0-9/abcdefg",
		"/abcdefg/z.75",
		"/abc/1.2.3.4.5-6_zyx/123.z/4",
		"/docker/docker-registry",
		"/123.abc",
		"/abc./abc",
		"/.abc",
		"/a--b",
		"/a-.b",
		"/_.abc",
		"/Docker/docker-registry",
		"/Abc/Cba"}
	for _, filename := range validFiles {
		err := suite.StorageDriver.PutContent(suite.ctx, filename, contents)
		defer suite.deletePath(c, firstPart(filename))
		c.Assert(err, check.IsNil)
		received, err := suite.StorageDriver.GetContent(suite.ctx, filename)
		c.Assert(err, check.IsNil)
		c.Assert(received, check.DeepEquals, contents)
	}
}
func (suite *DriverSuite) deletePath(c *check.C, path string) {
	for tries := 2; tries > 0; tries-- {
		err := suite.StorageDriver.Delete(suite.ctx, path)
		if _, ok := err.(storagedriver.PathNotFoundError); ok {
			err = nil
		}
		c.Assert(err, check.IsNil)
		paths, err := suite.StorageDriver.List(suite.ctx, path)
		if len(paths) == 0 {
			break
		}
		time.Sleep(time.Second * 2)
	}
}
func (suite *DriverSuite) TestInvalidPaths(c *check.C) {
	contents := randomContents(64)
	invalidFiles := []string{
		"",
		"/",
		"abc",
		"123.abc",
		"//bcd",
		"/abc_123/"}
	for _, filename := range invalidFiles {
		err := suite.StorageDriver.PutContent(suite.ctx, filename, contents)
		if err == nil {
			defer suite.deletePath(c, firstPart(filename))
		}
		c.Assert(err, check.NotNil)
		c.Assert(err, check.FitsTypeOf, storagedriver.InvalidPathError{})
		c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
		_, err = suite.StorageDriver.GetContent(suite.ctx, filename)
		c.Assert(err, check.NotNil)
		c.Assert(err, check.FitsTypeOf, storagedriver.InvalidPathError{})
		c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
	}
}
func (suite *DriverSuite) TestWriteRead1(c *check.C) {
	filename := randomPath(32)
	contents := []byte("a")
	suite.writeReadCompare(c, filename, contents)
}
func (suite *DriverSuite) TestWriteRead2(c *check.C) {
	filename := randomPath(32)
	contents := []byte("\xc3\x9f")
	suite.writeReadCompare(c, filename, contents)
}
func (suite *DriverSuite) TestWriteRead3(c *check.C) {
	filename := randomPath(32)
	contents := randomContents(32)
	suite.writeReadCompare(c, filename, contents)
}
func (suite *DriverSuite) TestWriteRead4(c *check.C) {
	filename := randomPath(32)
	contents := randomContents(1024 * 1024)
	suite.writeReadCompare(c, filename, contents)
}
func (suite *DriverSuite) TestWriteReadNonUTF8(c *check.C) {
	filename := randomPath(32)
	contents := []byte{0x80, 0x80, 0x80, 0x80}
	suite.writeReadCompare(c, filename, contents)
}
func (suite *DriverSuite) TestTruncate(c *check.C) {
	filename := randomPath(32)
	contents := randomContents(1024 * 1024)
	suite.writeReadCompare(c, filename, contents)
	contents = randomContents(1024)
	suite.writeReadCompare(c, filename, contents)
}
func (suite *DriverSuite) TestReadNonexistent(c *check.C) {
	filename := randomPath(32)
	_, err := suite.StorageDriver.GetContent(suite.ctx, filename)
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
}
func (suite *DriverSuite) TestWriteReadStreams1(c *check.C) {
	filename := randomPath(32)
	contents := []byte("a")
	suite.writeReadCompareStreams(c, filename, contents)
}
func (suite *DriverSuite) TestWriteReadStreams2(c *check.C) {
	filename := randomPath(32)
	contents := []byte("\xc3\x9f")
	suite.writeReadCompareStreams(c, filename, contents)
}
func (suite *DriverSuite) TestWriteReadStreams3(c *check.C) {
	filename := randomPath(32)
	contents := randomContents(32)
	suite.writeReadCompareStreams(c, filename, contents)
}
func (suite *DriverSuite) TestWriteReadStreams4(c *check.C) {
	filename := randomPath(32)
	contents := randomContents(1024 * 1024)
	suite.writeReadCompareStreams(c, filename, contents)
}
func (suite *DriverSuite) TestWriteReadStreamsNonUTF8(c *check.C) {
	filename := randomPath(32)
	contents := []byte{0x80, 0x80, 0x80, 0x80}
	suite.writeReadCompareStreams(c, filename, contents)
}
func (suite *DriverSuite) TestWriteReadLargeStreams(c *check.C) {
	if testing.Short() {
		c.Skip("Skipping test in short mode")
	}
	filename := randomPath(32)
	defer suite.deletePath(c, firstPart(filename))
	checksum := sha1.New()
	var fileSize int64 = 5 * 1024 * 1024 * 1024
	contents := newRandReader(fileSize)
	writer, err := suite.StorageDriver.Writer(suite.ctx, filename, false)
	c.Assert(err, check.IsNil)
	written, err := io.Copy(writer, io.TeeReader(contents, checksum))
	c.Assert(err, check.IsNil)
	c.Assert(written, check.Equals, fileSize)
	err = writer.Commit()
	c.Assert(err, check.IsNil)
	err = writer.Close()
	c.Assert(err, check.IsNil)
	reader, err := suite.StorageDriver.Reader(suite.ctx, filename, 0)
	c.Assert(err, check.IsNil)
	defer reader.Close()
	writtenChecksum := sha1.New()
	io.Copy(writtenChecksum, reader)
	c.Assert(writtenChecksum.Sum(nil), check.DeepEquals, checksum.Sum(nil))
}
func (suite *DriverSuite) TestReaderWithOffset(c *check.C) {
	filename := randomPath(32)
	defer suite.deletePath(c, firstPart(filename))
	chunkSize := int64(32)
	contentsChunk1 := randomContents(chunkSize)
	contentsChunk2 := randomContents(chunkSize)
	contentsChunk3 := randomContents(chunkSize)
	err := suite.StorageDriver.PutContent(suite.ctx, filename, append(append(contentsChunk1, contentsChunk2...), contentsChunk3...))
	c.Assert(err, check.IsNil)
	reader, err := suite.StorageDriver.Reader(suite.ctx, filename, 0)
	c.Assert(err, check.IsNil)
	defer reader.Close()
	readContents, err := ioutil.ReadAll(reader)
	c.Assert(err, check.IsNil)
	c.Assert(readContents, check.DeepEquals, append(append(contentsChunk1, contentsChunk2...), contentsChunk3...))
	reader, err = suite.StorageDriver.Reader(suite.ctx, filename, chunkSize)
	c.Assert(err, check.IsNil)
	defer reader.Close()
	readContents, err = ioutil.ReadAll(reader)
	c.Assert(err, check.IsNil)
	c.Assert(readContents, check.DeepEquals, append(contentsChunk2, contentsChunk3...))
	reader, err = suite.StorageDriver.Reader(suite.ctx, filename, chunkSize*2)
	c.Assert(err, check.IsNil)
	defer reader.Close()
	readContents, err = ioutil.ReadAll(reader)
	c.Assert(err, check.IsNil)
	c.Assert(readContents, check.DeepEquals, contentsChunk3)
	reader, err = suite.StorageDriver.Reader(suite.ctx, filename, -1)
	c.Assert(err, check.FitsTypeOf, storagedriver.InvalidOffsetError{})
	c.Assert(err.(storagedriver.InvalidOffsetError).Offset, check.Equals, int64(-1))
	c.Assert(err.(storagedriver.InvalidOffsetError).Path, check.Equals, filename)
	c.Assert(reader, check.IsNil)
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
	reader, err = suite.StorageDriver.Reader(suite.ctx, filename, chunkSize*3)
	c.Assert(err, check.IsNil)
	defer reader.Close()
	buf := make([]byte, chunkSize)
	n, err := reader.Read(buf)
	c.Assert(err, check.Equals, io.EOF)
	c.Assert(n, check.Equals, 0)
	reader, err = suite.StorageDriver.Reader(suite.ctx, filename, chunkSize*3-1)
	c.Assert(err, check.IsNil)
	defer reader.Close()
	n, err = reader.Read(buf)
	c.Assert(n, check.Equals, 1)
	if err != nil {
		c.Assert(err, check.Equals, io.EOF)
	}
	n, err = reader.Read(buf)
	c.Assert(n, check.Equals, 0)
	c.Assert(err, check.Equals, io.EOF)
}
func (suite *DriverSuite) TestContinueStreamAppendLarge(c *check.C) {
	suite.testContinueStreamAppend(c, int64(10*1024*1024))
}
func (suite *DriverSuite) TestContinueStreamAppendSmall(c *check.C) {
	suite.testContinueStreamAppend(c, int64(32))
}
func (suite *DriverSuite) testContinueStreamAppend(c *check.C, chunkSize int64) {
	filename := randomPath(32)
	defer suite.deletePath(c, firstPart(filename))
	contentsChunk1 := randomContents(chunkSize)
	contentsChunk2 := randomContents(chunkSize)
	contentsChunk3 := randomContents(chunkSize)
	fullContents := append(append(contentsChunk1, contentsChunk2...), contentsChunk3...)
	writer, err := suite.StorageDriver.Writer(suite.ctx, filename, false)
	c.Assert(err, check.IsNil)
	nn, err := io.Copy(writer, bytes.NewReader(contentsChunk1))
	c.Assert(err, check.IsNil)
	c.Assert(nn, check.Equals, int64(len(contentsChunk1)))
	err = writer.Close()
	c.Assert(err, check.IsNil)
	curSize := writer.Size()
	c.Assert(curSize, check.Equals, int64(len(contentsChunk1)))
	writer, err = suite.StorageDriver.Writer(suite.ctx, filename, true)
	c.Assert(err, check.IsNil)
	c.Assert(writer.Size(), check.Equals, curSize)
	nn, err = io.Copy(writer, bytes.NewReader(contentsChunk2))
	c.Assert(err, check.IsNil)
	c.Assert(nn, check.Equals, int64(len(contentsChunk2)))
	err = writer.Close()
	c.Assert(err, check.IsNil)
	curSize = writer.Size()
	c.Assert(curSize, check.Equals, 2*chunkSize)
	writer, err = suite.StorageDriver.Writer(suite.ctx, filename, true)
	c.Assert(err, check.IsNil)
	c.Assert(writer.Size(), check.Equals, curSize)
	nn, err = io.Copy(writer, bytes.NewReader(fullContents[curSize:]))
	c.Assert(err, check.IsNil)
	c.Assert(nn, check.Equals, int64(len(fullContents[curSize:])))
	err = writer.Commit()
	c.Assert(err, check.IsNil)
	err = writer.Close()
	c.Assert(err, check.IsNil)
	received, err := suite.StorageDriver.GetContent(suite.ctx, filename)
	c.Assert(err, check.IsNil)
	c.Assert(received, check.DeepEquals, fullContents)
}
func (suite *DriverSuite) TestReadNonexistentStream(c *check.C) {
	filename := randomPath(32)
	_, err := suite.StorageDriver.Reader(suite.ctx, filename, 0)
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
	_, err = suite.StorageDriver.Reader(suite.ctx, filename, 64)
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
}
func (suite *DriverSuite) TestList(c *check.C) {
	rootDirectory := "/" + randomFilename(int64(8+rand.Intn(8)))
	defer suite.deletePath(c, rootDirectory)
	doesnotexist := path.Join(rootDirectory, "nonexistent")
	_, err := suite.StorageDriver.List(suite.ctx, doesnotexist)
	c.Assert(err, check.Equals, storagedriver.PathNotFoundError{
		Path:       doesnotexist,
		DriverName: suite.StorageDriver.Name(),
	})
	parentDirectory := rootDirectory + "/" + randomFilename(int64(8+rand.Intn(8)))
	childFiles := make([]string, 50)
	for i := 0; i < len(childFiles); i++ {
		childFile := parentDirectory + "/" + randomFilename(int64(8+rand.Intn(8)))
		childFiles[i] = childFile
		err := suite.StorageDriver.PutContent(suite.ctx, childFile, randomContents(32))
		c.Assert(err, check.IsNil)
	}
	sort.Strings(childFiles)
	keys, err := suite.StorageDriver.List(suite.ctx, "/")
	c.Assert(err, check.IsNil)
	c.Assert(keys, check.DeepEquals, []string{rootDirectory})
	keys, err = suite.StorageDriver.List(suite.ctx, rootDirectory)
	c.Assert(err, check.IsNil)
	c.Assert(keys, check.DeepEquals, []string{parentDirectory})
	keys, err = suite.StorageDriver.List(suite.ctx, parentDirectory)
	c.Assert(err, check.IsNil)
	sort.Strings(keys)
	c.Assert(keys, check.DeepEquals, childFiles)
}
func (suite *DriverSuite) TestMove(c *check.C) {
	contents := randomContents(32)
	sourcePath := randomPath(32)
	destPath := randomPath(32)
	defer suite.deletePath(c, firstPart(sourcePath))
	defer suite.deletePath(c, firstPart(destPath))
	err := suite.StorageDriver.PutContent(suite.ctx, sourcePath, contents)
	c.Assert(err, check.IsNil)
	err = suite.StorageDriver.Move(suite.ctx, sourcePath, destPath)
	c.Assert(err, check.IsNil)
	received, err := suite.StorageDriver.GetContent(suite.ctx, destPath)
	c.Assert(err, check.IsNil)
	c.Assert(received, check.DeepEquals, contents)
	_, err = suite.StorageDriver.GetContent(suite.ctx, sourcePath)
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
}
func (suite *DriverSuite) TestMoveOverwrite(c *check.C) {
	sourcePath := randomPath(32)
	destPath := randomPath(32)
	sourceContents := randomContents(32)
	destContents := randomContents(64)
	defer suite.deletePath(c, firstPart(sourcePath))
	defer suite.deletePath(c, firstPart(destPath))
	err := suite.StorageDriver.PutContent(suite.ctx, sourcePath, sourceContents)
	c.Assert(err, check.IsNil)
	err = suite.StorageDriver.PutContent(suite.ctx, destPath, destContents)
	c.Assert(err, check.IsNil)
	err = suite.StorageDriver.Move(suite.ctx, sourcePath, destPath)
	c.Assert(err, check.IsNil)
	received, err := suite.StorageDriver.GetContent(suite.ctx, destPath)
	c.Assert(err, check.IsNil)
	c.Assert(received, check.DeepEquals, sourceContents)
	_, err = suite.StorageDriver.GetContent(suite.ctx, sourcePath)
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
}
func (suite *DriverSuite) TestMoveNonexistent(c *check.C) {
	contents := randomContents(32)
	sourcePath := randomPath(32)
	destPath := randomPath(32)
	defer suite.deletePath(c, firstPart(destPath))
	err := suite.StorageDriver.PutContent(suite.ctx, destPath, contents)
	c.Assert(err, check.IsNil)
	err = suite.StorageDriver.Move(suite.ctx, sourcePath, destPath)
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
	received, err := suite.StorageDriver.GetContent(suite.ctx, destPath)
	c.Assert(err, check.IsNil)
	c.Assert(received, check.DeepEquals, contents)
}
func (suite *DriverSuite) TestMoveInvalid(c *check.C) {
	contents := randomContents(32)
	err := suite.StorageDriver.PutContent(suite.ctx, "/notadir", contents)
	c.Assert(err, check.IsNil)
	defer suite.deletePath(c, "/notadir")
	err = suite.StorageDriver.Move(suite.ctx, "/notadir/foo", "/notadir/bar")
	c.Assert(err, check.NotNil)  
}
func (suite *DriverSuite) TestDelete(c *check.C) {
	filename := randomPath(32)
	contents := randomContents(32)
	defer suite.deletePath(c, firstPart(filename))
	err := suite.StorageDriver.PutContent(suite.ctx, filename, contents)
	c.Assert(err, check.IsNil)
	err = suite.StorageDriver.Delete(suite.ctx, filename)
	c.Assert(err, check.IsNil)
	_, err = suite.StorageDriver.GetContent(suite.ctx, filename)
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
}
func (suite *DriverSuite) TestURLFor(c *check.C) {
	filename := randomPath(32)
	contents := randomContents(32)
	defer suite.deletePath(c, firstPart(filename))
	err := suite.StorageDriver.PutContent(suite.ctx, filename, contents)
	c.Assert(err, check.IsNil)
	url, err := suite.StorageDriver.URLFor(suite.ctx, filename, nil)
	if _, ok := err.(storagedriver.ErrUnsupportedMethod); ok {
		return
	}
	c.Assert(err, check.IsNil)
	response, err := http.Get(url)
	c.Assert(err, check.IsNil)
	defer response.Body.Close()
	read, err := ioutil.ReadAll(response.Body)
	c.Assert(err, check.IsNil)
	c.Assert(read, check.DeepEquals, contents)
	url, err = suite.StorageDriver.URLFor(suite.ctx, filename, map[string]interface{}{"method": "HEAD"})
	if _, ok := err.(storagedriver.ErrUnsupportedMethod); ok {
		return
	}
	c.Assert(err, check.IsNil)
	response, err = http.Head(url)
	c.Assert(response.StatusCode, check.Equals, 200)
	c.Assert(response.ContentLength, check.Equals, int64(32))
}
func (suite *DriverSuite) TestDeleteNonexistent(c *check.C) {
	filename := randomPath(32)
	err := suite.StorageDriver.Delete(suite.ctx, filename)
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
}
func (suite *DriverSuite) TestDeleteFolder(c *check.C) {
	dirname := randomPath(32)
	filename1 := randomPath(32)
	filename2 := randomPath(32)
	filename3 := randomPath(32)
	contents := randomContents(32)
	defer suite.deletePath(c, firstPart(dirname))
	err := suite.StorageDriver.PutContent(suite.ctx, path.Join(dirname, filename1), contents)
	c.Assert(err, check.IsNil)
	err = suite.StorageDriver.PutContent(suite.ctx, path.Join(dirname, filename2), contents)
	c.Assert(err, check.IsNil)
	err = suite.StorageDriver.PutContent(suite.ctx, path.Join(dirname, filename3), contents)
	c.Assert(err, check.IsNil)
	err = suite.StorageDriver.Delete(suite.ctx, path.Join(dirname, filename1))
	c.Assert(err, check.IsNil)
	_, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename1))
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
	_, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename2))
	c.Assert(err, check.IsNil)
	_, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename3))
	c.Assert(err, check.IsNil)
	err = suite.StorageDriver.Delete(suite.ctx, dirname)
	c.Assert(err, check.IsNil)
	_, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename1))
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
	_, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename2))
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
	_, err = suite.StorageDriver.GetContent(suite.ctx, path.Join(dirname, filename3))
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
}
func (suite *DriverSuite) TestStatCall(c *check.C) {
	content := randomContents(4096)
	dirPath := randomPath(32)
	fileName := randomFilename(32)
	filePath := path.Join(dirPath, fileName)
	defer suite.deletePath(c, firstPart(dirPath))
	fi, err := suite.StorageDriver.Stat(suite.ctx, dirPath)
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
	c.Assert(fi, check.IsNil)
	fi, err = suite.StorageDriver.Stat(suite.ctx, filePath)
	c.Assert(err, check.NotNil)
	c.Assert(err, check.FitsTypeOf, storagedriver.PathNotFoundError{})
	c.Assert(strings.Contains(err.Error(), suite.Name()), check.Equals, true)
	c.Assert(fi, check.IsNil)
	err = suite.StorageDriver.PutContent(suite.ctx, filePath, content)
	c.Assert(err, check.IsNil)
	fi, err = suite.StorageDriver.Stat(suite.ctx, filePath)
	c.Assert(err, check.IsNil)
	c.Assert(fi, check.NotNil)
	c.Assert(fi.Path(), check.Equals, filePath)
	c.Assert(fi.Size(), check.Equals, int64(len(content)))
	c.Assert(fi.IsDir(), check.Equals, false)
	createdTime := fi.ModTime()
	time.Sleep(time.Second * 10)
	content = randomContents(4096)
	err = suite.StorageDriver.PutContent(suite.ctx, filePath, content)
	c.Assert(err, check.IsNil)
	fi, err = suite.StorageDriver.Stat(suite.ctx, filePath)
	c.Assert(err, check.IsNil)
	c.Assert(fi, check.NotNil)
	time.Sleep(time.Second * 5)  
	modTime := fi.ModTime()
	if !modTime.After(createdTime) {
		c.Errorf("modtime (%s) is before the creation time (%s)", modTime, createdTime)
	}
	fi, err = suite.StorageDriver.Stat(suite.ctx, dirPath)
	c.Assert(err, check.IsNil)
	c.Assert(fi, check.NotNil)
	c.Assert(fi.Path(), check.Equals, dirPath)
	c.Assert(fi.Size(), check.Equals, int64(0))
	c.Assert(fi.IsDir(), check.Equals, true)
}
func (suite *DriverSuite) TestPutContentMultipleTimes(c *check.C) {
	filename := randomPath(32)
	contents := randomContents(4096)
	defer suite.deletePath(c, firstPart(filename))
	err := suite.StorageDriver.PutContent(suite.ctx, filename, contents)
	c.Assert(err, check.IsNil)
	contents = randomContents(2048)  
	err = suite.StorageDriver.PutContent(suite.ctx, filename, contents)
	c.Assert(err, check.IsNil)
	readContents, err := suite.StorageDriver.GetContent(suite.ctx, filename)
	c.Assert(err, check.IsNil)
	c.Assert(readContents, check.DeepEquals, contents)
}
func (suite *DriverSuite) TestConcurrentStreamReads(c *check.C) {
	var filesize int64 = 128 * 1024 * 1024
	if testing.Short() {
		filesize = 10 * 1024 * 1024
		c.Log("Reducing file size to 10MB for short mode")
	}
	filename := randomPath(32)
	contents := randomContents(filesize)
	defer suite.deletePath(c, firstPart(filename))
	err := suite.StorageDriver.PutContent(suite.ctx, filename, contents)
	c.Assert(err, check.IsNil)
	var wg sync.WaitGroup
	readContents := func() {
		defer wg.Done()
		offset := rand.Int63n(int64(len(contents)))
		reader, err := suite.StorageDriver.Reader(suite.ctx, filename, offset)
		c.Assert(err, check.IsNil)
		readContents, err := ioutil.ReadAll(reader)
		c.Assert(err, check.IsNil)
		c.Assert(readContents, check.DeepEquals, contents[offset:])
	}
	wg.Add(10)
	for i := 0; i < 10; i++ {
		go readContents()
	}
	wg.Wait()
}
func (suite *DriverSuite) TestConcurrentFileStreams(c *check.C) {
	numStreams := 32
	if testing.Short() {
		numStreams = 8
		c.Log("Reducing number of streams to 8 for short mode")
	}
	var wg sync.WaitGroup
	testStream := func(size int64) {
		defer wg.Done()
		suite.testFileStreams(c, size)
	}
	wg.Add(numStreams)
	for i := numStreams; i > 0; i-- {
		go testStream(int64(numStreams) * 1024 * 1024)
	}
	wg.Wait()
}