proto_convert_route_hosts_test.go RawHistoryFolder

1package sessionwire
2
3import (
4	"testing"
5
6	"github.com/stretchr/testify/require"
7	"google.golang.org/protobuf/proto"
8
9	"github.com/bnema/vev/internal/domain"
10	"github.com/bnema/vev/internal/protocol"
11	"github.com/bnema/vev/internal/protocol/wire"
12)
13
14func routeHostsTestSnapshot() protocol.RecentRouteSnapshot {
15	target := protocol.ExactSessionTarget{LifecycleID: domain.SessionLifecycleID{7}, SessionName: "work"}
16	return protocol.RecentRouteSnapshot{
17		Generation: 3,
18		Entries: []protocol.RecentRouteEntry{{
19			Key: 1, Generation: 1, Target: target, Name: "work", HostLabel: "box",
20			Kind: protocol.RouteKindRemote, Attention: true, AttentionSeq: 5, Visited: true,
21		}},
22		Hosts: []protocol.RouteHost{
23			{Key: 2, Generation: 1, Label: "a", Kind: protocol.RouteKindRemote},
24			{Key: 3, Generation: 1, Label: "local", Kind: protocol.RouteKindLocal},
25		},
26	}
27}
28
29// TestProtoRouteHostsWire pins the new route snapshot fields byte for byte
30// and checks the envelope rejects a truncated prefix and trailing garbage.
31func TestProtoRouteHostsWire(t *testing.T) {
32	hostBytes, err := proto.Marshal(routeHostToWire(protocol.RouteHost{Key: 2, Generation: 1, Label: "a", Kind: protocol.RouteKindRemote}))
33	require.NoError(t, err)
34	require.Equal(t, []byte{0x08, 0x02, 0x10, 0x01, 0x1A, 0x01, 'a', 0x20, 0x02}, hostBytes)
35	seqBytes, err := proto.Marshal(&wire.RecentRouteEntry{AttentionSeq: 5})
36	require.NoError(t, err)
37	require.Equal(t, []byte{0x50, 0x05}, seqBytes)
38	visitedBytes, err := proto.Marshal(&wire.RecentRouteEntry{Visited: true})
39	require.NoError(t, err)
40	require.Equal(t, []byte{0x58, 0x01}, visitedBytes)
41
42	snapshot := routeHostsTestSnapshot()
43	envelope, err := encodeProtoClient(snapshot)
44	require.NoError(t, err)
45	raw, err := proto.Marshal(envelope)
46	require.NoError(t, err)
47
48	tests := []struct {
49		name    string
50		raw     []byte
51		wantErr bool
52	}{
53		{name: "exact", raw: raw},
54		{name: "truncated prefix", raw: raw[:len(raw)-1], wantErr: true},
55		{name: "trailing garbage", raw: append(append([]byte(nil), raw...), 0xFF), wantErr: true},
56	}
57	for _, tt := range tests {
58		t.Run(tt.name, func(t *testing.T) {
59			err := wire.ScanEnvelope(&wire.ClientEnvelope{}, tt.raw)
60			if tt.wantErr {
61				require.Error(t, err)
62				return
63			}
64			require.NoError(t, err)
65			decoded := &wire.ClientEnvelope{}
66			require.NoError(t, proto.Unmarshal(tt.raw, decoded))
67			got, err := decodeProtoClient(decoded)
68			require.NoError(t, err)
69			require.Equal(t, snapshot, got)
70		})
71	}
72}
73
74func TestProtoRouteHostsRejectInvalid(t *testing.T) {
75	tests := []struct {
76		name   string
77		mutate func(*wire.RecentRouteSnapshot)
78	}{
79		{name: "zero host identity", mutate: func(s *wire.RecentRouteSnapshot) { s.Hosts[0].Key = 0 }},
80		{name: "empty host label", mutate: func(s *wire.RecentRouteSnapshot) { s.Hosts[0].Label = "" }},
81		{name: "unknown host kind", mutate: func(s *wire.RecentRouteSnapshot) { s.Hosts[0].Kind = 9 }},
82		{name: "host collides with entry", mutate: func(s *wire.RecentRouteSnapshot) { s.Hosts[0].Key = 1 }},
83		{name: "duplicate host", mutate: func(s *wire.RecentRouteSnapshot) { s.Hosts[1].Key = s.Hosts[0].Key }},
84		{name: "attention order without attention", mutate: func(s *wire.RecentRouteSnapshot) { s.Entries[0].Attention = false }},
85		{name: "nil host", mutate: func(s *wire.RecentRouteSnapshot) { s.Hosts[0] = nil }},
86	}
87	for _, tt := range tests {
88		t.Run(tt.name, func(t *testing.T) {
89			message, err := recentRouteSnapshotToWire(routeHostsTestSnapshot())
90			require.NoError(t, err)
91			tt.mutate(message)
92			_, err = recentRouteSnapshotFromWire(message)
93			require.Error(t, err)
94		})
95	}
96}

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