From 72b8c3e9a093bef951b04607d8aaf31d621a6f94 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Mon, 16 Mar 2015 12:18:06 +1100 Subject: [PATCH 1/9] Declared two time-related matchers. --- fusetesting/stat.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 fusetesting/stat.go diff --git a/fusetesting/stat.go b/fusetesting/stat.go new file mode 100644 index 0000000..b157e08 --- /dev/null +++ b/fusetesting/stat.go @@ -0,0 +1,31 @@ +// 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 fusetesting + +import ( + "time" + + "github.com/jacobsa/oglematchers" +) + +// Match *os.FileInfo values that specify an mtime equal to the given time. On +// platforms where the Sys() method returns a struct containing an mtime, check +// also that it matches. +func MtimeIs(expected time.Time) oglematchers.Matcher + +// Match *os.FileInfo values that specify a file birth time equal to the given +// time. On platforms where there is no birth time available, match all +// *os.FileInfo values. +func BirthtimeIs(expected time.Time) oglematchers.Matcher From 47570943e401417f8399bbe3684fc2184b46c3a5 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Mon, 16 Mar 2015 12:23:25 +1100 Subject: [PATCH 2/9] Implemented MtimeIs. --- fusetesting/stat.go | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/fusetesting/stat.go b/fusetesting/stat.go index b157e08..c1d282c 100644 --- a/fusetesting/stat.go +++ b/fusetesting/stat.go @@ -15,17 +15,47 @@ package fusetesting import ( + "fmt" + "os" + "reflect" "time" "github.com/jacobsa/oglematchers" ) -// Match *os.FileInfo values that specify an mtime equal to the given time. On +// Match os.FileInfo values that specify an mtime equal to the given time. On // platforms where the Sys() method returns a struct containing an mtime, check // also that it matches. -func MtimeIs(expected time.Time) oglematchers.Matcher +func MtimeIs(expected time.Time) oglematchers.Matcher { + return oglematchers.NewMatcher( + func(c interface{}) error { return mtimeIs(c, expected) }, + fmt.Sprintf("mtime is %v", expected)) +} -// Match *os.FileInfo values that specify a file birth time equal to the given +func mtimeIs(c interface{}, expected time.Time) error { + fi, ok := c.(os.FileInfo) + if !ok { + return fmt.Errorf("which is of type %v", reflect.TypeOf(c)) + } + + // Check ModTime(). + if fi.ModTime() != expected { + d := fi.ModTime().Sub(expected) + return fmt.Errorf("which has mtime %v, off by %v", fi.ModTime(), d) + } + + // Check Sys(). + if sysMtime, ok := extractMtime(fi.Sys()); ok { + if sysMtime != expected { + d := sysMtime.Sub(expected) + return fmt.Errorf("which has Sys() mtime %v, off by %v", sysMtime, d) + } + } + + return nil +} + +// Match os.FileInfo values that specify a file birth time equal to the given // time. On platforms where there is no birth time available, match all -// *os.FileInfo values. +// os.FileInfo values. func BirthtimeIs(expected time.Time) oglematchers.Matcher From f3df183df02dd3ab083220de0ff8c98d146176ab Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Mon, 16 Mar 2015 12:24:40 +1100 Subject: [PATCH 3/9] Fixed a build error. --- fusetesting/stat.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fusetesting/stat.go b/fusetesting/stat.go index c1d282c..320dbdf 100644 --- a/fusetesting/stat.go +++ b/fusetesting/stat.go @@ -55,6 +55,12 @@ func mtimeIs(c interface{}, expected time.Time) error { return nil } +// Extract the mtime from the result of os.FileInfo.Sys(), in a +// platform-specific way. If not supported on this platform, return !ok. +// +// Defined in stat_darwin.go, etc. +func extractMtime(sys interface{}) (mtime time.Time, ok bool) + // Match os.FileInfo values that specify a file birth time equal to the given // time. On platforms where there is no birth time available, match all // os.FileInfo values. From e264d64ef39bd7f775215e9562575f36198cc172 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Mon, 16 Mar 2015 12:25:13 +1100 Subject: [PATCH 4/9] Defined extractMtime for darwin. --- fusetesting/stat_darwin.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 fusetesting/stat_darwin.go diff --git a/fusetesting/stat_darwin.go b/fusetesting/stat_darwin.go new file mode 100644 index 0000000..c8785d5 --- /dev/null +++ b/fusetesting/stat_darwin.go @@ -0,0 +1,26 @@ +// 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 fusetesting + +import ( + "syscall" + "time" +) + +func extractMtime(sys interface{}) (mtime time.Time, ok bool) { + mtime = time.Unix(sys.(*syscall.Stat_t).Mtimespec.Unix()) + ok = true + return +} From 9489817fc6e55d30a172eb233daf10425805c74a Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Mon, 16 Mar 2015 12:27:57 +1100 Subject: [PATCH 5/9] Fixed a build error. --- fusetesting/stat.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/fusetesting/stat.go b/fusetesting/stat.go index 320dbdf..c1d282c 100644 --- a/fusetesting/stat.go +++ b/fusetesting/stat.go @@ -55,12 +55,6 @@ func mtimeIs(c interface{}, expected time.Time) error { return nil } -// Extract the mtime from the result of os.FileInfo.Sys(), in a -// platform-specific way. If not supported on this platform, return !ok. -// -// Defined in stat_darwin.go, etc. -func extractMtime(sys interface{}) (mtime time.Time, ok bool) - // Match os.FileInfo values that specify a file birth time equal to the given // time. On platforms where there is no birth time available, match all // os.FileInfo values. From 31da208636506a2ae1af7a3f93d9868c2482179f Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Mon, 16 Mar 2015 12:34:11 +1100 Subject: [PATCH 6/9] Implemented BirthtimeIs for darwin. --- fusetesting/stat.go | 26 +++++++++++++++++++++++++- fusetesting/stat_darwin.go | 6 ++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/fusetesting/stat.go b/fusetesting/stat.go index c1d282c..8077624 100644 --- a/fusetesting/stat.go +++ b/fusetesting/stat.go @@ -58,4 +58,28 @@ func mtimeIs(c interface{}, expected time.Time) error { // Match os.FileInfo values that specify a file birth time equal to the given // time. On platforms where there is no birth time available, match all // os.FileInfo values. -func BirthtimeIs(expected time.Time) oglematchers.Matcher +func BirthtimeIs(expected time.Time) oglematchers.Matcher { + return oglematchers.NewMatcher( + func(c interface{}) error { return birthtimeIs(c, expected) }, + fmt.Sprintf("birthtime is %v", expected)) +} + +func birthtimeIs(c interface{}, expected time.Time) error { + fi, ok := c.(os.FileInfo) + if !ok { + return fmt.Errorf("which is of type %v", reflect.TypeOf(c)) + } + + // Check Sys(). + if sysBirthtime, ok := extractBirthtime(fi.Sys()); ok { + if sysBirthtime != expected { + d := sysBirthtime.Sub(expected) + return fmt.Errorf( + "which has Sys() birthtime %v, off by %v", + sysBirthtime, + d) + } + } + + return nil +} diff --git a/fusetesting/stat_darwin.go b/fusetesting/stat_darwin.go index c8785d5..2b84caf 100644 --- a/fusetesting/stat_darwin.go +++ b/fusetesting/stat_darwin.go @@ -24,3 +24,9 @@ func extractMtime(sys interface{}) (mtime time.Time, ok bool) { ok = true return } + +func extractBirthtime(sys interface{}) (birthtime time.Time, ok bool) { + birthtime = time.Unix(sys.(*syscall.Stat_t).Birthtimespec.Unix()) + ok = true + return +} From e283dcf1bc0043751713e8d7b54bf9ed4c59c3b9 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Mon, 16 Mar 2015 12:38:17 +1100 Subject: [PATCH 7/9] Added an NlinkIs matcher. --- fusetesting/stat.go | 22 ++++++++++++++++++++++ fusetesting/stat_darwin.go | 6 ++++++ 2 files changed, 28 insertions(+) diff --git a/fusetesting/stat.go b/fusetesting/stat.go index 8077624..c084303 100644 --- a/fusetesting/stat.go +++ b/fusetesting/stat.go @@ -83,3 +83,25 @@ func birthtimeIs(c interface{}, expected time.Time) error { return nil } + +// Match os.FileInfo values that specify a number of links equal to the given +// number. On platforms where there is no nlink field available, match all +// os.FileInfo values. +func NlinkIs(expected uint64) oglematchers.Matcher { + return oglematchers.NewMatcher( + func(c interface{}) error { return nlinkIs(c, expected) }, + fmt.Sprintf("nlink is %v", expected)) +} + +func nlinkIs(c interface{}, expected uint64) error { + fi, ok := c.(os.FileInfo) + if !ok { + return fmt.Errorf("which is of type %v", reflect.TypeOf(c)) + } + + if actual, ok := extractNlink(fi.Sys()); ok && actual != expected { + return fmt.Errorf("which has nlink == %v", actual) + } + + return nil +} diff --git a/fusetesting/stat_darwin.go b/fusetesting/stat_darwin.go index 2b84caf..9b4ebf5 100644 --- a/fusetesting/stat_darwin.go +++ b/fusetesting/stat_darwin.go @@ -30,3 +30,9 @@ func extractBirthtime(sys interface{}) (birthtime time.Time, ok bool) { ok = true return } + +func extractNlink(sys interface{}) (nlink uint64, ok bool) { + nlink = uint64(sys.(*syscall.Stat_t).Nlink) + ok = true + return +} From 3b5a04f79d3cb6c96cfb5334450c03dff27344a6 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Mon, 16 Mar 2015 12:42:02 +1100 Subject: [PATCH 8/9] Use the new matchers. --- samples/memfs/memfs_test.go | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/samples/memfs/memfs_test.go b/samples/memfs/memfs_test.go index f73fcee..a1b89f6 100644 --- a/samples/memfs/memfs_test.go +++ b/samples/memfs/memfs_test.go @@ -28,6 +28,7 @@ import ( "time" "github.com/jacobsa/fuse" + "github.com/jacobsa/fuse/fusetesting" "github.com/jacobsa/fuse/samples/memfs" "github.com/jacobsa/gcsfuse/timeutil" . "github.com/jacobsa/oglematchers" @@ -69,10 +70,6 @@ func currentGid() uint32 { return uint32(gid) } -func timespecToTime(ts syscall.Timespec) time.Time { - return time.Unix(ts.Sec, ts.Nsec) -} - //////////////////////////////////////////////////////////////////////// // Boilerplate //////////////////////////////////////////////////////////////////////// @@ -187,7 +184,8 @@ func (t *MemFSTest) Mkdir_OneLevel() { ExpectEq("dir", fi.Name()) ExpectEq(0, fi.Size()) ExpectEq(os.ModeDir|0754, fi.Mode()) - ExpectEq(0, fi.ModTime().Sub(createTime)) + ExpectThat(fi, fusetesting.MtimeIs(createTime)) + ExpectThat(fi, fusetesting.BirthtimeIs(createTime)) ExpectTrue(fi.IsDir()) ExpectNe(0, stat.Ino) @@ -195,8 +193,6 @@ func (t *MemFSTest) Mkdir_OneLevel() { ExpectEq(currentUid(), stat.Uid) ExpectEq(currentGid(), stat.Gid) ExpectEq(0, stat.Size) - ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) - ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Check the root's mtime. fi, err = os.Stat(t.mfs.Dir()) @@ -250,7 +246,8 @@ func (t *MemFSTest) Mkdir_TwoLevels() { ExpectEq("dir", fi.Name()) ExpectEq(0, fi.Size()) ExpectEq(os.ModeDir|0754, fi.Mode()) - ExpectEq(0, fi.ModTime().Sub(createTime)) + ExpectThat(fi, fusetesting.MtimeIs(createTime)) + ExpectThat(fi, fusetesting.BirthtimeIs(createTime)) ExpectTrue(fi.IsDir()) ExpectNe(0, stat.Ino) @@ -258,8 +255,6 @@ func (t *MemFSTest) Mkdir_TwoLevels() { ExpectEq(currentUid(), stat.Uid) ExpectEq(currentGid(), stat.Gid) ExpectEq(0, stat.Size) - ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) - ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Check the parent's mtime. fi, err = os.Stat(path.Join(t.mfs.Dir(), "parent")) @@ -363,7 +358,8 @@ func (t *MemFSTest) CreateNewFile_InRoot() { ExpectEq("foo", fi.Name()) ExpectEq(len(contents), fi.Size()) ExpectEq(0400, fi.Mode()) - ExpectEq(0, fi.ModTime().Sub(createTime)) + ExpectThat(fi, fusetesting.MtimeIs(createTime)) + ExpectThat(fi, fusetesting.BirthtimeIs(createTime)) ExpectFalse(fi.IsDir()) ExpectNe(0, stat.Ino) @@ -371,8 +367,6 @@ func (t *MemFSTest) CreateNewFile_InRoot() { ExpectEq(currentUid(), stat.Uid) ExpectEq(currentGid(), stat.Gid) ExpectEq(len(contents), stat.Size) - ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) - ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Read it back. slice, err := ioutil.ReadFile(fileName) @@ -409,7 +403,8 @@ func (t *MemFSTest) CreateNewFile_InSubDir() { ExpectEq("foo", fi.Name()) ExpectEq(len(contents), fi.Size()) ExpectEq(0400, fi.Mode()) - ExpectEq(0, fi.ModTime().Sub(createTime)) + ExpectThat(fi, fusetesting.MtimeIs(createTime)) + ExpectThat(fi, fusetesting.BirthtimeIs(createTime)) ExpectFalse(fi.IsDir()) ExpectNe(0, stat.Ino) @@ -417,8 +412,6 @@ func (t *MemFSTest) CreateNewFile_InSubDir() { ExpectEq(currentUid(), stat.Uid) ExpectEq(currentGid(), stat.Gid) ExpectEq(len(contents), stat.Size) - ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(createTime)) - ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Read it back. slice, err := ioutil.ReadFile(fileName) @@ -463,7 +456,8 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() { ExpectEq("foo", fi.Name()) ExpectEq(len("Hello, world!"), fi.Size()) ExpectEq(0600, fi.Mode()) - ExpectEq(0, fi.ModTime().Sub(modifyTime)) + ExpectThat(fi, fusetesting.MtimeIs(modifyTime)) + ExpectThat(fi, fusetesting.BirthtimeIs(createTime)) ExpectFalse(fi.IsDir()) ExpectNe(0, stat.Ino) @@ -471,8 +465,6 @@ func (t *MemFSTest) ModifyExistingFile_InRoot() { ExpectEq(currentUid(), stat.Uid) ExpectEq(currentGid(), stat.Gid) ExpectEq(len("Hello, world!"), stat.Size) - ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(modifyTime)) - ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Read the file back. slice, err := ioutil.ReadFile(fileName) @@ -522,7 +514,8 @@ func (t *MemFSTest) ModifyExistingFile_InSubDir() { ExpectEq("foo", fi.Name()) ExpectEq(len("Hello, world!"), fi.Size()) ExpectEq(0600, fi.Mode()) - ExpectEq(0, fi.ModTime().Sub(modifyTime)) + ExpectThat(fi, fusetesting.MtimeIs(modifyTime)) + ExpectThat(fi, fusetesting.BirthtimeIs(createTime)) ExpectFalse(fi.IsDir()) ExpectNe(0, stat.Ino) @@ -530,8 +523,6 @@ func (t *MemFSTest) ModifyExistingFile_InSubDir() { ExpectEq(currentUid(), stat.Uid) ExpectEq(currentGid(), stat.Gid) ExpectEq(len("Hello, world!"), stat.Size) - ExpectEq(0, timespecToTime(stat.Mtimespec).Sub(modifyTime)) - ExpectEq(0, timespecToTime(stat.Birthtimespec).Sub(createTime)) // Read the file back. slice, err := ioutil.ReadFile(fileName) From f47428398e4bcf403700b17d28a46110e13715a6 Mon Sep 17 00:00:00 2001 From: Aaron Jacobs Date: Mon, 16 Mar 2015 12:43:35 +1100 Subject: [PATCH 9/9] Added linux support. --- fusetesting/stat_linux.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 fusetesting/stat_linux.go diff --git a/fusetesting/stat_linux.go b/fusetesting/stat_linux.go new file mode 100644 index 0000000..eec3568 --- /dev/null +++ b/fusetesting/stat_linux.go @@ -0,0 +1,36 @@ +// 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 fusetesting + +import ( + "syscall" + "time" +) + +func extractMtime(sys interface{}) (mtime time.Time, ok bool) { + mtime = time.Unix(sys.(*syscall.Stat_t).Mtim.Unix()) + ok = true + return +} + +func extractBirthtime(sys interface{}) (birthtime time.Time, ok bool) { + return +} + +func extractNlink(sys interface{}) (nlink uint64, ok bool) { + nlink = sys.(*syscall.Stat_t).Nlink + ok = true + return +}