attention_route_test.go RawHistoryFolder

1package daemon
2
3import (
4	"testing"
5
6	"github.com/stretchr/testify/require"
7
8	"github.com/bnema/vev/internal/domain"
9	"github.com/bnema/vev/internal/protocol"
10)
11
12func attentionRouteEntry(key uint64, name string, marker byte, seq uint64) protocol.RecentRouteEntry {
13	entry := testRouteEntry(key, 1, name, marker, protocol.RouteKindRemote)
14	entry.HostLabel = "box"
15	entry.Attention = seq != 0
16	entry.AttentionSeq = seq
17	return entry
18}
19
20// TestOldestRouteAttention pins the cross-daemon half of jump-to-attention
21// (Plan 003 C5): the oldest client-observed bell wins, and a lifecycle this
22// daemon owns is never delegated to the client.
23func TestOldestRouteAttention(t *testing.T) {
24	owned := testRouteTarget("mine", 9).LifecycleID
25	tests := []struct {
26		name    string
27		entries []protocol.RecentRouteEntry
28		wantKey uint64
29		wantOK  bool
30	}{
31		{name: "no bells", entries: []protocol.RecentRouteEntry{attentionRouteEntry(1, "a", 1, 0)}},
32		{
33			name:    "oldest onset wins over recency",
34			entries: []protocol.RecentRouteEntry{attentionRouteEntry(1, "new", 1, 7), attentionRouteEntry(2, "old", 2, 3), attentionRouteEntry(3, "quiet", 3, 0)},
35			wantKey: 2, wantOK: true,
36		},
37		{
38			name:    "this daemon's own lifecycle is skipped",
39			entries: []protocol.RecentRouteEntry{attentionRouteEntry(1, "mine", 9, 1), attentionRouteEntry(2, "theirs", 2, 4)},
40			wantKey: 2, wantOK: true,
41		},
42	}
43	for _, tt := range tests {
44		t.Run(tt.name, func(t *testing.T) {
45			snapshot := protocol.RecentRouteSnapshot{Generation: 5, Entries: tt.entries}
46			require.NoError(t, snapshot.Validate())
47			action, ok := oldestRouteAttention(snapshot, func(lifecycle domain.SessionLifecycleID) bool { return lifecycle == owned })
48			require.Equal(t, tt.wantOK, ok)
49			if tt.wantOK {
50				require.Equal(t, protocol.RouteNavigationAction{SnapshotGeneration: 5, Key: tt.wantKey, Generation: 1}, action)
51			}
52		})
53	}
54}
55
56// TestJumpAttentionDelegatesOtherDaemonsToTheClient drives the real jump:
57// with no bell on this daemon, the oldest route bell becomes a client
58// navigation request on the attachment.
59func TestJumpAttentionDelegatesOtherDaemonsToTheClient(t *testing.T) {
60	d, source, ac, _ := newManualSessionWithPTYs(t, nil)
61	transport := &closeTrackingTransport{}
62	ac.replaceTransport(transport)
63	rc := d.attachCoordinator(source, nil, ac, true)
64	token := source.captureAttachmentCapability(ac, transport)
65	token.lease = rc.attachmentLease(ac)
66	ac.installTestAttachmentCapability(token)
67	effect, admitted := ac.beginAttachmentEffect(token)
68	require.True(t, admitted)
69	defer effect.End()
70	ac.setRouteSnapshot(protocol.RecentRouteSnapshot{
71		Generation: 6,
72		Entries:    []protocol.RecentRouteEntry{attentionRouteEntry(4, "later", 4, 9), attentionRouteEntry(5, "first", 5, 2)},
73	})
74
75	require.NoError(t, d.jumpAttentionForAttachment(source, ac, effect))
76
77	var actions []protocol.RouteNavigationAction
78	for _, frame := range transport.Sends() {
79		if action, ok := decodeServerMessage(t, frame).(protocol.RouteNavigationAction); ok {
80			actions = append(actions, action)
81		}
82	}
83	require.Equal(t, []protocol.RouteNavigationAction{{SnapshotGeneration: 6, Key: 5, Generation: 1}}, actions)
84	require.Same(t, source, ac.currentSession(), "the client navigates; the daemon never switches")
85}

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