wings/internal/ufs/fs_unix_test.go

256 lines
5.9 KiB
Go
Raw Normal View History

// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: Copyright (c) 2024 Matthew Penner
//go:build unix
package ufs_test
import (
"errors"
"os"
"path/filepath"
"testing"
"github.com/pterodactyl/wings/internal/ufs"
)
type testUnixFS struct {
*ufs.UnixFS
TmpDir string
Root string
}
func (fs *testUnixFS) Cleanup() {
_ = fs.Close()
_ = os.RemoveAll(fs.TmpDir)
}
func newTestUnixFS() (*testUnixFS, error) {
tmpDir, err := os.MkdirTemp(os.TempDir(), "ufs")
if err != nil {
return nil, err
}
root := filepath.Join(tmpDir, "root")
if err := os.Mkdir(root, 0o755); err != nil {
return nil, err
}
// TODO: test both disabled and enabled.
fs, err := ufs.NewUnixFS(root, false)
if err != nil {
return nil, err
}
tfs := &testUnixFS{
UnixFS: fs,
TmpDir: tmpDir,
Root: root,
}
return tfs, nil
}
func TestUnixFS_Remove(t *testing.T) {
t.Parallel()
fs, err := newTestUnixFS()
if err != nil {
t.Fatal(err)
return
}
defer fs.Cleanup()
t.Run("base directory", func(t *testing.T) {
// Try to remove the base directory.
if err := fs.Remove(""); !errors.Is(err, ufs.ErrBadPathResolution) {
t.Errorf("expected an a bad path resolution error, but got: %v", err)
return
}
})
t.Run("path traversal", func(t *testing.T) {
// Try to remove the base directory.
if err := fs.RemoveAll("../root"); !errors.Is(err, ufs.ErrBadPathResolution) {
t.Errorf("expected an a bad path resolution error, but got: %v", err)
return
}
})
}
func TestUnixFS_RemoveAll(t *testing.T) {
t.Parallel()
fs, err := newTestUnixFS()
if err != nil {
t.Fatal(err)
return
}
defer fs.Cleanup()
t.Run("base directory", func(t *testing.T) {
// Try to remove the base directory.
if err := fs.RemoveAll(""); !errors.Is(err, ufs.ErrBadPathResolution) {
t.Errorf("expected an a bad path resolution error, but got: %v", err)
return
}
})
t.Run("path traversal", func(t *testing.T) {
// Try to remove the base directory.
if err := fs.RemoveAll("../root"); !errors.Is(err, ufs.ErrBadPathResolution) {
t.Errorf("expected an a bad path resolution error, but got: %v", err)
return
}
})
}
func TestUnixFS_Rename(t *testing.T) {
t.Parallel()
fs, err := newTestUnixFS()
if err != nil {
t.Fatal(err)
return
}
defer fs.Cleanup()
t.Run("rename base directory", func(t *testing.T) {
// Try to rename the base directory.
if err := fs.Rename("", "yeet"); !errors.Is(err, ufs.ErrBadPathResolution) {
t.Errorf("expected an a bad path resolution error, but got: %v", err)
return
}
})
t.Run("rename over base directory", func(t *testing.T) {
// Create a directory that we are going to try and move over top of the
// existing base directory.
if err := fs.Mkdir("overwrite_dir", 0o755); err != nil {
t.Error(err)
return
}
// Try to rename over the base directory.
if err := fs.Rename("overwrite_dir", ""); !errors.Is(err, ufs.ErrBadPathResolution) {
t.Errorf("expected an a bad path resolution error, but got: %v", err)
return
}
})
t.Run("directory rename", func(t *testing.T) {
// Create a directory to rename to something else.
if err := fs.Mkdir("test_directory", 0o755); err != nil {
t.Error(err)
return
}
// Try to rename "test_directory" to "directory".
if err := fs.Rename("test_directory", "directory"); err != nil {
t.Errorf("expected no error, but got: %v", err)
return
}
// Sanity check
if _, err := os.Lstat(filepath.Join(fs.Root, "directory")); err != nil {
t.Errorf("Lstat errored when performing sanity check: %v", err)
return
}
})
t.Run("file rename", func(t *testing.T) {
// Create a directory to rename to something else.
if f, err := fs.Create("test_file"); err != nil {
t.Error(err)
return
} else {
_ = f.Close()
}
// Try to rename "test_file" to "file".
if err := fs.Rename("test_file", "file"); err != nil {
t.Errorf("expected no error, but got: %v", err)
return
}
// Sanity check
if _, err := os.Lstat(filepath.Join(fs.Root, "file")); err != nil {
t.Errorf("Lstat errored when performing sanity check: %v", err)
return
}
})
}
func TestUnixFS_Touch(t *testing.T) {
t.Parallel()
fs, err := newTestUnixFS()
if err != nil {
t.Fatal(err)
return
}
defer fs.Cleanup()
t.Run("base directory", func(t *testing.T) {
path := "i_touched_a_file"
f, err := fs.Touch(path, ufs.O_RDWR, 0o644)
if err != nil {
t.Error(err)
return
}
_ = f.Close()
// Sanity check
if _, err := os.Lstat(filepath.Join(fs.Root, path)); err != nil {
t.Errorf("Lstat errored when performing sanity check: %v", err)
return
}
})
t.Run("existing parent directory", func(t *testing.T) {
dir := "some_parent_directory"
if err := fs.Mkdir(dir, 0o755); err != nil {
t.Errorf("error creating parent directory: %v", err)
return
}
path := filepath.Join(dir, "i_touched_a_file")
f, err := fs.Touch(path, ufs.O_RDWR, 0o644)
if err != nil {
t.Errorf("error touching file: %v", err)
return
}
_ = f.Close()
// Sanity check
if _, err := os.Lstat(filepath.Join(fs.Root, path)); err != nil {
t.Errorf("Lstat errored when performing sanity check: %v", err)
return
}
})
t.Run("non-existent parent directory", func(t *testing.T) {
path := "some_other_directory/i_touched_a_file"
f, err := fs.Touch(path, ufs.O_RDWR, 0o644)
if err != nil {
t.Errorf("error touching file: %v", err)
return
}
_ = f.Close()
// Sanity check
if _, err := os.Lstat(filepath.Join(fs.Root, path)); err != nil {
t.Errorf("Lstat errored when performing sanity check: %v", err)
return
}
})
t.Run("non-existent parent directories", func(t *testing.T) {
path := "some_other_directory/some_directory/i_touched_a_file"
f, err := fs.Touch(path, ufs.O_RDWR, 0o644)
if err != nil {
t.Errorf("error touching file: %v", err)
return
}
_ = f.Close()
// Sanity check
if _, err := os.Lstat(filepath.Join(fs.Root, path)); err != nil {
t.Errorf("Lstat errored when performing sanity check: %v", err)
return
}
})
}