124 lines
3.5 KiB
Go
124 lines
3.5 KiB
Go
package process
|
|
|
|
import (
|
|
"os"
|
|
osExec "os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestDefaultShellCommand_CustomShell(t *testing.T) {
|
|
cmd := defaultShellCommand("/bin/sh")
|
|
if cmd[0] != "/bin/sh" {
|
|
t.Errorf("expected preferred shell as first element, got %q", cmd[0])
|
|
}
|
|
}
|
|
|
|
func TestDefaultShellCommand_EmptyPreferred(t *testing.T) {
|
|
cmd := defaultShellCommand("")
|
|
if len(cmd) == 0 {
|
|
t.Fatal("expected non-empty command")
|
|
}
|
|
// On Unix the shell must be invoked WITHOUT -l so /etc/profile doesn't
|
|
// reset PATH (which would drop /data/.npm-global/bin where agent CLIs
|
|
// installed via the Settings → Agents install button live).
|
|
if runtime.GOOS != "windows" {
|
|
for _, a := range cmd[1:] {
|
|
if a == "-l" {
|
|
t.Errorf("expected no -l flag on Unix shell, got %v", cmd)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestDefaultShellCommand_InvalidPreferredFallsBack(t *testing.T) {
|
|
if runtime.GOOS == "windows" {
|
|
t.Skip("unix-only fallback behavior")
|
|
}
|
|
originalShell := os.Getenv("SHELL")
|
|
defer func() { _ = os.Setenv("SHELL", originalShell) }()
|
|
|
|
_ = os.Setenv("SHELL", "/bin/sh")
|
|
cmd := defaultShellCommand("/this/path/does/not/exist")
|
|
if cmd[0] != "/bin/sh" {
|
|
t.Fatalf("expected fallback to SHELL (/bin/sh), got %q", cmd[0])
|
|
}
|
|
}
|
|
|
|
func TestShellExecArgs(t *testing.T) {
|
|
prog, args := shellExecArgs("echo hello")
|
|
if prog == "" {
|
|
t.Fatal("expected non-empty program")
|
|
}
|
|
if len(args) == 0 {
|
|
t.Fatal("expected non-empty args")
|
|
}
|
|
if runtime.GOOS == "windows" {
|
|
if args[len(args)-1] != "echo hello" {
|
|
t.Errorf("expected command string in args, got prog=%q args=%v", prog, args)
|
|
}
|
|
return
|
|
}
|
|
if !strings.Contains(args[len(args)-1], "echo hello") {
|
|
t.Errorf("expected command string in shell wrapper, got prog=%q args=%v", prog, args)
|
|
}
|
|
}
|
|
|
|
func TestShellExecArgsRestoresManagedGitHubPath(t *testing.T) {
|
|
if runtime.GOOS == "windows" {
|
|
t.Skip("Unix shell wrapper only")
|
|
}
|
|
_, args := shellExecArgs("echo hello")
|
|
command := args[len(args)-1]
|
|
for _, want := range []string{
|
|
"KANDEV_GITHUB_CREDENTIAL_BROKER_URL",
|
|
"KANDEV_GITHUB_CLI_SHIM_DIR",
|
|
"PATH=\"${KANDEV_GITHUB_CLI_SHIM_DIR}:${PATH:-}\"",
|
|
"echo hello",
|
|
} {
|
|
if !strings.Contains(command, want) {
|
|
t.Fatalf("shell command missing %q: %s", want, command)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestShellExecArgsRestoresManagedGitHubPathInProcess(t *testing.T) {
|
|
if runtime.GOOS == "windows" {
|
|
t.Skip("Unix shell wrapper only")
|
|
}
|
|
root := t.TempDir()
|
|
shimDir := filepath.Join(root, "managed github shim")
|
|
homeDir := filepath.Join(root, "home")
|
|
if err := os.MkdirAll(shimDir, 0o700); err != nil {
|
|
t.Fatalf("create shim directory: %v", err)
|
|
}
|
|
if err := os.MkdirAll(homeDir, 0o700); err != nil {
|
|
t.Fatalf("create home directory: %v", err)
|
|
}
|
|
marker := filepath.Join(shimDir, "kandev-marker")
|
|
if err := os.WriteFile(marker, []byte("#!/bin/sh\n"), 0o700); err != nil {
|
|
t.Fatalf("write marker executable: %v", err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(homeDir, ".profile"), []byte("PATH=/usr/bin:/bin\nexport PATH\n"), 0o700); err != nil {
|
|
t.Fatalf("write login profile: %v", err)
|
|
}
|
|
|
|
prog, args := shellExecArgs("command -v kandev-marker")
|
|
command := osExec.Command(prog, args...)
|
|
command.Env = []string{
|
|
"HOME=" + homeDir,
|
|
"PATH=" + shimDir + ":/usr/bin:/bin",
|
|
"KANDEV_GITHUB_CREDENTIAL_BROKER_URL=https://kandev.example/resolve",
|
|
"KANDEV_GITHUB_CLI_SHIM_DIR=" + shimDir,
|
|
}
|
|
output, err := command.CombinedOutput()
|
|
if err != nil {
|
|
t.Fatalf("managed shell command failed: %v\n%s", err, output)
|
|
}
|
|
if strings.TrimSpace(string(output)) != marker {
|
|
t.Fatalf("marker resolution = %q, want %q", output, marker)
|
|
}
|
|
}
|