package integration
import (
"os"
"path/filepath"
"reflect"
"syscall"
"testing"
"github.com/bazelbuild/sandboxfs/integration/utils"
)
func TestNesting_ScaffoldIntermediateComponents(t *testing.T) {
state := utils.MountSetup(t, "--mapping=ro:/:%ROOT%", "--mapping=ro:/1/2/3/4/5:%ROOT%/subdir")
defer state.TearDown(t)
utils.MustWriteFile(t, state.RootPath("subdir", "file"), 0644, "some contents")
if err := utils.DirEquals(state.RootPath("subdir"), state.MountPath("1/2/3/4/5")); err != nil {
t.Error(err)
}
if err := utils.FileEquals(state.MountPath("1/2/3/4/5", "file"), "some contents"); err != nil {
t.Error(err)
}
utils.MustMkdirAll(t, state.TempPath("golden/1/2/3/4/5"), 0755)
for _, dir := range []string{"1/2/3/4", "1/2/3", "1/2", "1"} {
goldenDir := state.TempPath("golden", dir)
if err := os.Chmod(goldenDir, 0555); err != nil {
t.Errorf("Failed to set golden dir permissions to 0555 to match scaffold dir expectations: %v", err)
}
defer os.Chmod(goldenDir, 0755)
scaffoldDir := state.MountPath(dir)
if err := utils.DirEquals(goldenDir, scaffoldDir); err != nil {
t.Error(err)
}
}
}
func TestNesting_ScaffoldIntermediateComponentsAreImmutable(t *testing.T) {
root := utils.RequireRoot(t, "Requires root privileges to write to directories with mode 0555")
state := utils.MountSetupWithUser(t, root, "--mapping=ro:/:%ROOT%", "--mapping=rw:/1/2/3:%ROOT%/subdir")
defer state.TearDown(t)
for _, dir := range []string{"1/foo", "1/2/foo"} {
err := os.Mkdir(state.MountPath(dir), 0755)
pathErr, ok := err.(*os.PathError)
if !ok || pathErr.Err != syscall.EPERM {
t.Errorf("Want Mkdir to fail inside scaffold directory %s with %v; got %v (%v)", dir, syscall.EPERM, err, reflect.TypeOf(err))
}
}
if err := os.Mkdir(state.MountPath("1/2/3/foo"), 0755); err != nil {
t.Errorf("Want Mkdir to succeed inside non-scaffold directory; got %v", err)
}
}
func TestNesting_ReadWriteWithinReadOnly(t *testing.T) {
state := utils.MountSetup(t, "--mapping=rw:/:%ROOT%", "--mapping=ro:/ro:%ROOT%/one/two", "--mapping=rw:/ro/rw:%ROOT%")
defer state.TearDown(t)
if err := os.MkdirAll(state.MountPath("ro/hello"), 0755); err == nil {
t.Errorf("Mkdir succeeded in read-only mapping")
}
if err := os.MkdirAll(state.MountPath("ro/rw/hello"), 0755); err != nil {
t.Errorf("Mkdir failed in read-write mapping: %v", err)
}
}
func TestNesting_SameTarget(t *testing.T) {
state := utils.MountSetup(t, "--node_cache", "--mapping=ro:/:%ROOT%", "--mapping=rw:/dir1:%ROOT%/same", "--mapping=rw:/dir2/dir3/dir4:%ROOT%/same")
defer state.TearDown(t)
utils.MustWriteFile(t, state.MountPath("dir1/file"), 0644, "old contents")
utils.MustWriteFile(t, state.MountPath("dir2/dir3/dir4/file"), 0644, "new contents")
externalDir := state.RootPath("same")
if err := utils.FileEquals(filepath.Join(externalDir, "file"), "new contents"); err != nil {
t.Error(err)
}
for _, dir := range []string{"/dir1", "/dir2/dir3/dir4"} {
internalDir := state.MountPath(dir)
if err := utils.DirEquals(externalDir, internalDir); err != nil {
t.Error(err)
}
}
if err := utils.FileEquals(state.MountPath("dir1/file"), "new contents"); err != nil {
t.Error(err)
}
if err := utils.FileEquals(state.MountPath("dir2/dir3/dir4/file"), "new contents"); err != nil {
t.Error(err)
}
}
func TestNesting_PreserveSymlinks(t *testing.T) {
state := utils.MountSetup(t, "--mapping=ro:/:%ROOT%", "--mapping=ro:/dir1/dir2:%ROOT%")
defer state.TearDown(t)
utils.MustWriteFile(t, state.RootPath("file"), 0644, "file in root directory")
utils.MustMkdirAll(t, state.RootPath("dir"), 0755)
if err := os.Symlink("..", state.RootPath("dir/up")); err != nil {
t.Fatalf("Failed to create test symlink: %v", err)
}
if err := utils.FileEquals(state.MountPath("dir/up/file"), "file in root directory"); err != nil {
t.Error(err)
}
if err := utils.FileEquals(state.MountPath("dir1/dir2/dir/up/file"), "file in root directory"); err != nil {
t.Error(err)
}
}