diff --git a/samples/cachingfs/caching_fs_test.go b/samples/cachingfs/caching_fs_test.go index 8da681e..2daf46c 100644 --- a/samples/cachingfs/caching_fs_test.go +++ b/samples/cachingfs/caching_fs_test.go @@ -15,104 +15,65 @@ package cachingfs_test import ( - "io/ioutil" - "log" "os" "path" "runtime" - "strings" "syscall" "testing" "time" - "github.com/jacobsa/fuse" - "github.com/jacobsa/fuse/samples/cachingfs" "github.com/googlecloudplatform/gcsfuse/timeutil" + "github.com/jacobsa/fuse/samples" + "github.com/jacobsa/fuse/samples/cachingfs" . "github.com/jacobsa/oglematchers" . "github.com/jacobsa/ogletest" - "golang.org/x/net/context" ) -func TestHelloFS(t *testing.T) { RunTests(t) } +func TestCachingFS(t *testing.T) { RunTests(t) } //////////////////////////////////////////////////////////////////////// // Boilerplate //////////////////////////////////////////////////////////////////////// type cachingFSTest struct { - dir string + samples.SampleTest + fs cachingfs.CachingFS - mfs *fuse.MountedFileSystem initialMtime time.Time } var _ TearDownInterface = &cachingFSTest{} func (t *cachingFSTest) setUp( + ti *TestInfo, lookupEntryTimeout time.Duration, - getattrTimeout time.Duration, - config *fuse.MountConfig) { + getattrTimeout time.Duration) { var err error - // Set up a temporary directory for mounting. - t.dir, err = ioutil.TempDir("", "caching_fs_test") - AssertEq(nil, err) - // Create the file system. t.fs, err = cachingfs.NewCachingFS(lookupEntryTimeout, getattrTimeout) AssertEq(nil, err) - // Mount it. - t.mfs, err = fuse.Mount(t.dir, t.fs, config) - AssertEq(nil, err) + t.FileSystem = t.fs - err = t.mfs.WaitForReady(context.Background()) - AssertEq(nil, err) + // Mount it. + t.SampleTest.SetUp(ti) // Set up the mtime. t.initialMtime = time.Date(2012, 8, 15, 22, 56, 0, 0, time.Local) t.fs.SetMtime(t.initialMtime) } -func (t *cachingFSTest) TearDown() { - // Was the file system mounted? - if t.mfs == nil { - return - } - - // Unmount the file system. Try again on "resource busy" errors. - delay := 10 * time.Millisecond - for { - err := t.mfs.Unmount() - if err == nil { - break - } - - if strings.Contains(err.Error(), "resource busy") { - log.Println("Resource busy error while unmounting; trying again") - time.Sleep(delay) - delay = time.Duration(1.3 * float64(delay)) - continue - } - - panic("MountedFileSystem.Unmount: " + err.Error()) - } - - if err := t.mfs.Join(context.Background()); err != nil { - panic("MountedFileSystem.Join: " + err.Error()) - } -} - func (t *cachingFSTest) statAll() (foo, dir, bar os.FileInfo) { var err error - foo, err = os.Stat(path.Join(t.dir, "foo")) + foo, err = os.Stat(path.Join(t.Dir, "foo")) AssertEq(nil, err) - dir, err = os.Stat(path.Join(t.dir, "dir")) + dir, err = os.Stat(path.Join(t.Dir, "dir")) AssertEq(nil, err) - bar, err = os.Stat(path.Join(t.dir, "dir/bar")) + bar, err = os.Stat(path.Join(t.Dir, "dir/bar")) AssertEq(nil, err) return @@ -121,13 +82,13 @@ func (t *cachingFSTest) statAll() (foo, dir, bar os.FileInfo) { func (t *cachingFSTest) openFiles() (foo, dir, bar *os.File) { var err error - foo, err = os.Open(path.Join(t.dir, "foo")) + foo, err = os.Open(path.Join(t.Dir, "foo")) AssertEq(nil, err) - dir, err = os.Open(path.Join(t.dir, "dir")) + dir, err = os.Open(path.Join(t.Dir, "dir")) AssertEq(nil, err) - bar, err = os.Open(path.Join(t.dir, "dir/bar")) + bar, err = os.Open(path.Join(t.Dir, "dir/bar")) AssertEq(nil, err) return @@ -171,7 +132,7 @@ func (t *BasicsTest) SetUp(ti *TestInfo) { getattrTimeout = 0 ) - t.cachingFSTest.setUp(lookupEntryTimeout, getattrTimeout, &fuse.MountConfig{}) + t.cachingFSTest.setUp(ti, lookupEntryTimeout, getattrTimeout) } func (t *BasicsTest) StatNonexistent() { @@ -184,7 +145,7 @@ func (t *BasicsTest) StatNonexistent() { } for _, n := range names { - _, err := os.Stat(path.Join(t.dir, n)) + _, err := os.Stat(path.Join(t.Dir, n)) AssertNe(nil, err) ExpectTrue(os.IsNotExist(err), "n: %s, err: %v", n, err) @@ -192,7 +153,7 @@ func (t *BasicsTest) StatNonexistent() { } func (t *BasicsTest) StatFoo() { - fi, err := os.Stat(path.Join(t.dir, "foo")) + fi, err := os.Stat(path.Join(t.Dir, "foo")) AssertEq(nil, err) ExpectEq("foo", fi.Name()) @@ -205,7 +166,7 @@ func (t *BasicsTest) StatFoo() { } func (t *BasicsTest) StatDir() { - fi, err := os.Stat(path.Join(t.dir, "dir")) + fi, err := os.Stat(path.Join(t.Dir, "dir")) AssertEq(nil, err) ExpectEq("dir", fi.Name()) @@ -217,7 +178,7 @@ func (t *BasicsTest) StatDir() { } func (t *BasicsTest) StatBar() { - fi, err := os.Stat(path.Join(t.dir, "dir/bar")) + fi, err := os.Stat(path.Join(t.Dir, "dir/bar")) AssertEq(nil, err) ExpectEq("bar", fi.Name()) @@ -247,7 +208,7 @@ func (t *NoCachingTest) SetUp(ti *TestInfo) { getattrTimeout = 0 ) - t.cachingFSTest.setUp(lookupEntryTimeout, getattrTimeout, &fuse.MountConfig{}) + t.cachingFSTest.setUp(ti, lookupEntryTimeout, getattrTimeout) } func (t *NoCachingTest) StatStat() { @@ -324,11 +285,9 @@ func init() { RegisterTestSuite(&EntryCachingTest{}) } func (t *EntryCachingTest) SetUp(ti *TestInfo) { t.lookupEntryTimeout = 250 * time.Millisecond - config := &fuse.MountConfig{ - EnableVnodeCaching: true, - } + t.SampleTest.MountConfig.EnableVnodeCaching = true - t.cachingFSTest.setUp(t.lookupEntryTimeout, 0, config) + t.cachingFSTest.setUp(ti, t.lookupEntryTimeout, 0) } func (t *EntryCachingTest) StatStat() { @@ -437,7 +396,7 @@ func init() { RegisterTestSuite(&AttributeCachingTest{}) } func (t *AttributeCachingTest) SetUp(ti *TestInfo) { t.getattrTimeout = 250 * time.Millisecond - t.cachingFSTest.setUp(0, t.getattrTimeout, &fuse.MountConfig{}) + t.cachingFSTest.setUp(ti, 0, t.getattrTimeout) } func (t *AttributeCachingTest) StatStat() { diff --git a/samples/hellofs/hello_fs_test.go b/samples/hellofs/hello_fs_test.go index c0daa89..c336029 100644 --- a/samples/hellofs/hello_fs_test.go +++ b/samples/hellofs/hello_fs_test.go @@ -17,20 +17,15 @@ package hellofs_test import ( "io" "io/ioutil" - "log" "os" "path" - "strings" "syscall" "testing" - "time" - "github.com/jacobsa/fuse" + "github.com/jacobsa/fuse/samples" "github.com/jacobsa/fuse/samples/hellofs" - "github.com/googlecloudplatform/gcsfuse/timeutil" . "github.com/jacobsa/oglematchers" . "github.com/jacobsa/ogletest" - "golang.org/x/net/context" ) func TestHelloFS(t *testing.T) { RunTests(t) } @@ -40,63 +35,17 @@ func TestHelloFS(t *testing.T) { RunTests(t) } //////////////////////////////////////////////////////////////////////// type HelloFSTest struct { - clock timeutil.SimulatedClock - mfs *fuse.MountedFileSystem + samples.SampleTest } -var _ SetUpInterface = &HelloFSTest{} -var _ TearDownInterface = &HelloFSTest{} - func init() { RegisterTestSuite(&HelloFSTest{}) } func (t *HelloFSTest) SetUp(ti *TestInfo) { - var err error - - // Set up a fixed, non-zero time. - t.clock.SetTime(time.Now()) - - // Set up a temporary directory for mounting. - mountPoint, err := ioutil.TempDir("", "hello_fs_test") - if err != nil { - panic("ioutil.TempDir: " + err.Error()) + t.FileSystem = &hellofs.HelloFS{ + Clock: &t.Clock, } - // Mount a file system. - fs := &hellofs.HelloFS{ - Clock: &t.clock, - } - - if t.mfs, err = fuse.Mount(mountPoint, fs, &fuse.MountConfig{}); err != nil { - panic("Mount: " + err.Error()) - } - - if err = t.mfs.WaitForReady(context.Background()); err != nil { - panic("MountedFileSystem.WaitForReady: " + err.Error()) - } -} - -func (t *HelloFSTest) TearDown() { - // Unmount the file system. Try again on "resource busy" errors. - delay := 10 * time.Millisecond - for { - err := t.mfs.Unmount() - if err == nil { - break - } - - if strings.Contains(err.Error(), "resource busy") { - log.Println("Resource busy error while unmounting; trying again") - time.Sleep(delay) - delay = time.Duration(1.3 * float64(delay)) - continue - } - - panic("MountedFileSystem.Unmount: " + err.Error()) - } - - if err := t.mfs.Join(context.Background()); err != nil { - panic("MountedFileSystem.Join: " + err.Error()) - } + t.SampleTest.SetUp(ti) } //////////////////////////////////////////////////////////////////////// @@ -104,7 +53,7 @@ func (t *HelloFSTest) TearDown() { //////////////////////////////////////////////////////////////////////// func (t *HelloFSTest) ReadDir_Root() { - entries, err := ioutil.ReadDir(t.mfs.Dir()) + entries, err := ioutil.ReadDir(t.Dir) AssertEq(nil, err) AssertEq(2, len(entries)) @@ -115,7 +64,7 @@ func (t *HelloFSTest) ReadDir_Root() { ExpectEq("dir", fi.Name()) ExpectEq(0, fi.Size()) ExpectEq(os.ModeDir|0555, fi.Mode()) - ExpectEq(0, t.clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime()) + ExpectEq(0, t.Clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime()) ExpectTrue(fi.IsDir()) // hello @@ -123,12 +72,12 @@ func (t *HelloFSTest) ReadDir_Root() { ExpectEq("hello", fi.Name()) ExpectEq(len("Hello, world!"), fi.Size()) ExpectEq(0444, fi.Mode()) - ExpectEq(0, t.clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime()) + ExpectEq(0, t.Clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime()) ExpectFalse(fi.IsDir()) } func (t *HelloFSTest) ReadDir_Dir() { - entries, err := ioutil.ReadDir(path.Join(t.mfs.Dir(), "dir")) + entries, err := ioutil.ReadDir(path.Join(t.Dir, "dir")) AssertEq(nil, err) AssertEq(1, len(entries)) @@ -139,76 +88,76 @@ func (t *HelloFSTest) ReadDir_Dir() { ExpectEq("world", fi.Name()) ExpectEq(len("Hello, world!"), fi.Size()) ExpectEq(0444, fi.Mode()) - ExpectEq(0, t.clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime()) + ExpectEq(0, t.Clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime()) ExpectFalse(fi.IsDir()) } func (t *HelloFSTest) ReadDir_NonExistent() { - _, err := ioutil.ReadDir(path.Join(t.mfs.Dir(), "foobar")) + _, err := ioutil.ReadDir(path.Join(t.Dir, "foobar")) AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("no such file"))) } func (t *HelloFSTest) Stat_Hello() { - fi, err := os.Stat(path.Join(t.mfs.Dir(), "hello")) + fi, err := os.Stat(path.Join(t.Dir, "hello")) AssertEq(nil, err) ExpectEq("hello", fi.Name()) ExpectEq(len("Hello, world!"), fi.Size()) ExpectEq(0444, fi.Mode()) - ExpectEq(0, t.clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime()) + ExpectEq(0, t.Clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime()) ExpectFalse(fi.IsDir()) ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink) } func (t *HelloFSTest) Stat_Dir() { - fi, err := os.Stat(path.Join(t.mfs.Dir(), "dir")) + fi, err := os.Stat(path.Join(t.Dir, "dir")) AssertEq(nil, err) ExpectEq("dir", fi.Name()) ExpectEq(0, fi.Size()) ExpectEq(0555|os.ModeDir, fi.Mode()) - ExpectEq(0, t.clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime()) + ExpectEq(0, t.Clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime()) ExpectTrue(fi.IsDir()) ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink) } func (t *HelloFSTest) Stat_World() { - fi, err := os.Stat(path.Join(t.mfs.Dir(), "dir/world")) + fi, err := os.Stat(path.Join(t.Dir, "dir/world")) AssertEq(nil, err) ExpectEq("world", fi.Name()) ExpectEq(len("Hello, world!"), fi.Size()) ExpectEq(0444, fi.Mode()) - ExpectEq(0, t.clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime()) + ExpectEq(0, t.Clock.Now().Sub(fi.ModTime()), "ModTime: %v", fi.ModTime()) ExpectFalse(fi.IsDir()) ExpectEq(1, fi.Sys().(*syscall.Stat_t).Nlink) } func (t *HelloFSTest) Stat_NonExistent() { - _, err := os.Stat(path.Join(t.mfs.Dir(), "foobar")) + _, err := os.Stat(path.Join(t.Dir, "foobar")) AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("no such file"))) } func (t *HelloFSTest) ReadFile_Hello() { - slice, err := ioutil.ReadFile(path.Join(t.mfs.Dir(), "hello")) + slice, err := ioutil.ReadFile(path.Join(t.Dir, "hello")) AssertEq(nil, err) ExpectEq("Hello, world!", string(slice)) } func (t *HelloFSTest) ReadFile_Dir() { - _, err := ioutil.ReadFile(path.Join(t.mfs.Dir(), "dir")) + _, err := ioutil.ReadFile(path.Join(t.Dir, "dir")) AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("is a directory"))) } func (t *HelloFSTest) ReadFile_World() { - slice, err := ioutil.ReadFile(path.Join(t.mfs.Dir(), "dir/world")) + slice, err := ioutil.ReadFile(path.Join(t.Dir, "dir/world")) AssertEq(nil, err) ExpectEq("Hello, world!", string(slice)) @@ -221,7 +170,7 @@ func (t *HelloFSTest) OpenAndRead() { var err error // Open the file. - f, err := os.Open(path.Join(t.mfs.Dir(), "hello")) + f, err := os.Open(path.Join(t.Dir, "hello")) defer func() { if f != nil { ExpectEq(nil, f.Close()) @@ -268,7 +217,7 @@ func (t *HelloFSTest) OpenAndRead() { } func (t *HelloFSTest) Open_NonExistent() { - _, err := os.Open(path.Join(t.mfs.Dir(), "foobar")) + _, err := os.Open(path.Join(t.Dir, "foobar")) AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("no such file"))) diff --git a/samples/memfs/memfs_test.go b/samples/memfs/memfs_test.go index 51008cd..f51648d 100644 --- a/samples/memfs/memfs_test.go +++ b/samples/memfs/memfs_test.go @@ -17,23 +17,19 @@ package memfs_test import ( "io" "io/ioutil" - "log" "os" "os/user" "path" "strconv" - "strings" "syscall" "testing" "time" - "github.com/jacobsa/fuse" "github.com/jacobsa/fuse/fusetesting" + "github.com/jacobsa/fuse/samples" "github.com/jacobsa/fuse/samples/memfs" - "github.com/googlecloudplatform/gcsfuse/timeutil" . "github.com/jacobsa/oglematchers" . "github.com/jacobsa/ogletest" - "golang.org/x/net/context" ) func TestMemFS(t *testing.T) { RunTests(t) } @@ -86,77 +82,14 @@ func applyUmask(m os.FileMode) os.FileMode { //////////////////////////////////////////////////////////////////////// type MemFSTest struct { - clock timeutil.SimulatedClock - mfs *fuse.MountedFileSystem - - // Files to close when tearing down. Nil entries are skipped. - toClose []io.Closer + samples.SampleTest } -var _ SetUpInterface = &MemFSTest{} -var _ TearDownInterface = &MemFSTest{} - func init() { RegisterTestSuite(&MemFSTest{}) } func (t *MemFSTest) SetUp(ti *TestInfo) { - var err error - - // Set up a fixed, non-zero time. - t.clock.SetTime(time.Now()) - - // Set up a temporary directory for mounting. - mountPoint, err := ioutil.TempDir("", "memfs_test") - if err != nil { - panic("ioutil.TempDir: " + err.Error()) - } - - // Mount a file system. - fs := memfs.NewMemFS(currentUid(), currentGid(), &t.clock) - - t.mfs, err = fuse.Mount(mountPoint, fs, &fuse.MountConfig{}) - if err != nil { - panic("Mount: " + err.Error()) - } - - if err = t.mfs.WaitForReady(context.Background()); err != nil { - panic("MountedFileSystem.WaitForReady: " + err.Error()) - } -} - -func (t *MemFSTest) TearDown() { - // Close any files we opened. - for _, c := range t.toClose { - if c == nil { - continue - } - - err := c.Close() - if err != nil { - panic(err) - } - } - - // Unmount the file system. Try again on "resource busy" errors. - delay := 10 * time.Millisecond - for { - err := t.mfs.Unmount() - if err == nil { - break - } - - if strings.Contains(err.Error(), "resource busy") { - log.Println("Resource busy error while unmounting; trying again") - time.Sleep(delay) - delay = time.Duration(1.3 * float64(delay)) - continue - } - - panic("MountedFileSystem.Unmount: " + err.Error()) - } - - if err := t.mfs.Join(context.Background()); err != nil { - panic("MountedFileSystem.Join: " + err.Error()) - } + t.FileSystem = memfs.NewMemFS(currentUid(), currentGid(), &t.Clock) + t.SampleTest.SetUp(ti) } //////////////////////////////////////////////////////////////////////// @@ -164,7 +97,7 @@ func (t *MemFSTest) TearDown() { //////////////////////////////////////////////////////////////////////// func (t *MemFSTest) ContentsOfEmptyFileSystem() { - entries, err := ioutil.ReadDir(t.mfs.Dir()) + entries, err := ioutil.ReadDir(t.Dir) AssertEq(nil, err) ExpectThat(entries, ElementsAre()) @@ -176,18 +109,18 @@ func (t *MemFSTest) Mkdir_OneLevel() { var stat *syscall.Stat_t var entries []os.FileInfo - dirName := path.Join(t.mfs.Dir(), "dir") + dirName := path.Join(t.Dir, "dir") // Simulate time advancing. - t.clock.AdvanceTime(time.Second) + t.Clock.AdvanceTime(time.Second) // Create a directory within the root. - createTime := t.clock.Now() + createTime := t.Clock.Now() err = os.Mkdir(dirName, 0754) AssertEq(nil, err) // Simulate time advancing. - t.clock.AdvanceTime(time.Second) + t.Clock.AdvanceTime(time.Second) // Stat the directory. fi, err = os.Stat(dirName) @@ -208,7 +141,7 @@ func (t *MemFSTest) Mkdir_OneLevel() { ExpectEq(0, stat.Size) // Check the root's mtime. - fi, err = os.Stat(t.mfs.Dir()) + fi, err = os.Stat(t.Dir) AssertEq(nil, err) ExpectEq(0, fi.ModTime().Sub(createTime)) @@ -220,7 +153,7 @@ func (t *MemFSTest) Mkdir_OneLevel() { ExpectThat(entries, ElementsAre()) // Read the root. - entries, err = ioutil.ReadDir(t.mfs.Dir()) + entries, err = ioutil.ReadDir(t.Dir) AssertEq(nil, err) AssertEq(1, len(entries)) @@ -237,22 +170,22 @@ func (t *MemFSTest) Mkdir_TwoLevels() { var entries []os.FileInfo // Create a directory within the root. - err = os.Mkdir(path.Join(t.mfs.Dir(), "parent"), 0700) + err = os.Mkdir(path.Join(t.Dir, "parent"), 0700) AssertEq(nil, err) // Simulate time advancing. - t.clock.AdvanceTime(time.Second) + t.Clock.AdvanceTime(time.Second) // Create a child of that directory. - createTime := t.clock.Now() - err = os.Mkdir(path.Join(t.mfs.Dir(), "parent/dir"), 0754) + createTime := t.Clock.Now() + err = os.Mkdir(path.Join(t.Dir, "parent/dir"), 0754) AssertEq(nil, err) // Simulate time advancing. - t.clock.AdvanceTime(time.Second) + t.Clock.AdvanceTime(time.Second) // Stat the directory. - fi, err = os.Stat(path.Join(t.mfs.Dir(), "parent/dir")) + fi, err = os.Stat(path.Join(t.Dir, "parent/dir")) stat = fi.Sys().(*syscall.Stat_t) AssertEq(nil, err) @@ -270,18 +203,18 @@ func (t *MemFSTest) Mkdir_TwoLevels() { ExpectEq(0, stat.Size) // Check the parent's mtime. - fi, err = os.Stat(path.Join(t.mfs.Dir(), "parent")) + fi, err = os.Stat(path.Join(t.Dir, "parent")) AssertEq(nil, err) ExpectEq(0, fi.ModTime().Sub(createTime)) // Read the directory. - entries, err = ioutil.ReadDir(path.Join(t.mfs.Dir(), "parent/dir")) + entries, err = ioutil.ReadDir(path.Join(t.Dir, "parent/dir")) AssertEq(nil, err) ExpectThat(entries, ElementsAre()) // Read the parent. - entries, err = ioutil.ReadDir(path.Join(t.mfs.Dir(), "parent")) + entries, err = ioutil.ReadDir(path.Join(t.Dir, "parent")) AssertEq(nil, err) AssertEq(1, len(entries)) @@ -293,7 +226,7 @@ func (t *MemFSTest) Mkdir_TwoLevels() { func (t *MemFSTest) Mkdir_AlreadyExists() { var err error - dirName := path.Join(t.mfs.Dir(), "dir") + dirName := path.Join(t.Dir, "dir") // Create the directory once. err = os.Mkdir(dirName, 0754) @@ -310,7 +243,7 @@ func (t *MemFSTest) Mkdir_IntermediateIsFile() { var err error // Create a file. - fileName := path.Join(t.mfs.Dir(), "foo") + fileName := path.Join(t.Dir, "foo") err = ioutil.WriteFile(fileName, []byte{}, 0700) AssertEq(nil, err) @@ -326,7 +259,7 @@ func (t *MemFSTest) Mkdir_IntermediateIsNonExistent() { var err error // Attempt to create a sub-directory of a non-existent sub-directory. - dirName := path.Join(t.mfs.Dir(), "foo/dir") + dirName := path.Join(t.Dir, "foo/dir") err = os.Mkdir(dirName, 0754) AssertNe(nil, err) @@ -337,11 +270,11 @@ func (t *MemFSTest) Mkdir_PermissionDenied() { var err error // Create a directory within the root without write permissions. - err = os.Mkdir(path.Join(t.mfs.Dir(), "parent"), 0500) + err = os.Mkdir(path.Join(t.Dir, "parent"), 0500) AssertEq(nil, err) // Attempt to create a child of that directory. - err = os.Mkdir(path.Join(t.mfs.Dir(), "parent/dir"), 0754) + err = os.Mkdir(path.Join(t.Dir, "parent/dir"), 0754) AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("permission denied"))) @@ -353,15 +286,15 @@ func (t *MemFSTest) CreateNewFile_InRoot() { var stat *syscall.Stat_t // Write a file. - fileName := path.Join(t.mfs.Dir(), "foo") + fileName := path.Join(t.Dir, "foo") const contents = "Hello\x00world" - createTime := t.clock.Now() + createTime := t.Clock.Now() err = ioutil.WriteFile(fileName, []byte(contents), 0400) AssertEq(nil, err) // Simulate time advancing. - t.clock.AdvanceTime(time.Second) + t.Clock.AdvanceTime(time.Second) // Stat it. fi, err = os.Stat(fileName) @@ -393,7 +326,7 @@ func (t *MemFSTest) CreateNewFile_InSubDir() { var stat *syscall.Stat_t // Create a sub-dir. - dirName := path.Join(t.mfs.Dir(), "dir") + dirName := path.Join(t.Dir, "dir") err = os.Mkdir(dirName, 0700) AssertEq(nil, err) @@ -401,12 +334,12 @@ func (t *MemFSTest) CreateNewFile_InSubDir() { fileName := path.Join(dirName, "foo") const contents = "Hello\x00world" - createTime := t.clock.Now() + createTime := t.Clock.Now() err = ioutil.WriteFile(fileName, []byte(contents), 0400) AssertEq(nil, err) // Simulate time advancing. - t.clock.AdvanceTime(time.Second) + t.Clock.AdvanceTime(time.Second) // Stat it. fi, err = os.Stat(fileName) @@ -439,27 +372,27 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() { var stat *syscall.Stat_t // Write a file. - fileName := path.Join(t.mfs.Dir(), "foo") + fileName := path.Join(t.Dir, "foo") - createTime := t.clock.Now() + createTime := t.Clock.Now() err = ioutil.WriteFile(fileName, []byte("Hello, world!"), 0600) AssertEq(nil, err) // Simulate time advancing. - t.clock.AdvanceTime(time.Second) + t.Clock.AdvanceTime(time.Second) // Open the file and modify it. f, err := os.OpenFile(fileName, os.O_WRONLY, 0400) - t.toClose = append(t.toClose, f) + t.ToClose = append(t.ToClose, f) AssertEq(nil, err) - modifyTime := t.clock.Now() + modifyTime := t.Clock.Now() n, err = f.WriteAt([]byte("H"), 0) AssertEq(nil, err) AssertEq(1, n) // Simulate time advancing. - t.clock.AdvanceTime(time.Second) + t.Clock.AdvanceTime(time.Second) // Stat the file. fi, err = os.Stat(fileName) @@ -492,32 +425,32 @@ func (t *MemFSTest) ModifyExistingFile_InSubDir() { var stat *syscall.Stat_t // Create a sub-directory. - dirName := path.Join(t.mfs.Dir(), "dir") + dirName := path.Join(t.Dir, "dir") err = os.Mkdir(dirName, 0700) AssertEq(nil, err) // Write a file. fileName := path.Join(dirName, "foo") - createTime := t.clock.Now() + createTime := t.Clock.Now() err = ioutil.WriteFile(fileName, []byte("Hello, world!"), 0600) AssertEq(nil, err) // Simulate time advancing. - t.clock.AdvanceTime(time.Second) + t.Clock.AdvanceTime(time.Second) // Open the file and modify it. f, err := os.OpenFile(fileName, os.O_WRONLY, 0400) - t.toClose = append(t.toClose, f) + t.ToClose = append(t.ToClose, f) AssertEq(nil, err) - modifyTime := t.clock.Now() + modifyTime := t.Clock.Now() n, err = f.WriteAt([]byte("H"), 0) AssertEq(nil, err) AssertEq(1, n) // Simulate time advancing. - t.clock.AdvanceTime(time.Second) + t.Clock.AdvanceTime(time.Second) // Stat the file. fi, err = os.Stat(fileName) @@ -547,7 +480,7 @@ func (t *MemFSTest) UnlinkFile_Exists() { var err error // Write a file. - fileName := path.Join(t.mfs.Dir(), "foo") + fileName := path.Join(t.Dir, "foo") err = ioutil.WriteFile(fileName, []byte("Hello, world!"), 0600) AssertEq(nil, err) @@ -562,24 +495,24 @@ func (t *MemFSTest) UnlinkFile_Exists() { ExpectThat(err, Error(HasSubstr("no such file"))) // Nothing should be in the directory. - entries, err := ioutil.ReadDir(t.mfs.Dir()) + entries, err := ioutil.ReadDir(t.Dir) AssertEq(nil, err) ExpectThat(entries, ElementsAre()) } func (t *MemFSTest) UnlinkFile_NonExistent() { - err := os.Remove(path.Join(t.mfs.Dir(), "foo")) + err := os.Remove(path.Join(t.Dir, "foo")) AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("no such file"))) } func (t *MemFSTest) UnlinkFile_StillOpen() { - fileName := path.Join(t.mfs.Dir(), "foo") + fileName := path.Join(t.Dir, "foo") // Create and open a file. f, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0600) - t.toClose = append(t.toClose, f) + t.ToClose = append(t.ToClose, f) AssertEq(nil, err) // Write some data into it. @@ -592,7 +525,7 @@ func (t *MemFSTest) UnlinkFile_StillOpen() { AssertEq(nil, err) // The directory should no longer contain it. - entries, err := ioutil.ReadDir(t.mfs.Dir()) + entries, err := ioutil.ReadDir(t.Dir) AssertEq(nil, err) ExpectThat(entries, ElementsAre()) @@ -622,11 +555,11 @@ func (t *MemFSTest) Rmdir_NonEmpty() { var err error // Create two levels of directories. - err = os.MkdirAll(path.Join(t.mfs.Dir(), "foo/bar"), 0754) + err = os.MkdirAll(path.Join(t.Dir, "foo/bar"), 0754) AssertEq(nil, err) // Attempt to remove the parent. - err = os.Remove(path.Join(t.mfs.Dir(), "foo")) + err = os.Remove(path.Join(t.Dir, "foo")) AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("not empty"))) @@ -637,44 +570,44 @@ func (t *MemFSTest) Rmdir_Empty() { var entries []os.FileInfo // Create two levels of directories. - err = os.MkdirAll(path.Join(t.mfs.Dir(), "foo/bar"), 0754) + err = os.MkdirAll(path.Join(t.Dir, "foo/bar"), 0754) AssertEq(nil, err) // Simulate time advancing. - t.clock.AdvanceTime(time.Second) + t.Clock.AdvanceTime(time.Second) // Remove the leaf. - rmTime := t.clock.Now() - err = os.Remove(path.Join(t.mfs.Dir(), "foo/bar")) + rmTime := t.Clock.Now() + err = os.Remove(path.Join(t.Dir, "foo/bar")) AssertEq(nil, err) // Simulate time advancing. - t.clock.AdvanceTime(time.Second) + t.Clock.AdvanceTime(time.Second) // There should be nothing left in the parent. - entries, err = ioutil.ReadDir(path.Join(t.mfs.Dir(), "foo")) + entries, err = ioutil.ReadDir(path.Join(t.Dir, "foo")) AssertEq(nil, err) ExpectThat(entries, ElementsAre()) // Check the parent's mtime. - fi, err := os.Stat(path.Join(t.mfs.Dir(), "foo")) + fi, err := os.Stat(path.Join(t.Dir, "foo")) AssertEq(nil, err) ExpectEq(0, fi.ModTime().Sub(rmTime)) // Remove the parent. - err = os.Remove(path.Join(t.mfs.Dir(), "foo")) + err = os.Remove(path.Join(t.Dir, "foo")) AssertEq(nil, err) // Now the root directory should be empty, too. - entries, err = ioutil.ReadDir(t.mfs.Dir()) + entries, err = ioutil.ReadDir(t.Dir) AssertEq(nil, err) ExpectThat(entries, ElementsAre()) } func (t *MemFSTest) Rmdir_NonExistent() { - err := os.Remove(path.Join(t.mfs.Dir(), "blah")) + err := os.Remove(path.Join(t.Dir, "blah")) AssertNe(nil, err) ExpectThat(err, Error(HasSubstr("no such file or directory"))) @@ -684,15 +617,15 @@ func (t *MemFSTest) Rmdir_OpenedForReading() { var err error // Create a directory. - createTime := t.clock.Now() - err = os.Mkdir(path.Join(t.mfs.Dir(), "dir"), 0700) + createTime := t.Clock.Now() + err = os.Mkdir(path.Join(t.Dir, "dir"), 0700) AssertEq(nil, err) // Simulate time advancing. - t.clock.AdvanceTime(time.Second) + t.Clock.AdvanceTime(time.Second) // Open the directory for reading. - f, err := os.Open(path.Join(t.mfs.Dir(), "dir")) + f, err := os.Open(path.Join(t.Dir, "dir")) defer func() { if f != nil { ExpectEq(nil, f.Close()) @@ -702,18 +635,18 @@ func (t *MemFSTest) Rmdir_OpenedForReading() { AssertEq(nil, err) // Remove the directory. - err = os.Remove(path.Join(t.mfs.Dir(), "dir")) + err = os.Remove(path.Join(t.Dir, "dir")) AssertEq(nil, err) // Create a new directory, with the same name even, and add some contents // within it. - err = os.MkdirAll(path.Join(t.mfs.Dir(), "dir/foo"), 0700) + err = os.MkdirAll(path.Join(t.Dir, "dir/foo"), 0700) AssertEq(nil, err) - err = os.MkdirAll(path.Join(t.mfs.Dir(), "dir/bar"), 0700) + err = os.MkdirAll(path.Join(t.Dir, "dir/bar"), 0700) AssertEq(nil, err) - err = os.MkdirAll(path.Join(t.mfs.Dir(), "dir/baz"), 0700) + err = os.MkdirAll(path.Join(t.Dir, "dir/baz"), 0700) AssertEq(nil, err) // We should still be able to stat the open file handle. It should show up as @@ -740,11 +673,11 @@ func (t *MemFSTest) CaseSensitive() { var err error // Create a file. - err = ioutil.WriteFile(path.Join(t.mfs.Dir(), "file"), []byte{}, 0400) + err = ioutil.WriteFile(path.Join(t.Dir, "file"), []byte{}, 0400) AssertEq(nil, err) // Create a directory. - err = os.Mkdir(path.Join(t.mfs.Dir(), "dir"), 0400) + err = os.Mkdir(path.Join(t.Dir, "dir"), 0400) AssertEq(nil, err) // Attempt to stat with the wrong case. @@ -758,7 +691,7 @@ func (t *MemFSTest) CaseSensitive() { } for _, name := range names { - _, err = os.Stat(path.Join(t.mfs.Dir(), name)) + _, err = os.Stat(path.Join(t.Dir, name)) AssertNe(nil, err, "Name: %s", name) AssertThat(err, Error(HasSubstr("no such file or directory"))) } @@ -769,8 +702,8 @@ func (t *MemFSTest) WriteOverlapsEndOfFile() { var n int // Create a file. - f, err := os.Create(path.Join(t.mfs.Dir(), "foo")) - t.toClose = append(t.toClose, f) + f, err := os.Create(path.Join(t.Dir, "foo")) + t.ToClose = append(t.ToClose, f) AssertEq(nil, err) // Make it 4 bytes long. @@ -793,8 +726,8 @@ func (t *MemFSTest) WriteStartsAtEndOfFile() { var n int // Create a file. - f, err := os.Create(path.Join(t.mfs.Dir(), "foo")) - t.toClose = append(t.toClose, f) + f, err := os.Create(path.Join(t.Dir, "foo")) + t.ToClose = append(t.ToClose, f) AssertEq(nil, err) // Make it 2 bytes long. @@ -817,8 +750,8 @@ func (t *MemFSTest) WriteStartsPastEndOfFile() { var n int // Create a file. - f, err := os.Create(path.Join(t.mfs.Dir(), "foo")) - t.toClose = append(t.toClose, f) + f, err := os.Create(path.Join(t.Dir, "foo")) + t.ToClose = append(t.ToClose, f) AssertEq(nil, err) // Write the range [2, 6). @@ -837,8 +770,8 @@ func (t *MemFSTest) WriteAtDoesntChangeOffset_NotAppendMode() { var n int // Create a file. - f, err := os.Create(path.Join(t.mfs.Dir(), "foo")) - t.toClose = append(t.toClose, f) + f, err := os.Create(path.Join(t.Dir, "foo")) + t.ToClose = append(t.ToClose, f) AssertEq(nil, err) // Make it 16 bytes long. @@ -866,11 +799,11 @@ func (t *MemFSTest) WriteAtDoesntChangeOffset_AppendMode() { // Create a file in append mode. f, err := os.OpenFile( - path.Join(t.mfs.Dir(), "foo"), + path.Join(t.Dir, "foo"), os.O_RDWR|os.O_APPEND|os.O_CREATE, 0600) - t.toClose = append(t.toClose, f) + t.ToClose = append(t.ToClose, f) AssertEq(nil, err) // Make it 16 bytes long. @@ -899,13 +832,13 @@ func (t *MemFSTest) AppendMode() { buf := make([]byte, 1024) // Create a file with some contents. - fileName := path.Join(t.mfs.Dir(), "foo") + fileName := path.Join(t.Dir, "foo") err = ioutil.WriteFile(fileName, []byte("Jello, "), 0600) AssertEq(nil, err) // Open the file in append mode. f, err := os.OpenFile(fileName, os.O_RDWR|os.O_APPEND, 0600) - t.toClose = append(t.toClose, f) + t.ToClose = append(t.ToClose, f) AssertEq(nil, err) // Seek to somewhere silly and then write. @@ -953,8 +886,8 @@ func (t *MemFSTest) ReadsPastEndOfFile() { buf := make([]byte, 1024) // Create a file. - f, err := os.Create(path.Join(t.mfs.Dir(), "foo")) - t.toClose = append(t.toClose, f) + f, err := os.Create(path.Join(t.Dir, "foo")) + t.ToClose = append(t.ToClose, f) AssertEq(nil, err) // Give it some contents. @@ -983,7 +916,7 @@ func (t *MemFSTest) ReadsPastEndOfFile() { func (t *MemFSTest) Truncate_Smaller() { var err error - fileName := path.Join(t.mfs.Dir(), "foo") + fileName := path.Join(t.Dir, "foo") // Create a file. err = ioutil.WriteFile(fileName, []byte("taco"), 0600) @@ -991,7 +924,7 @@ func (t *MemFSTest) Truncate_Smaller() { // Open it for modification. f, err := os.OpenFile(fileName, os.O_RDWR, 0) - t.toClose = append(t.toClose, f) + t.ToClose = append(t.ToClose, f) AssertEq(nil, err) // Truncate it. @@ -1011,7 +944,7 @@ func (t *MemFSTest) Truncate_Smaller() { func (t *MemFSTest) Truncate_SameSize() { var err error - fileName := path.Join(t.mfs.Dir(), "foo") + fileName := path.Join(t.Dir, "foo") // Create a file. err = ioutil.WriteFile(fileName, []byte("taco"), 0600) @@ -1019,7 +952,7 @@ func (t *MemFSTest) Truncate_SameSize() { // Open it for modification. f, err := os.OpenFile(fileName, os.O_RDWR, 0) - t.toClose = append(t.toClose, f) + t.ToClose = append(t.ToClose, f) AssertEq(nil, err) // Truncate it. @@ -1039,7 +972,7 @@ func (t *MemFSTest) Truncate_SameSize() { func (t *MemFSTest) Truncate_Larger() { var err error - fileName := path.Join(t.mfs.Dir(), "foo") + fileName := path.Join(t.Dir, "foo") // Create a file. err = ioutil.WriteFile(fileName, []byte("taco"), 0600) @@ -1047,7 +980,7 @@ func (t *MemFSTest) Truncate_Larger() { // Open it for modification. f, err := os.OpenFile(fileName, os.O_RDWR, 0) - t.toClose = append(t.toClose, f) + t.ToClose = append(t.ToClose, f) AssertEq(nil, err) // Truncate it. @@ -1067,7 +1000,7 @@ func (t *MemFSTest) Truncate_Larger() { func (t *MemFSTest) Chmod() { var err error - fileName := path.Join(t.mfs.Dir(), "foo") + fileName := path.Join(t.Dir, "foo") // Create a file. err = ioutil.WriteFile(fileName, []byte(""), 0600) @@ -1085,7 +1018,7 @@ func (t *MemFSTest) Chmod() { func (t *MemFSTest) Chtimes() { var err error - fileName := path.Join(t.mfs.Dir(), "foo") + fileName := path.Join(t.Dir, "foo") // Create a file. err = ioutil.WriteFile(fileName, []byte(""), 0600) @@ -1103,7 +1036,7 @@ func (t *MemFSTest) Chtimes() { } func (t *MemFSTest) ReadDirWhileModifying() { - dirName := path.Join(t.mfs.Dir(), "dir") + dirName := path.Join(t.Dir, "dir") createFile := func(name string) { AssertEq(nil, ioutil.WriteFile(path.Join(dirName, name), []byte{}, 0400)) } @@ -1114,7 +1047,7 @@ func (t *MemFSTest) ReadDirWhileModifying() { // Open the directory. d, err := os.Open(dirName) - t.toClose = append(t.toClose, d) + t.ToClose = append(t.ToClose, d) AssertEq(nil, err) // Add four files. diff --git a/samples/testing.go b/samples/testing.go new file mode 100644 index 0000000..bdb2b57 --- /dev/null +++ b/samples/testing.go @@ -0,0 +1,152 @@ +// Copyright 2015 Google Inc. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package samples + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "strings" + "time" + + "github.com/googlecloudplatform/gcsfuse/timeutil" + "github.com/jacobsa/fuse" + "github.com/jacobsa/ogletest" + "golang.org/x/net/context" +) + +// A struct that implements common behavior needed by tests in the samples/ +// directory. Use it as an embedded field in your test fixture, calling its +// SetUp method from your SetUp method after setting the FileSystem field. +type SampleTest struct { + // The file system under test and the configuration with which it should be + // mounted. These must be set by the user of this type before calling SetUp; + // all the other fields below are set by SetUp itself. + FileSystem fuse.FileSystem + MountConfig fuse.MountConfig + + // A context object that can be used for long-running operations. + Ctx context.Context + + // A clock with a fixed initial time. The test's set up method may use this + // to wire the file system with a clock, if desired. + Clock timeutil.SimulatedClock + + // The directory at which the file system is mounted. + Dir string + + // Anothing non-nil in this slice will be closed by TearDown. The test will + // fail if closing fails. + ToClose []io.Closer + + mfs *fuse.MountedFileSystem +} + +// Mount the supplied file system and initialize the other exported fields of +// the struct. Panics on error. +// +// REQUIRES: t.FileSystem has been set. +func (t *SampleTest) SetUp(ti *ogletest.TestInfo) { + err := t.initialize(t.FileSystem, &t.MountConfig) + if err != nil { + panic(err) + } +} + +// Like Initialize, but doens't panic. +func (t *SampleTest) initialize( + fs fuse.FileSystem, + config *fuse.MountConfig) (err error) { + // Initialize the context. + t.Ctx = context.Background() + + // Initialize the clock. + t.Clock.SetTime(time.Date(2012, 8, 15, 22, 56, 0, 0, time.Local)) + + // Set up a temporary directory. + t.Dir, err = ioutil.TempDir("", "sample_test") + if err != nil { + err = fmt.Errorf("TempDir: %v", err) + return + } + + // Mount the file system. + t.mfs, err = fuse.Mount(t.Dir, fs, config) + if err != nil { + err = fmt.Errorf("Mount: %v", err) + return + } + + // Wait for it to be read. + err = t.mfs.WaitForReady(t.Ctx) + if err != nil { + err = fmt.Errorf("WaitForReady: %v", err) + return + } + + return +} + +// Unmount the file system and clean up. Panics on error. +func (t *SampleTest) TearDown() { + err := t.destroy() + if err != nil { + panic(err) + } +} + +// Like TearDown, but doesn't panic. +func (t *SampleTest) destroy() (err error) { + // Close what is necessary. + for _, c := range t.ToClose { + if c == nil { + continue + } + + ogletest.ExpectEq(nil, c.Close()) + } + + // Was the file system mounted? + if t.mfs == nil { + return + } + + // Unmount the file system. Try again on "resource busy" errors. + delay := 10 * time.Millisecond + for { + err = t.mfs.Unmount() + if err == nil { + break + } + + if strings.Contains(err.Error(), "resource busy") { + log.Println("Resource busy error while unmounting; trying again") + time.Sleep(delay) + delay = time.Duration(1.3 * float64(delay)) + continue + } + + err = fmt.Errorf("MountedFileSystem.Unmount: %v", err) + return + } + + if err = t.mfs.Join(t.Ctx); err != nil { + err = fmt.Errorf("MountedFileSystem.Join: %v", err) + return + } + + return +}