diff --git a/internal/archiver/archiver_nowin_test.go b/internal/archiver/archiver_nowin_test.go deleted file mode 100644 index a4d6432dc..000000000 --- a/internal/archiver/archiver_nowin_test.go +++ /dev/null @@ -1,98 +0,0 @@ -// +build !windows - -package archiver - -import ( - "context" - "os" - "syscall" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/restic/restic/internal/checker" - "github.com/restic/restic/internal/fs" - "github.com/restic/restic/internal/restic" -) - -func TestMetadataChanged(t *testing.T) { - files := TestDir{ - "testfile": TestFile{ - Content: "foo bar test file", - }, - } - - tempdir, repo, cleanup := prepareTempdirRepoSrc(t, files) - defer cleanup() - - back := fs.TestChdir(t, tempdir) - defer back() - - // get metadata - fi := lstat(t, "testfile") - want, err := restic.NodeFromFileInfo("testfile", fi) - if err != nil { - t.Fatal(err) - } - - fs := &StatFS{ - FS: fs.Local{}, - OverrideLstat: map[string]os.FileInfo{ - "testfile": fi, - }, - } - - snapshotID, node2 := snapshot(t, repo, fs, restic.ID{}, "testfile") - - // set some values so we can then compare the nodes - want.Content = node2.Content - want.Path = "" - want.ExtendedAttributes = nil - - // make sure that metadata was recorded successfully - if !cmp.Equal(want, node2) { - t.Fatalf("metadata does not match:\n%v", cmp.Diff(want, node2)) - } - - // modify the mode - stat, ok := fi.Sys().(*syscall.Stat_t) - if ok { - // change a few values - stat.Mode = 0400 - stat.Uid = 1234 - stat.Gid = 1235 - - // wrap the os.FileInfo so we can return a modified stat_t - fi = wrappedFileInfo{ - FileInfo: fi, - sys: stat, - mode: 0400, - } - fs.OverrideLstat["testfile"] = fi - } else { - // skip the test on this platform - t.Skipf("unable to modify os.FileInfo, Sys() returned %T", fi.Sys()) - } - - want, err = restic.NodeFromFileInfo("testfile", fi) - if err != nil { - t.Fatal(err) - } - - // make another snapshot - snapshotID, node3 := snapshot(t, repo, fs, snapshotID, "testfile") - - // set some values so we can then compare the nodes - want.Content = node2.Content - want.Path = "" - want.ExtendedAttributes = nil - - // make sure that metadata was recorded successfully - if !cmp.Equal(want, node3) { - t.Fatalf("metadata does not match:\n%v", cmp.Diff(want, node2)) - } - - // make sure the content matches - TestEnsureFileContent(context.Background(), t, repo, "testfile", node3, files["testfile"].(TestFile)) - - checker.TestCheckRepo(t, repo) -} diff --git a/internal/archiver/archiver_test.go b/internal/archiver/archiver_test.go index aff4f10f3..531978812 100644 --- a/internal/archiver/archiver_test.go +++ b/internal/archiver/archiver_test.go @@ -14,6 +14,7 @@ import ( "testing" "time" + "github.com/google/go-cmp/cmp" "github.com/restic/restic/internal/checker" "github.com/restic/restic/internal/errors" "github.com/restic/restic/internal/fs" @@ -2012,16 +2013,69 @@ func (f fileStat) Stat() (os.FileInfo, error) { return f.fi, nil } -type wrappedFileInfo struct { - os.FileInfo - sys interface{} - mode os.FileMode -} +func TestMetadataChanged(t *testing.T) { + files := TestDir{ + "testfile": TestFile{ + Content: "foo bar test file", + }, + } -func (fi wrappedFileInfo) Sys() interface{} { - return fi.sys -} + tempdir, repo, cleanup := prepareTempdirRepoSrc(t, files) + defer cleanup() -func (fi wrappedFileInfo) Mode() os.FileMode { - return fi.mode + back := fs.TestChdir(t, tempdir) + defer back() + + // get metadata + fi := lstat(t, "testfile") + want, err := restic.NodeFromFileInfo("testfile", fi) + if err != nil { + t.Fatal(err) + } + + fs := &StatFS{ + FS: fs.Local{}, + OverrideLstat: map[string]os.FileInfo{ + "testfile": fi, + }, + } + + snapshotID, node2 := snapshot(t, repo, fs, restic.ID{}, "testfile") + + // set some values so we can then compare the nodes + want.Content = node2.Content + want.Path = "" + want.ExtendedAttributes = nil + + // make sure that metadata was recorded successfully + if !cmp.Equal(want, node2) { + t.Fatalf("metadata does not match:\n%v", cmp.Diff(want, node2)) + } + + // modify the mode by wrapping it in a new struct + fs.OverrideLstat["testfile"] = wrapFileInfo(t, fi, 0400, 51234, 51235) + + // set the override values in the 'want' node which + want.Mode = 0400 + // ignore UID and GID on Windows + if runtime.GOOS != "windows" { + want.UID = 51234 + want.GID = 51235 + } + // no user and group name + want.User = "" + want.Group = "" + + // make another snapshot + snapshotID, node3 := snapshot(t, repo, fs, snapshotID, "testfile") + + // make sure that metadata was recorded successfully + if !cmp.Equal(want, node3) { + t.Fatalf("metadata does not match:\n%v", cmp.Diff(want, node3)) + } + + // make sure the content matches + TestEnsureFileContent(context.Background(), t, repo, "testfile", node3, files["testfile"].(TestFile)) + + checker.TestCheckRepo(t, repo) } diff --git a/internal/archiver/archiver_unix_test.go b/internal/archiver/archiver_unix_test.go new file mode 100644 index 000000000..4af972577 --- /dev/null +++ b/internal/archiver/archiver_unix_test.go @@ -0,0 +1,41 @@ +// +build !windows + +package archiver + +import ( + "os" + "syscall" + "testing" +) + +type wrappedFileInfo struct { + os.FileInfo + sys interface{} + mode os.FileMode +} + +func (fi wrappedFileInfo) Sys() interface{} { + return fi.sys +} + +func (fi wrappedFileInfo) Mode() os.FileMode { + return fi.mode +} + +// wrapFileInfo returns a new os.FileInfo with the mode, owner, and group fields changed. +func wrapFileInfo(t testing.TB, fi os.FileInfo, mode os.FileMode, uid, gid uint) os.FileInfo { + // get the underlying stat_t and modify the values + stat := fi.Sys().(*syscall.Stat_t) + stat.Mode = uint32(mode) + stat.Uid = uint32(uid) + stat.Gid = uint32(gid) + + // wrap the os.FileInfo so we can return a modified stat_t + res := wrappedFileInfo{ + FileInfo: fi, + sys: stat, + mode: mode, + } + + return res +} diff --git a/internal/archiver/archiver_windows_test.go b/internal/archiver/archiver_windows_test.go new file mode 100644 index 000000000..6a0100f49 --- /dev/null +++ b/internal/archiver/archiver_windows_test.go @@ -0,0 +1,28 @@ +// +build windows + +package archiver + +import ( + "os" + "testing" +) + +type wrappedFileInfo struct { + os.FileInfo + mode os.FileMode +} + +func (fi wrappedFileInfo) Mode() os.FileMode { + return fi.mode +} + +// wrapFileInfo returns a new os.FileInfo with the mode, owner, and group fields changed. +func wrapFileInfo(t testing.TB, fi os.FileInfo, mode os.FileMode, uid, gid uint) os.FileInfo { + // wrap the os.FileInfo and return the modified mode, uid and gid are ignored on Windows + res := wrappedFileInfo{ + FileInfo: fi, + mode: mode, + } + + return res +}