mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
62 lines
1.4 KiB
Go
62 lines
1.4 KiB
Go
//go:build !windows
|
|
|
|
package tools
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
"strings"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func processExists(pid int) bool {
|
|
if pid <= 0 {
|
|
return false
|
|
}
|
|
err := syscall.Kill(pid, 0)
|
|
return err == nil || err == syscall.EPERM
|
|
}
|
|
|
|
func TestShellTool_TimeoutKillsChildProcess(t *testing.T) {
|
|
tool := NewExecTool(t.TempDir(), false)
|
|
tool.SetTimeout(500 * time.Millisecond)
|
|
|
|
args := map[string]interface{}{
|
|
// Spawn a child process that would outlive the shell unless process-group kill is used.
|
|
"command": "sleep 60 & echo $! > child.pid; wait",
|
|
}
|
|
|
|
result := tool.Execute(context.Background(), args)
|
|
if !result.IsError {
|
|
t.Fatalf("expected timeout error, got success: %s", result.ForLLM)
|
|
}
|
|
if !strings.Contains(result.ForLLM, "timed out") {
|
|
t.Fatalf("expected timeout message, got: %s", result.ForLLM)
|
|
}
|
|
|
|
childPIDPath := filepath.Join(tool.workingDir, "child.pid")
|
|
data, err := os.ReadFile(childPIDPath)
|
|
if err != nil {
|
|
t.Fatalf("failed to read child pid file: %v", err)
|
|
}
|
|
|
|
childPID, err := strconv.Atoi(strings.TrimSpace(string(data)))
|
|
if err != nil {
|
|
t.Fatalf("failed to parse child pid: %v", err)
|
|
}
|
|
|
|
deadline := time.Now().Add(2 * time.Second)
|
|
for time.Now().Before(deadline) {
|
|
if !processExists(childPID) {
|
|
return
|
|
}
|
|
time.Sleep(50 * time.Millisecond)
|
|
}
|
|
|
|
t.Fatalf("child process %d is still running after timeout", childPID)
|
|
}
|