diff --git a/dotnet/test/E2E/RpcShellAndFleetE2ETests.cs b/dotnet/test/E2E/RpcShellAndFleetE2ETests.cs index 1491c88a2..a35e5de41 100644 --- a/dotnet/test/E2E/RpcShellAndFleetE2ETests.cs +++ b/dotnet/test/E2E/RpcShellAndFleetE2ETests.cs @@ -34,7 +34,9 @@ public async Task Should_Kill_Shell_Process() ? "powershell -NoLogo -NoProfile -Command \"Start-Sleep -Seconds 30\"" : "sleep 30"; - var execResult = await session.Rpc.Shell.ExecAsync(command); + // On Windows, terminating the shell wrapper can briefly leave grandchildren alive. + // Keep this command outside the fixture workspace so that cleanup is not blocked by cwd handles. + var execResult = await session.Rpc.Shell.ExecAsync(command, cwd: Path.GetTempPath()); Assert.False(string.IsNullOrWhiteSpace(execResult.ProcessId)); var killResult = await session.Rpc.Shell.KillAsync(execResult.ProcessId); diff --git a/go/internal/e2e/rpc_shell_and_fleet_e2e_test.go b/go/internal/e2e/rpc_shell_and_fleet_e2e_test.go index cfd7f57ba..ff7e545dd 100644 --- a/go/internal/e2e/rpc_shell_and_fleet_e2e_test.go +++ b/go/internal/e2e/rpc_shell_and_fleet_e2e_test.go @@ -63,7 +63,10 @@ func TestRpcShellAndFleetE2E(t *testing.T) { command = "sleep 30" } - exec, err := session.RPC.Shell.Exec(t.Context(), &rpc.ShellExecRequest{Command: command}) + // On Windows, terminating the shell wrapper can briefly leave grandchildren alive. + // Keep this command outside the fixture workspace so cleanup is not blocked by cwd handles. + cwd := os.TempDir() + exec, err := session.RPC.Shell.Exec(t.Context(), &rpc.ShellExecRequest{Command: command, Cwd: &cwd}) if err != nil { t.Fatalf("Failed to call session.shell.exec: %v", err) } diff --git a/nodejs/test/e2e/rpc_shell_and_fleet.e2e.test.ts b/nodejs/test/e2e/rpc_shell_and_fleet.e2e.test.ts index b7868ea3f..ce9bed143 100644 --- a/nodejs/test/e2e/rpc_shell_and_fleet.e2e.test.ts +++ b/nodejs/test/e2e/rpc_shell_and_fleet.e2e.test.ts @@ -85,7 +85,9 @@ describe("Shell and fleet RPC", async () => { ? `powershell -NoLogo -NoProfile -Command "Start-Sleep -Seconds 30"` : "sleep 30"; - const execResult = await session.rpc.shell.exec({ command }); + // On Windows, terminating the shell wrapper can briefly leave grandchildren alive. + // Keep this command outside the fixture workspace so cleanup is not blocked by cwd handles. + const execResult = await session.rpc.shell.exec({ command, cwd: os.tmpdir() }); expect(execResult.processId).toBeTruthy(); const killResult = await session.rpc.shell.kill({ processId: execResult.processId }); diff --git a/python/e2e/test_rpc_shell_and_fleet_e2e.py b/python/e2e/test_rpc_shell_and_fleet_e2e.py index a0d3901f7..c5384825b 100644 --- a/python/e2e/test_rpc_shell_and_fleet_e2e.py +++ b/python/e2e/test_rpc_shell_and_fleet_e2e.py @@ -9,6 +9,7 @@ import asyncio import sys +import tempfile import uuid from pathlib import Path @@ -75,7 +76,11 @@ async def test_should_kill_shell_process(self, ctx: E2ETestContext): else: command = "sleep 30" - exec_result = await session.rpc.shell.exec(ShellExecRequest(command=command)) + # On Windows, terminating the shell wrapper can briefly leave grandchildren alive. + # Keep this command outside the fixture workspace so cleanup is not blocked by cwd handles. + exec_result = await session.rpc.shell.exec( + ShellExecRequest(command=command, cwd=tempfile.gettempdir()) + ) assert (exec_result.process_id or "").strip() kill_result = await session.rpc.shell.kill(