@@ -6,6 +6,8 @@ import (
66 "strings"
77 "testing"
88 "time"
9+
10+ "github.com/stretchr/testify/require"
911)
1012
1113func TestBackgroundShellManager_Start(t *testing.T) {
@@ -248,7 +250,7 @@ func TestBackgroundShellManager_KillAll(t *testing.T) {
248250 }
249251
250252 // Kill all shells
251− manager.KillAll()
253+ manager.KillAll(context.Background())
252254
253255 // Verify all shells are done
254256 if !shell1.IsDone() {
@@ -280,3 +282,25 @@ func TestBackgroundShellManager_KillAll(t *testing.T) {
280282 }
281283 }
282284}
285+
286+func TestBackgroundShellManager_KillAll_Timeout(t *testing.T) {
287+ t.Parallel()
288+
289+ workingDir := t.TempDir()
290+ manager := newBackgroundShellManager()
291+
292+ // Start a shell that traps signals and ignores cancellation.
293+ _, err := manager.Start(context.Background(), workingDir, nil, "trap '' TERM INT; sleep 60", "")
294+ require.NoError(t, err)
295+
296+ // Short timeout to test the timeout path.
297+ ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
298+ defer cancel()
299+
300+ start := time.Now()
301+ manager.KillAll(ctx)
302+ elapsed := time.Since(start)
303+
304+ // Must return promptly after timeout, not hang for 60 seconds.
305+ require.Less(t, elapsed, 2*time.Second)
306+}