"io/fs"
"math/rand"
"os"
- "os/user"
"path/filepath"
"reflect"
"regexp"
- "strconv"
- "syscall"
"testing"
"github.com/google/go-cmp/cmp"
"ruderich.org/simon/safcm"
+ ft "ruderich.org/simon/safcm/cmd/safcm-remote/sync/filetest"
)
-type File struct {
- Path string
- Mode fs.FileMode
- Data []byte
-}
-
-func walkDir(basePath string) ([]File, error) {
- var res []File
- err := filepath.WalkDir(basePath, func(path string, d fs.DirEntry, err error) error {
- if err != nil {
- return err
- }
- info, err := d.Info()
- if err != nil {
- return err
- }
- rel, err := filepath.Rel(basePath, path)
- if err != nil {
- return err
- }
-
- f := File{
- Path: rel,
- Mode: info.Mode(),
- }
- if f.Mode.Type() == 0 {
- x, err := os.ReadFile(path)
- if err != nil {
- return err
- }
- f.Data = x
- } else if f.Mode.Type() == fs.ModeSymlink {
- x, err := os.Readlink(path)
- if err != nil {
- return err
- }
- f.Data = []byte(x)
- }
- res = append(res, f)
- return nil
- })
- if err != nil {
- return nil, err
- }
- return res, nil
-}
-
var randFilesRegexp = regexp.MustCompile(`\d+"$`)
func TestSyncFiles(t *testing.T) {
t.Fatal(err)
}
- root := File{
+ root := ft.File{
Path: ".",
Mode: fs.ModeDir | 0700,
}
- user, uid, group, gid := currentUserAndGroup()
+ user, uid, group, gid := ft.CurrentUserAndGroup()
tmpTestFilePath := "/tmp/safcm-sync-files-test-file"
req safcm.MsgSyncReq
prepare func()
triggers []string
- expFiles []File
+ expFiles []ft.File
expResp safcm.MsgSyncResp
expDbg []string
expErr error
},
nil,
nil,
- []File{
+ []ft.File{
root,
{
Path: "dir",
},
},
func() {
- createDirectory("dir", 0755)
- createFile("dir/file", "content\n", 0644)
+ ft.CreateDirectory("dir", 0755)
+ ft.CreateFile("dir/file", "content\n", 0644)
},
nil,
- []File{
+ []ft.File{
root,
{
Path: "dir",
},
nil,
nil,
- []File{
+ []ft.File{
root,
},
safcm.MsgSyncResp{},
},
nil,
nil,
- []File{
+ []ft.File{
root,
},
safcm.MsgSyncResp{},
},
nil,
nil,
- []File{
+ []ft.File{
root,
},
safcm.MsgSyncResp{},
},
},
func() {
- createDirectory("dir", 0755)
- createFile("dir/file", "content\n", 0644)
+ ft.CreateDirectory("dir", 0755)
+ ft.CreateFile("dir/file", "content\n", 0644)
},
nil,
- []File{
+ []ft.File{
root,
{
Path: "dir",
if err != nil {
panic(err)
}
- createDirectory("dir", 0755)
- createFile("dir/file", "content\n", 0644)
+ ft.CreateDirectory("dir", 0755)
+ ft.CreateFile("dir/file", "content\n", 0644)
},
[]string{
".",
},
- []File{
+ []ft.File{
root,
{
Path: "dir",
},
},
func() {
- createDirectory("dir", 0750)
- createFile("dir/file", "content\n", 0644)
+ ft.CreateDirectory("dir", 0750)
+ ft.CreateFile("dir/file", "content\n", 0644)
},
[]string{
".",
"dir",
},
- []File{
+ []ft.File{
root,
{
Path: "dir",
},
},
func() {
- createDirectory("dir", 0755)
+ ft.CreateDirectory("dir", 0755)
},
[]string{
".",
"dir",
"dir/file",
},
- []File{
+ []ft.File{
root,
{
Path: "dir",
"dir",
"dir/file",
},
- []File{
+ []ft.File{
root,
{
Path: "dir",
// Don't use variable for more robust test
"/tmp/safcm-sync-files-test-file",
},
- []File{
+ []ft.File{
root,
},
safcm.MsgSyncResp{
cmp.Diff(tc.expDbg, dbg))
}
- files, err := walkDir(path)
+ files, err := ft.WalkDir(path)
if err != nil {
t.Fatal(err)
}
t.Fatal(err)
}
- root := File{
+ root := ft.File{
Path: ".",
Mode: fs.ModeDir | 0700,
}
- user, uid, group, gid := currentUserAndGroup()
+ user, uid, group, gid := ft.CurrentUserAndGroup()
tests := []struct {
name string
file *safcm.File
prepare func()
expChanged bool
- expFiles []File
+ expFiles []ft.File
expResp safcm.MsgSyncResp
expDbg []string
expErr error
},
nil,
true,
- []File{
+ []ft.File{
root,
{
Path: "file",
},
nil,
true,
- []File{root},
+ []ft.File{root},
safcm.MsgSyncResp{
FileChanges: []safcm.FileChange{
{
OrigGroup: "group",
},
func() {
- createFile("file", "content\n", 0644)
+ ft.CreateFile("file", "content\n", 0644)
},
false,
- []File{
+ []ft.File{
root,
{
Path: "file",
OrigGroup: "group",
},
func() {
- createFile("file", "content\n", 0644)
+ ft.CreateFile("file", "content\n", 0644)
},
false,
- []File{
+ []ft.File{
root,
{
Path: "file",
OrigGroup: "group",
},
func() {
- createFile("file", "content\n", 0755)
+ ft.CreateFile("file", "content\n", 0755)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "file",
OrigGroup: "group",
},
func() {
- createFile("file", "old content\n", 0644)
+ ft.CreateFile("file", "old content\n", 0644)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "file",
},
nil,
true,
- []File{
+ []ft.File{
root,
{
Path: "link",
OrigGroup: "group",
},
func() {
- createFile(".link8717895732742165505", "", 0600)
+ ft.CreateFile(".link8717895732742165505", "", 0600)
},
true,
- []File{
+ []ft.File{
root,
{
Path: ".link8717895732742165505",
},
nil,
true,
- []File{root},
+ []ft.File{root},
safcm.MsgSyncResp{
FileChanges: []safcm.FileChange{
{
OrigGroup: "group",
},
func() {
- createSymlink("link", "target")
+ ft.CreateSymlink("link", "target")
},
false,
- []File{
+ []ft.File{
root,
{
Path: "link",
OrigGroup: "group",
},
func() {
- createSymlink("link", "old-target")
+ ft.CreateSymlink("link", "old-target")
},
true,
- []File{
+ []ft.File{
root,
{
Path: "link",
},
nil,
true,
- []File{
+ []ft.File{
root,
{
Path: "dir",
},
nil,
true,
- []File{root},
+ []ft.File{root},
safcm.MsgSyncResp{
FileChanges: []safcm.FileChange{
{
OrigGroup: "group",
},
func() {
- createDirectory("dir", 0755)
+ ft.CreateDirectory("dir", 0755)
},
false,
- []File{
+ []ft.File{
root,
{
Path: "dir",
OrigGroup: "group",
},
func() {
- createDirectory("dir", 0500|fs.ModeSticky)
+ ft.CreateDirectory("dir", 0500|fs.ModeSticky)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "dir",
OrigGroup: "group",
},
func() {
- createFile("path", "content\n", 0644)
+ ft.CreateFile("path", "content\n", 0644)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "path",
Data: []byte("target"),
},
func() {
- createFile("path", "content\n", 0644)
+ ft.CreateFile("path", "content\n", 0644)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "path",
Data: []byte("content\n"),
},
func() {
- createSymlink("path", "target")
+ ft.CreateSymlink("path", "target")
},
true,
- []File{
+ []ft.File{
root,
{
Path: "path",
OrigGroup: "group",
},
func() {
- createSymlink("path", "target")
+ ft.CreateSymlink("path", "target")
},
true,
- []File{
+ []ft.File{
root,
{
Path: "path",
Data: []byte("content\n"),
},
func() {
- createDirectory("path", 0777)
+ ft.CreateDirectory("path", 0777)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "path",
Data: []byte("target"),
},
func() {
- createDirectory("path", 0777)
+ ft.CreateDirectory("path", 0777)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "path",
Data: []byte("content\n"),
},
func() {
- createFifo("path", 0666)
+ ft.CreateFifo("path", 0666)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "path",
Data: []byte("target"),
},
func() {
- createFifo("path", 0666)
+ ft.CreateFifo("path", 0666)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "path",
OrigGroup: "group",
},
func() {
- createFifo("path", 0666)
+ ft.CreateFifo("path", 0666)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "path",
Data: []byte("target"),
},
func() {
- createFile("path", "target", 0644)
+ ft.CreateFile("path", "target", 0644)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "path",
OrigGroup: "group",
},
func() {
- createFile("file", `this
+ ft.CreateFile("file", `this
is
file
!
`, 0644)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "file",
OrigGroup: "group",
},
func() {
- createFile("file", "\x00\x01\x02", 0644)
+ ft.CreateFile("file", "\x00\x01\x02", 0644)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "file",
OrigGroup: "group",
},
func() {
- createFile("file", "\x00\x01\x02", 0644)
+ ft.CreateFile("file", "\x00\x01\x02", 0644)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "file",
OrigGroup: "group",
},
func() {
- createFile("file", "content\n", 0644)
+ ft.CreateFile("file", "content\n", 0644)
},
true,
- []File{
+ []ft.File{
root,
{
Path: "file",
cmp.Diff(tc.expDbg, dbg))
}
- files, err := walkDir(path)
+ files, err := ft.WalkDir(path)
if err != nil {
t.Fatal(err)
}
}
}
}
-
-// Helper functions
-
-func createFile(path string, data string, mode fs.FileMode) {
- err := os.WriteFile(path, []byte(data), 0644)
- if err != nil {
- panic(err)
- }
- err = os.Chmod(path, mode)
- if err != nil {
- panic(err)
- }
-}
-func createSymlink(path string, data string) {
- err := os.Symlink(data, path)
- if err != nil {
- panic(err)
- }
-}
-func createDirectory(path string, mode fs.FileMode) {
- err := os.Mkdir(path, 0700)
- if err != nil {
- panic(err)
- }
- err = os.Chmod(path, mode)
- if err != nil {
- panic(err)
- }
-}
-func createFifo(path string, mode fs.FileMode) {
- err := syscall.Mkfifo(path, 0600)
- if err != nil {
- panic(err)
- }
- err = os.Chmod(path, mode)
- if err != nil {
- panic(err)
- }
-}
-
-func currentUserAndGroup() (string, int, string, int) {
- u, err := user.Current()
- if err != nil {
- panic(err)
- }
- g, err := user.LookupGroupId(u.Gid)
- if err != nil {
- panic(err)
- }
- uid, err := strconv.Atoi(u.Uid)
- if err != nil {
- panic(err)
- }
- gid, err := strconv.Atoi(g.Gid)
- if err != nil {
- panic(err)
- }
- return u.Username, uid, g.Name, gid
-}
--- /dev/null
+// Utility functions useful for file-related tests
+
+// Copyright (C) 2021 Simon Ruderich
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+package filetest
+
+import (
+ "io/fs"
+ "os"
+ "os/user"
+ "path/filepath"
+ "strconv"
+ "syscall"
+)
+
+type File struct {
+ Path string
+ Mode fs.FileMode
+ Data []byte
+}
+
+func WalkDir(basePath string) ([]File, error) {
+ var res []File
+ err := filepath.WalkDir(basePath, func(path string, d fs.DirEntry, err error) error {
+ if err != nil {
+ return err
+ }
+ info, err := d.Info()
+ if err != nil {
+ return err
+ }
+ rel, err := filepath.Rel(basePath, path)
+ if err != nil {
+ return err
+ }
+
+ f := File{
+ Path: rel,
+ Mode: info.Mode(),
+ }
+ if f.Mode.Type() == 0 {
+ x, err := os.ReadFile(path)
+ if err != nil {
+ return err
+ }
+ f.Data = x
+ } else if f.Mode.Type() == fs.ModeSymlink {
+ x, err := os.Readlink(path)
+ if err != nil {
+ return err
+ }
+ f.Data = []byte(x)
+ }
+ res = append(res, f)
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ return res, nil
+}
+
+func CurrentUserAndGroup() (string, int, string, int) {
+ u, err := user.Current()
+ if err != nil {
+ panic(err)
+ }
+ g, err := user.LookupGroupId(u.Gid)
+ if err != nil {
+ panic(err)
+ }
+ uid, err := strconv.Atoi(u.Uid)
+ if err != nil {
+ panic(err)
+ }
+ gid, err := strconv.Atoi(g.Gid)
+ if err != nil {
+ panic(err)
+ }
+ return u.Username, uid, g.Name, gid
+}
+
+func CreateFile(path string, data string, mode fs.FileMode) {
+ err := os.WriteFile(path, []byte(data), 0644)
+ if err != nil {
+ panic(err)
+ }
+ err = os.Chmod(path, mode)
+ if err != nil {
+ panic(err)
+ }
+}
+
+func CreateSymlink(path string, data string) {
+ err := os.Symlink(data, path)
+ if err != nil {
+ panic(err)
+ }
+}
+
+func CreateDirectory(path string, mode fs.FileMode) {
+ err := os.Mkdir(path, 0700)
+ if err != nil {
+ panic(err)
+ }
+ err = os.Chmod(path, mode)
+ if err != nil {
+ panic(err)
+ }
+}
+
+func CreateFifo(path string, mode fs.FileMode) {
+ err := syscall.Mkfifo(path, 0600)
+ if err != nil {
+ panic(err)
+ }
+ err = os.Chmod(path, mode)
+ if err != nil {
+ panic(err)
+ }
+}