Skip to content

Commit 6463e41

Browse files
committed
chore: add workspace bash background tests
1 parent d10a605 commit 6463e41

File tree

1 file changed

+143
-0
lines changed

1 file changed

+143
-0
lines changed

codersdk/toolsdk/bash_test.go

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/coder/coder/v2/agent/agenttest"
1010
"github.com/coder/coder/v2/coderd/coderdtest"
1111
"github.com/coder/coder/v2/codersdk/toolsdk"
12+
"github.com/coder/coder/v2/testutil"
1213
)
1314

1415
func TestWorkspaceBash(t *testing.T) {
@@ -338,3 +339,145 @@ func TestWorkspaceBashTimeoutIntegration(t *testing.T) {
338339
require.NotContains(t, result.Output, "Command canceled due to timeout")
339340
})
340341
}
342+
343+
func TestWorkspaceBashBackgroundIntegration(t *testing.T) {
344+
t.Parallel()
345+
346+
t.Run("BackgroundCommandReturnsImmediately", func(t *testing.T) {
347+
t.Parallel()
348+
349+
client, workspace, agentToken := setupWorkspaceForAgent(t)
350+
351+
// Start the agent and wait for it to be fully ready
352+
_ = agenttest.New(t, client.URL, agentToken)
353+
354+
// Wait for workspace agents to be ready
355+
coderdtest.NewWorkspaceAgentWaiter(t, client, workspace.ID).Wait()
356+
357+
deps, err := toolsdk.NewDeps(client)
358+
require.NoError(t, err)
359+
360+
args := toolsdk.WorkspaceBashArgs{
361+
Workspace: workspace.Name,
362+
Command: `echo "started" && sleep 5 && echo "completed"`, // Command that would take 5+ seconds
363+
Background: true, // Run in background
364+
}
365+
366+
result, err := toolsdk.WorkspaceBash.Handler(t.Context(), deps, args)
367+
368+
// Should not error
369+
require.NoError(t, err)
370+
371+
t.Logf("Background result: exitCode=%d, output=%q", result.ExitCode, result.Output)
372+
373+
// Should have exit code 0 (background start successful)
374+
require.Equal(t, 0, result.ExitCode)
375+
376+
// Should contain PID and log path info, not the actual command output
377+
require.Contains(t, result.Output, "Command started with PID:")
378+
require.Contains(t, result.Output, "Log path: /tmp/mcp-bg/")
379+
380+
// Should NOT contain the actual command output since it runs in background
381+
// The command was `echo "started" && sleep 5 && echo "completed"`
382+
// So we check that the quoted strings don't appear in the output
383+
require.NotContains(t, result.Output, `"started"`, "Should not contain command output in background mode")
384+
require.NotContains(t, result.Output, `"completed"`, "Should not contain command output in background mode")
385+
})
386+
387+
t.Run("BackgroundVsNormalExecution", func(t *testing.T) {
388+
t.Parallel()
389+
390+
client, workspace, agentToken := setupWorkspaceForAgent(t)
391+
392+
// Start the agent and wait for it to be fully ready
393+
_ = agenttest.New(t, client.URL, agentToken)
394+
395+
// Wait for workspace agents to be ready
396+
coderdtest.NewWorkspaceAgentWaiter(t, client, workspace.ID).Wait()
397+
398+
deps, err := toolsdk.NewDeps(client)
399+
require.NoError(t, err)
400+
401+
// First run the same command in normal mode
402+
normalArgs := toolsdk.WorkspaceBashArgs{
403+
Workspace: workspace.Name,
404+
Command: `echo "hello world"`,
405+
Background: false,
406+
}
407+
408+
normalResult, err := toolsdk.WorkspaceBash.Handler(t.Context(), deps, normalArgs)
409+
require.NoError(t, err)
410+
411+
// Normal mode should return the actual output
412+
require.Equal(t, 0, normalResult.ExitCode)
413+
require.Equal(t, "hello world", normalResult.Output)
414+
415+
// Now run the same command in background mode
416+
backgroundArgs := toolsdk.WorkspaceBashArgs{
417+
Workspace: workspace.Name,
418+
Command: `echo "hello world"`,
419+
Background: true,
420+
}
421+
422+
backgroundResult, err := toolsdk.WorkspaceBash.Handler(t.Context(), deps, backgroundArgs)
423+
require.NoError(t, err)
424+
425+
t.Logf("Normal result: %q", normalResult.Output)
426+
t.Logf("Background result: %q", backgroundResult.Output)
427+
428+
// Background mode should return PID/log info, not the actual output
429+
require.Equal(t, 0, backgroundResult.ExitCode)
430+
require.Contains(t, backgroundResult.Output, "Command started with PID:")
431+
require.Contains(t, backgroundResult.Output, "Log path: /tmp/mcp-bg/")
432+
require.NotContains(t, backgroundResult.Output, "hello world")
433+
})
434+
435+
t.Run("BackgroundIgnoresTimeout", func(t *testing.T) {
436+
t.Parallel()
437+
438+
client, workspace, agentToken := setupWorkspaceForAgent(t)
439+
440+
// Start the agent and wait for it to be fully ready
441+
_ = agenttest.New(t, client.URL, agentToken)
442+
443+
// Wait for workspace agents to be ready
444+
coderdtest.NewWorkspaceAgentWaiter(t, client, workspace.ID).Wait()
445+
446+
deps, err := toolsdk.NewDeps(client)
447+
require.NoError(t, err)
448+
449+
args := toolsdk.WorkspaceBashArgs{
450+
Workspace: workspace.Name,
451+
Command: `sleep 1 && echo "done" > /tmp/done`, // Command that would normally timeout
452+
TimeoutMs: 1, // 1 ms timeout (shorter than command duration)
453+
Background: true, // But running in background should ignore timeout
454+
}
455+
456+
result, err := toolsdk.WorkspaceBash.Handler(t.Context(), deps, args)
457+
458+
// Should not error and should not timeout
459+
require.NoError(t, err)
460+
461+
t.Logf("Background with timeout result: exitCode=%d, output=%q", result.ExitCode, result.Output)
462+
463+
// Should have exit code 0 (background start successful)
464+
require.Equal(t, 0, result.ExitCode)
465+
466+
// Should return PID/log info, indicating the background command started successfully
467+
require.Contains(t, result.Output, "Command started with PID:")
468+
require.Contains(t, result.Output, "Log path: /tmp/mcp-bg/")
469+
470+
// Should NOT contain timeout message since background mode ignores timeout
471+
require.NotContains(t, result.Output, "Command canceled due to timeout")
472+
473+
// Wait for the background command to complete
474+
require.Eventually(t, func() bool {
475+
args := toolsdk.WorkspaceBashArgs{
476+
Workspace: workspace.Name,
477+
Command: `cat /tmp/done`,
478+
}
479+
result, err := toolsdk.WorkspaceBash.Handler(t.Context(), deps, args)
480+
return err == nil && result.Output == "done"
481+
}, testutil.WaitMedium, testutil.IntervalMedium)
482+
})
483+
}

0 commit comments

Comments
 (0)