mirror of
https://github.com/octoleo/restic.git
synced 2024-11-22 21:05:10 +00:00
Merge pull request #2266 from restic/fix-windows-tests
Fix tests on Windows
This commit is contained in:
commit
cf3fc2a5b1
@ -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)
|
||||
}
|
@ -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"
|
||||
@ -556,11 +557,12 @@ func TestFileChanged(t *testing.T) {
|
||||
}
|
||||
|
||||
var tests = []struct {
|
||||
Name string
|
||||
Content []byte
|
||||
Modify func(t testing.TB, filename string)
|
||||
IgnoreInode bool
|
||||
Check bool
|
||||
Name string
|
||||
SkipForWindows bool
|
||||
Content []byte
|
||||
Modify func(t testing.TB, filename string)
|
||||
IgnoreInode bool
|
||||
SameFile bool
|
||||
}{
|
||||
{
|
||||
Name: "same-content-new-file",
|
||||
@ -579,6 +581,10 @@ func TestFileChanged(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Name: "new-content-same-timestamp",
|
||||
// on Windows, there's no "create time" field users cannot modify,
|
||||
// so we're unable to detect if a file has been modified when the
|
||||
// timestamps are reset, so we skip this test for Windows
|
||||
SkipForWindows: true,
|
||||
Modify: func(t testing.TB, filename string) {
|
||||
fi, err := os.Stat(filename)
|
||||
if err != nil {
|
||||
@ -622,12 +628,16 @@ func TestFileChanged(t *testing.T) {
|
||||
setTimestamp(t, filename, fi.ModTime(), fi.ModTime())
|
||||
},
|
||||
IgnoreInode: true,
|
||||
Check: true,
|
||||
SameFile: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.Name, func(t *testing.T) {
|
||||
if runtime.GOOS == "windows" && test.SkipForWindows {
|
||||
t.Skip("don't run test on Windows")
|
||||
}
|
||||
|
||||
tempdir, cleanup := restictest.TempDir(t)
|
||||
defer cleanup()
|
||||
|
||||
@ -648,10 +658,15 @@ func TestFileChanged(t *testing.T) {
|
||||
test.Modify(t, filename)
|
||||
|
||||
fiAfter := lstat(t, filename)
|
||||
if test.Check == fileChanged(fiAfter, node, test.IgnoreInode) {
|
||||
if test.Check {
|
||||
|
||||
if test.SameFile {
|
||||
// file should be detected as unchanged
|
||||
if fileChanged(fiAfter, node, test.IgnoreInode) {
|
||||
t.Fatalf("unmodified file detected as changed")
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
// file should be detected as changed
|
||||
if !fileChanged(fiAfter, node, test.IgnoreInode) && !test.SameFile {
|
||||
t.Fatalf("modified file detected as unchanged")
|
||||
}
|
||||
}
|
||||
@ -2007,16 +2022,77 @@ func (f fileStat) Stat() (os.FileInfo, error) {
|
||||
return f.fi, nil
|
||||
}
|
||||
|
||||
type wrappedFileInfo struct {
|
||||
os.FileInfo
|
||||
sys interface{}
|
||||
mode os.FileMode
|
||||
}
|
||||
// used by wrapFileInfo, use untyped const in order to avoid having a version
|
||||
// of wrapFileInfo for each OS
|
||||
const (
|
||||
mockFileInfoMode = 0400
|
||||
mockFileInfoUID = 51234
|
||||
mockFileInfoGID = 51235
|
||||
)
|
||||
|
||||
func (fi wrappedFileInfo) Sys() interface{} {
|
||||
return fi.sys
|
||||
}
|
||||
func TestMetadataChanged(t *testing.T) {
|
||||
files := TestDir{
|
||||
"testfile": TestFile{
|
||||
Content: "foo bar test file",
|
||||
},
|
||||
}
|
||||
|
||||
func (fi wrappedFileInfo) Mode() os.FileMode {
|
||||
return fi.mode
|
||||
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 by wrapping it in a new struct, uses the consts defined above
|
||||
fs.OverrideLstat["testfile"] = wrapFileInfo(t, fi)
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
41
internal/archiver/archiver_unix_test.go
Normal file
41
internal/archiver/archiver_unix_test.go
Normal file
@ -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) os.FileInfo {
|
||||
// get the underlying stat_t and modify the values
|
||||
stat := fi.Sys().(*syscall.Stat_t)
|
||||
stat.Mode = mockFileInfoMode
|
||||
stat.Uid = mockFileInfoUID
|
||||
stat.Gid = mockFileInfoGID
|
||||
|
||||
// wrap the os.FileInfo so we can return a modified stat_t
|
||||
res := wrappedFileInfo{
|
||||
FileInfo: fi,
|
||||
sys: stat,
|
||||
mode: mockFileInfoMode,
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
28
internal/archiver/archiver_windows_test.go
Normal file
28
internal/archiver/archiver_windows_test.go
Normal file
@ -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) os.FileInfo {
|
||||
// wrap the os.FileInfo and return the modified mode, uid and gid are ignored on Windows
|
||||
res := wrappedFileInfo{
|
||||
FileInfo: fi,
|
||||
mode: mockFileInfoMode,
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
@ -76,5 +76,6 @@ func (s statWin) mtim() syscall.Timespec {
|
||||
}
|
||||
|
||||
func (s statWin) ctim() syscall.Timespec {
|
||||
return syscall.NsecToTimespec(s.CreationTime.Nanoseconds())
|
||||
// Windows does not have the concept of a "change time" in the sense Unix uses it, so we're using the LastWriteTime here.
|
||||
return syscall.NsecToTimespec(s.LastWriteTime.Nanoseconds())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user