restic/internal/fs/node_xattr_all_test.go
Tesshu Flower 7dd18c66aa
restore: xattr restore filter tests
Signed-off-by: Tesshu Flower <tflower@redhat.com>
2024-12-02 19:38:43 -05:00

196 lines
4.9 KiB
Go

//go:build darwin || freebsd || linux || solaris || windows
// +build darwin freebsd linux solaris windows
package fs
import (
"bytes"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"github.com/restic/restic/internal/filter"
"github.com/restic/restic/internal/restic"
rtest "github.com/restic/restic/internal/test"
)
func setAndVerifyXattr(t *testing.T, file string, attrs []restic.ExtendedAttribute) {
if runtime.GOOS == "windows" {
// windows seems to convert the xattr name to upper case
for i := range attrs {
attrs[i].Name = strings.ToUpper(attrs[i].Name)
}
}
node := &restic.Node{
Type: restic.NodeTypeFile,
ExtendedAttributes: attrs,
}
/* restore all xattrs */
rtest.OK(t, nodeRestoreExtendedAttributes(node, file, func(_ string) bool { return true }))
nodeActual := &restic.Node{
Type: restic.NodeTypeFile,
}
rtest.OK(t, nodeFillExtendedAttributes(nodeActual, file, false))
rtest.Assert(t, nodeActual.Equals(*node), "xattr mismatch got %v expected %v", nodeActual.ExtendedAttributes, node.ExtendedAttributes)
}
func setAndVerifyXattrWithSelectFilter(t *testing.T, file string, testAttr []testXattrToRestore, xattrSelectFilter func(_ string) bool) {
attrs := make([]restic.ExtendedAttribute, len(testAttr))
for i := range testAttr {
attrs[i] = testAttr[i].xattr
}
if runtime.GOOS == "windows" {
// windows seems to convert the xattr name to upper case
for i := range attrs {
attrs[i].Name = strings.ToUpper(attrs[i].Name)
}
}
node := &restic.Node{
Type: restic.NodeTypeFile,
ExtendedAttributes: attrs,
}
rtest.OK(t, nodeRestoreExtendedAttributes(node, file, xattrSelectFilter))
nodeActual := &restic.Node{
Type: restic.NodeTypeFile,
}
rtest.OK(t, nodeFillExtendedAttributes(nodeActual, file, false))
// Check nodeActual to make sure only xattrs we expect are there
for _, testAttr := range testAttr {
xattrFound := false
xattrRestored := false
for _, restoredAttr := range nodeActual.ExtendedAttributes {
if restoredAttr.Name == testAttr.xattr.Name {
xattrFound = true
xattrRestored = bytes.Equal(restoredAttr.Value, testAttr.xattr.Value)
break
}
}
if testAttr.shouldRestore {
rtest.Assert(t, xattrFound, "xattr %s not restored", testAttr.xattr.Name)
rtest.Assert(t, xattrRestored, "xattr %v value not restored", testAttr.xattr)
} else {
rtest.Assert(t, !xattrFound, "xattr %v should not have been restored", testAttr.xattr)
}
}
}
type testXattrToRestore struct {
xattr restic.ExtendedAttribute
shouldRestore bool
}
func TestOverwriteXattr(t *testing.T) {
dir := t.TempDir()
file := filepath.Join(dir, "file")
rtest.OK(t, os.WriteFile(file, []byte("hello world"), 0o600))
setAndVerifyXattr(t, file, []restic.ExtendedAttribute{
{
Name: "user.foo",
Value: []byte("bar"),
},
{
Name: "abc.test",
Value: []byte("testxattr"),
},
})
setAndVerifyXattr(t, file, []restic.ExtendedAttribute{
{
Name: "user.other",
Value: []byte("some"),
},
})
}
func TestOverwriteXattrWithSelectFilter(t *testing.T) {
dir := t.TempDir()
file := filepath.Join(dir, "file2")
rtest.OK(t, os.WriteFile(file, []byte("hello world"), 0o600))
noopWarnf := func(_ string, _ ...interface{}) {}
// Set a filter as if the user passed in --include-xattr user.*
xattrSelectFilter1 := func(xattrName string) bool {
shouldInclude, _ := filter.IncludeByPattern([]string{"user.*"}, noopWarnf)(xattrName)
return shouldInclude
}
setAndVerifyXattrWithSelectFilter(t, file, []testXattrToRestore{
{
xattr: restic.ExtendedAttribute{
Name: "user.foo",
Value: []byte("bar"),
},
shouldRestore: true,
},
{
xattr: restic.ExtendedAttribute{
Name: "user.test",
Value: []byte("testxattr"),
},
shouldRestore: true,
},
{
xattr: restic.ExtendedAttribute{
Name: "security.other",
Value: []byte("testing"),
},
shouldRestore: false,
},
}, xattrSelectFilter1)
// Set a filter as if the user passed in --include-xattr user.*
xattrSelectFilter2 := func(xattrName string) bool {
shouldInclude, _ := filter.IncludeByPattern([]string{"user.o*", "user.comm*"}, noopWarnf)(xattrName)
return shouldInclude
}
setAndVerifyXattrWithSelectFilter(t, file, []testXattrToRestore{
{
xattr: restic.ExtendedAttribute{
Name: "user.other",
Value: []byte("some"),
},
shouldRestore: true,
},
{
xattr: restic.ExtendedAttribute{
Name: "security.other",
Value: []byte("testing"),
},
shouldRestore: false,
},
{
xattr: restic.ExtendedAttribute{
Name: "user.open",
Value: []byte("door"),
},
shouldRestore: true,
},
{
xattr: restic.ExtendedAttribute{
Name: "user.common",
Value: []byte("testing"),
},
shouldRestore: true,
},
{
xattr: restic.ExtendedAttribute{
Name: "user.bad",
Value: []byte("dontincludeme"),
},
shouldRestore: false,
},
}, xattrSelectFilter2)
}