Skip to content

Commit 7fc8ee4

Browse files
authored
test(cli/cliui): add test for context cancellation during log streaming (#21125)
Verifies that streamLogs properly returns ctx.Err() when the context is cancelled while waiting for logs. This covers the case where a user interrupts an SSH connection (e.g., Ctrl+C) during startup script execution. Refs #21104
1 parent d351821 commit 7fc8ee4

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

cli/cliui/agent_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,70 @@ func TestAgent(t *testing.T) {
566566
}
567567
require.NoError(t, cmd.Invoke().Run())
568568
})
569+
570+
t.Run("ContextCancelDuringLogStreaming", func(t *testing.T) {
571+
t.Parallel()
572+
573+
ctx, cancel := context.WithCancel(context.Background())
574+
defer cancel()
575+
576+
agent := codersdk.WorkspaceAgent{
577+
ID: uuid.New(),
578+
Status: codersdk.WorkspaceAgentConnected,
579+
FirstConnectedAt: ptr.Ref(time.Now()),
580+
CreatedAt: time.Now(),
581+
LifecycleState: codersdk.WorkspaceAgentLifecycleStarting,
582+
StartedAt: ptr.Ref(time.Now()),
583+
}
584+
585+
logs := make(chan []codersdk.WorkspaceAgentLog, 1)
586+
logStreamStarted := make(chan struct{})
587+
588+
cmd := &serpent.Command{
589+
Handler: func(inv *serpent.Invocation) error {
590+
return cliui.Agent(inv.Context(), io.Discard, agent.ID, cliui.AgentOptions{
591+
FetchInterval: time.Millisecond,
592+
Wait: true,
593+
Fetch: func(_ context.Context, _ uuid.UUID) (codersdk.WorkspaceAgent, error) {
594+
return agent, nil
595+
},
596+
FetchLogs: func(_ context.Context, _ uuid.UUID, _ int64, follow bool) (<-chan []codersdk.WorkspaceAgentLog, io.Closer, error) {
597+
// Signal that log streaming has started.
598+
select {
599+
case <-logStreamStarted:
600+
default:
601+
close(logStreamStarted)
602+
}
603+
return logs, closeFunc(func() error { return nil }), nil
604+
},
605+
})
606+
},
607+
}
608+
609+
inv := cmd.Invoke().WithContext(ctx)
610+
done := make(chan error, 1)
611+
go func() {
612+
done <- inv.Run()
613+
}()
614+
615+
// Wait for log streaming to start.
616+
select {
617+
case <-logStreamStarted:
618+
case <-time.After(testutil.WaitShort):
619+
t.Fatal("timed out waiting for log streaming to start")
620+
}
621+
622+
// Cancel the context while streaming logs.
623+
cancel()
624+
625+
// Verify that the agent function returns with a context error.
626+
select {
627+
case err := <-done:
628+
require.ErrorIs(t, err, context.Canceled)
629+
case <-time.After(testutil.WaitShort):
630+
t.Fatal("timed out waiting for agent to return after context cancellation")
631+
}
632+
})
569633
}
570634

571635
func TestPeerDiagnostics(t *testing.T) {

0 commit comments

Comments
 (0)