func mountSetupFull()

in integration/utils/exec.go [336:449]


func mountSetupFull(t *testing.T, stdout io.Writer, stderr io.Writer, user *UnixUser, rootSetup func(string) error, args ...string) *MountState {
	t.Helper()

	success := false

	// Reset the test's umask to zero.  This allows tests to not care about how the umask
	// affects files, which can introduce subtle bugs in the tests themselves.
	oldMask := unix.Umask(0)
	defer func() {
		if !success {
			unix.Umask(oldMask)
		}
	}()

	tempDir, err := ioutil.TempDir("", "test")
	if err != nil {
		t.Fatalf("Failed to create temporary directory: %v", err)
	}
	defer func() {
		if !success {
			os.RemoveAll(tempDir)
		}
	}()
	root := filepath.Join(tempDir, "root")
	mountPoint := filepath.Join(tempDir, "mnt")

	MustMkdirAll(t, root, 0755)
	MustMkdirAll(t, mountPoint, 0755)

	if user != nil {
		// Ensure all users can navigate through the temporary directory, which are often created with
		// strict permissions.
		if err := os.Chmod(tempDir, 0755); err != nil {
			t.Fatalf("Failed to change permissions of %s", tempDir)
		}

		// The mount point must be owned by the user that will mount the FUSE file system.
		if err := os.Chown(mountPoint, user.UID, user.GID); err != nil {
			t.Fatalf("Failed to change ownership of %s", mountPoint)
		}
	}

	realArgs := make([]string, 0, len(args)+1)
	for _, arg := range args {
		realArgs = append(realArgs, strings.Replace(arg, "%ROOT%", root, -1))
	}
	realArgs = append(realArgs, mountPoint)

	if err := createDirsRequiredByMappings(root, realArgs...); err != nil {
		t.Fatalf("Failed to create directories required by mappings: %v", err)
	}
	if rootSetup != nil {
		if err := rootSetup(root); err != nil {
			t.Fatalf("Failed to run custom rootSetup hook on %s: %v", root, err)
		}
	}

	var storedStdout *bytes.Buffer
	if stdout == os.Stdout {
		storedStdout = new(bytes.Buffer)
		stdout = storedStdout
	}

	var storedStderr *bytes.Buffer
	if stderr == os.Stderr {
		storedStderr = new(bytes.Buffer)
		stderr = storedStderr
	}

	var cmd *exec.Cmd
	var stdin io.WriteCloser
	if !hasRootMapping(realArgs...) {
		// Without a mapping at root, we can't wait for sandboxfs to come up using a cookie
		// file.  For now, we assume that only the reconfiguration tests do this as they get
		// the same wait functionality by pushing an initial configuration request.
		//
		// TODO(jmmv): We shouldn't need to do this.  Now that there is no more "static" and
		// "dynamic" sandbox types, we could define initial root mappings in all cases and
		// then let the reconfiguration take over.  This is tricky because sandboxfs blocks
		// when opening the input FIFO until there is a writer for it, which is not yet the
		// case for our tests.  And, with the work I'm planning to do on reconfigurations, I
		// may drop the possibility of changing the root mapping.
		cmd, stdin, err = startBackground("", stdout, stderr, user, realArgs...)
	} else {
		MustWriteFile(t, filepath.Join(root, ".cookie"), 0444, "")
		cmd, stdin, err = startBackground(".cookie", stdout, stderr, user, realArgs...)
		if err := os.Remove(filepath.Join(root, ".cookie")); err != nil {
			t.Errorf("Failed to delete the startup cookie file: %v", err)
			// Continue text execution.  Failing hard here is a difficult condition to
			// handle because sandboxfs is already running and we'd need to clean it up.
			// It's easier to just let the test run, and it's actually beneficial to do
			// so: many tests will work even if the removal failed, so the few tests
			// that fail will hint at to what may be wrong.
		}
		if err != nil {
			t.Fatalf("Failed to start sandboxfs: %v", err)
		}
	}

	// All operations that can fail are now done.  Setting success=true prevents any deferred
	// cleanup routines from running, so any code below this line must not be able to fail.
	success = true
	state := &MountState{
		Cmd:        cmd,
		Stdin:      stdin,
		stdout:     storedStdout,
		stderr:     storedStderr,
		tempDir:    tempDir,
		root:       root,
		mountPoint: mountPoint,
		oldMask:    oldMask,
	}
	return state
}