detached 8421039

test(daemon): cover invalid terminal dimensions

commit
8421039c00e455e62904f591e666688f0726b9b8
author
brice · · 2026-08-04 06:53 UTC
parent
8f34248
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +37 -26
M internal/usecase/daemon/daemon_test.go +37 -26
@@ -575,32 +575,43 @@ func tabCount(sess *session) int {
575575 // --- handshake --------------------------------------------------------------
576576
577577 func TestRouteRejectsInvalidTerminalSizeBeforeResumeMutation(t *testing.T) {
578- pty, release := newBlockingPTY(t)
579- defer release()
580- d := newTestDaemon(t, newFactory(t, pty), stubClock{})
581-
582- transport := &closeTrackingTransport{}
583- sess, ac, err := d.route(helloResumeCapable(ports.IntentNew, "work", 0), transport)
584- require.NoError(t, err)
585- token := ac.resumeToken
586- d.clientGone(sess, ac, transport, false)
587-
588- d.mu.Lock()
589- parked := d.parked[token]
590- d.mu.Unlock()
591- require.NotNil(t, parked)
592-
593- invalid := helloResumeCapable(ports.IntentResume, "work", token)
594- invalid.Size = domain.Size{Cols: 0, Rows: 24}
595- _, _, err = d.route(invalid, &closeTrackingTransport{})
596- var protocolErr *protoErr
597- require.ErrorAs(t, err, &protocolErr)
598- require.Equal(t, ports.ErrInternal, protocolErr.code)
599-
600- d.mu.Lock()
601- require.Same(t, parked, d.parked[token], "invalid resume must not consume the parked attachment")
602- d.mu.Unlock()
603- require.Same(t, transport, ac.transport(), "invalid resume must not bind a replacement transport")
578+ tests := []struct {
579+ name string
580+ size domain.Size
581+ }{
582+ {name: "zero columns", size: domain.Size{Cols: 0, Rows: 24}},
583+ {name: "zero rows", size: domain.Size{Cols: 80, Rows: 0}},
584+ }
585+ for _, tt := range tests {
586+ t.Run(tt.name, func(t *testing.T) {
587+ pty, release := newBlockingPTY(t)
588+ defer release()
589+ d := newTestDaemon(t, newFactory(t, pty), stubClock{})
590+
591+ transport := &closeTrackingTransport{}
592+ sess, ac, err := d.route(helloResumeCapable(ports.IntentNew, "work", 0), transport)
593+ require.NoError(t, err)
594+ token := ac.resumeToken
595+ d.clientGone(sess, ac, transport, false)
596+
597+ d.mu.Lock()
598+ parked := d.parked[token]
599+ d.mu.Unlock()
600+ require.NotNil(t, parked)
601+
602+ invalid := helloResumeCapable(ports.IntentResume, "work", token)
603+ invalid.Size = tt.size
604+ _, _, err = d.route(invalid, &closeTrackingTransport{})
605+ var protocolErr *protoErr
606+ require.ErrorAs(t, err, &protocolErr)
607+ require.Equal(t, ports.ErrInternal, protocolErr.code)
608+
609+ d.mu.Lock()
610+ require.Same(t, parked, d.parked[token], "invalid resume must not consume the parked attachment")
611+ d.mu.Unlock()
612+ require.Same(t, transport, ac.transport(), "invalid resume must not bind a replacement transport")
613+ })
614+ }
604615 }
605616
606617 func waitGroupDone(wg *sync.WaitGroup) <-chan struct{} {
@@ -575,32 +575,43 @@ func tabCount(sess *session) int {
575 // --- handshake --------------------------------------------------------------575 // --- handshake --------------------------------------------------------------
576 576
577 func TestRouteRejectsInvalidTerminalSizeBeforeResumeMutation(t *testing.T) {577 func TestRouteRejectsInvalidTerminalSizeBeforeResumeMutation(t *testing.T) {
578- pty, release := newBlockingPTY(t)578+ tests := []struct {
579- defer release()579+ name string
580- d := newTestDaemon(t, newFactory(t, pty), stubClock{})580+ size domain.Size
581-581+ }{
582- transport := &closeTrackingTransport{}582+ {name: "zero columns", size: domain.Size{Cols: 0, Rows: 24}},
583- sess, ac, err := d.route(helloResumeCapable(ports.IntentNew, "work", 0), transport)583+ {name: "zero rows", size: domain.Size{Cols: 80, Rows: 0}},
584- require.NoError(t, err)584+ }
585- token := ac.resumeToken585+ for _, tt := range tests {
586- d.clientGone(sess, ac, transport, false)586+ t.Run(tt.name, func(t *testing.T) {
587-587+ pty, release := newBlockingPTY(t)
588- d.mu.Lock()588+ defer release()
589- parked := d.parked[token]589+ d := newTestDaemon(t, newFactory(t, pty), stubClock{})
590- d.mu.Unlock()590+
591- require.NotNil(t, parked)591+ transport := &closeTrackingTransport{}
592-592+ sess, ac, err := d.route(helloResumeCapable(ports.IntentNew, "work", 0), transport)
593- invalid := helloResumeCapable(ports.IntentResume, "work", token)593+ require.NoError(t, err)
594- invalid.Size = domain.Size{Cols: 0, Rows: 24}594+ token := ac.resumeToken
595- _, _, err = d.route(invalid, &closeTrackingTransport{})595+ d.clientGone(sess, ac, transport, false)
596- var protocolErr *protoErr596+
597- require.ErrorAs(t, err, &protocolErr)597+ d.mu.Lock()
598- require.Equal(t, ports.ErrInternal, protocolErr.code)598+ parked := d.parked[token]
599-599+ d.mu.Unlock()
600- d.mu.Lock()600+ require.NotNil(t, parked)
601- require.Same(t, parked, d.parked[token], "invalid resume must not consume the parked attachment")601+
602- d.mu.Unlock()602+ invalid := helloResumeCapable(ports.IntentResume, "work", token)
603- require.Same(t, transport, ac.transport(), "invalid resume must not bind a replacement transport")603+ invalid.Size = tt.size
604+ _, _, err = d.route(invalid, &closeTrackingTransport{})
605+ var protocolErr *protoErr
606+ require.ErrorAs(t, err, &protocolErr)
607+ require.Equal(t, ports.ErrInternal, protocolErr.code)
608+
609+ d.mu.Lock()
610+ require.Same(t, parked, d.parked[token], "invalid resume must not consume the parked attachment")
611+ d.mu.Unlock()
612+ require.Same(t, transport, ac.transport(), "invalid resume must not bind a replacement transport")
613+ })
614+ }
604 }615 }
605 616
606 func waitGroupDone(wg *sync.WaitGroup) <-chan struct{} {617 func waitGroupDone(wg *sync.WaitGroup) <-chan struct{} {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close