Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix tests on Windows #2266

Merged
merged 5 commits into from May 5, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
98 changes: 0 additions & 98 deletions internal/archiver/archiver_nowin_test.go

This file was deleted.

114 changes: 95 additions & 19 deletions internal/archiver/archiver_test.go
Expand Up @@ -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"
Expand Down Expand Up @@ -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",
Expand All @@ -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 {
Expand Down Expand Up @@ -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()

Expand All @@ -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")
}
}
Expand Down Expand Up @@ -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",
},
}

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))

func (fi wrappedFileInfo) Mode() os.FileMode {
return fi.mode
checker.TestCheckRepo(t, repo)
}
41 changes: 41 additions & 0 deletions 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) 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 changes: 28 additions & 0 deletions 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) 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
}
3 changes: 2 additions & 1 deletion internal/restic/node_windows.go
Expand Up @@ -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())
}