package shell import ( "os" "os/exec" "strings" "testing" "time" ) // 执行正常的命令 func TestExecute_Success(t *testing.T) { res, err := Execute(ExecuteParams{ Cmd: `echo hello`, Timeout: 2, }) if err != nil { t.Fatalf("unexpected error: %v", err) } if res.ExitCode != 0 { t.Fatalf("expected exit code 0, got %d", res.ExitCode) } if strings.TrimSpace(res.Stdout) != "hello" { t.Fatalf("unexpected stdout: %q", res.Stdout) } } // 执行命令不存在 func TestExecute_CommandNotFound(t *testing.T) { _, err := Execute(ExecuteParams{ Cmd: `this_command_should_not_exist_123`, Timeout: 1, }) if err == nil { t.Fatalf("expected error, got nil") } } // 命令非零退出码 func TestExecute_NonZeroExit(t *testing.T) { res, err := Execute(ExecuteParams{ Cmd: `sh -c "exit 42"`, Timeout: 2, }) if err != nil { t.Fatalf("unexpected error: %v", err) } if res.ExitCode != 42 { t.Fatalf("expected exit code 42, got %d", res.ExitCode) } } // 命令超时退出时 func TestExecute_Timeout_KillProcessGroup(t *testing.T) { start := time.Now() res, err := Execute(ExecuteParams{ Cmd: `sh -c "sleep 100 & wait"`, Timeout: 1, }) elapsed := time.Since(start) if elapsed > 5*time.Second { t.Fatalf("Execute hung too long: %v", elapsed) } if res.ExitCode != 124 { t.Fatalf("expected exit code 124, got %d", res.ExitCode) } if err != nil && err != ErrExecutorLostControl { t.Fatalf("unexpected error: %v", err) } } // 命令输出超限时 func TestExecute_OutputLimit(t *testing.T) { res, err := Execute(ExecuteParams{ Cmd: `sh -c "yes | head -c 2097152"`, // 2MB Timeout: 2, }) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(res.Stdout) > 1<<20 { t.Fatalf("stdout exceeded limit: %d", len(res.Stdout)) } } // 测试无孤儿进程 func TestExecute_NoOrphanProcess(t *testing.T) { _, _ = Execute(ExecuteParams{ Cmd: `sh -c "sleep 100 & wait"`, Timeout: 1, }) time.Sleep(300 * time.Millisecond) out, _ := exec.Command("pgrep", "-f", "sleep 100").Output() if len(out) > 0 { t.Fatalf("orphan sleep process detected: %s", out) } } // 执行正常的命令 func TestExecute_Ls(t *testing.T) { res, err := Execute(ExecuteParams{ Cmd: "ls -l", Timeout: 2, }) if err != nil { t.Fatalf("unexpected error: %v", err) } if res.ExitCode != 0 { t.Fatalf("expected exit code 0, got %d", res.ExitCode) } if strings.TrimSpace(res.Stdout) == "" { t.Fatalf("ls stdout should not be empty") } } // 展开"环境变量" func TestExecute_WithEnvExpansion(t *testing.T) { home := os.Getenv("HOME") if home == "" { t.Skip("HOME not set") } res, err := Execute(ExecuteParams{ Cmd: `echo $HOME`, Timeout: 2, }) if err != nil { t.Fatalf("unexpected error: %v", err) } if res.ExitCode != 0 { t.Fatalf("expected exit code 0, got %d", res.ExitCode) } if strings.TrimSpace(res.Stdout) != home { t.Fatalf("unexpected stdout: %q", res.Stdout) } }