Ctrl K
ComunidadGuías…

utils/keploy_path_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package utils

import (
	"io"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"

	"go.uber.org/zap"
)

// keploy keeps its tests in <path>/keploy, and the binary is called keploy:
// download it into a project and run `./keploy record` there, and the folder
// keploy wants IS the binary. The error has to say which it is, and how to get
// out of it -- without telling anyone to overwrite their installed keploy.
func TestKeployPathThatIsAFileSaysWhatToDo(t *testing.T) {
	dir := t.TempDir()
	file := filepath.Join(dir, "keploy")
	if err := os.WriteFile(file, []byte("an old download, or anything"), 0o600); err != nil {
		t.Fatal(err)
	}
	err := EnsureKeployPathIsFolder(file)
	if err == nil {
		t.Fatal("a file where the keploy folder goes was accepted")
	}
	for _, want := range []string{file, "a file, not a folder", "remove or rename that file", "--path"} {
		if !strings.Contains(err.Error(), want) {
			t.Errorf("the error does not say %q: %v", want, err)
		}
	}
	if strings.Contains(err.Error(), "/usr/local/bin") {
		t.Errorf("a file that is not the running keploy was to be moved into /usr/local/bin, over the installed one: %v", err)
	}
	// The permission check native runs meet next explains it the same way,
	// not with the bare "exists but is not a directory". (A no-op on Windows.)
	if runtime.GOOS != "windows" {
		if _, err := CheckKeployFolderPermissions(zap.NewNop(), file); err == nil || !strings.Contains(err.Error(), "a file, not a folder") {
			t.Errorf("the permission check does not explain a file at the keploy folder's path: %v", err)
		}
	}

	// A folder, or nothing yet, is fine.
	if err := EnsureKeployPathIsFolder(dir); err != nil {
		t.Fatalf("a folder was refused: %v", err)
	}
	if err := EnsureKeployPathIsFolder(filepath.Join(dir, "absent")); err != nil {
		t.Fatalf("a path that does not exist yet was refused: %v", err)
	}

	exe, err := os.Executable()
	if err != nil {
		t.Skip("no executable path on this platform")
	}

	// Another copy of keploy -- an old download, while the installed one runs
	// -- is not the running binary, whatever it looks like: a new file with the
	// same bytes and the exec bit. Only file identity tells them apart, and
	// pointing this one at /usr/local/bin would overwrite the installed keploy.
	other := filepath.Join(t.TempDir(), "keploy")
	copyExecutable(t, exe, other)
	err = EnsureKeployPathIsFolder(other)
	if err == nil || !strings.Contains(err.Error(), "a file, not a folder") || !strings.Contains(err.Error(), "remove or rename that file") {
		t.Errorf("another copy of keploy did not get the advice for a file in the way: %v", err)
	}
	if err != nil && strings.Contains(err.Error(), "/usr/local/bin") {
		t.Errorf("another copy of keploy was to be moved into /usr/local/bin, over the installed one: %v", err)
	}

	// ...and when that file is the running binary, it says so, and to move it.
	self := filepath.Join(t.TempDir(), "keploy")
	if err := os.Symlink(exe, self); err != nil {
		t.Skipf("cannot symlink here: %v", err)
	}
	err = EnsureKeployPathIsFolder(self)
	if err == nil || !strings.Contains(err.Error(), "this keploy binary, not a folder") || !strings.Contains(err.Error(), "move the keploy binary out of this folder") {
		t.Fatalf("the running binary at the keploy folder's path was not named: %v", err)
	}

	// A folder reached through a symlink -- a test store kept elsewhere (shared,
	// or mounted) and linked in -- is a folder. The link itself is not.
	linked := filepath.Join(t.TempDir(), "keploy")
	if err := os.Symlink(dir, linked); err != nil {
		t.Fatalf("symlink: %v", err)
	}
	if err := EnsureKeployPathIsFolder(linked); err != nil {
		t.Fatalf("a symlink to a keploy folder was refused: %v", err)
	}
}

// copyExecutable writes a byte-for-byte copy of src to dst, executable: a new
// file, never a link to src.
func copyExecutable(t *testing.T, src, dst string) {
	t.Helper()
	in, err := os.Open(src)
	if err != nil {
		t.Fatal(err)
	}
	defer in.Close()
	out, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o755)
	if err != nil {
		t.Fatal(err)
	}
	if _, err := io.Copy(out, in); err != nil {
		out.Close()
		t.Fatal(err)
	}
	if err := out.Close(); err != nil {
		t.Fatal(err)
	}
}