v0.9.0 e5e4ded

remote_preview_watch_test.go RawHistoryFolder

1package sessionwire
2
3import (
4	"testing"
5	"time"
6
7	"github.com/stretchr/testify/require"
8	"google.golang.org/protobuf/proto"
9
10	"github.com/bnema/vev/internal/domain"
11	"github.com/bnema/vev/internal/protocol"
12	"github.com/bnema/vev/internal/protocol/wire"
13)
14
15func testRemotePreviewWatch() protocol.RemotePreviewWatch {
16	return protocol.RemotePreviewWatch{
17		Request: protocol.RemotePreviewRequest{
18			Version: protocol.RemotePreviewSchemaVersion,
19			Target: domain.RemoteSessionTarget{
20				Endpoint: "local", DisplayOrigin: "local", LifecycleID: domain.SessionLifecycleID{7},
21				SessionName: "work", LiveTabID: "tab-2",
22			},
23			Width: 80, Height: 24,
24		},
25		MinInterval: 125 * time.Millisecond,
26	}
27}
28
29// TestRemotePreviewWatchByteRoundTrip pins the watch as a client first
30// message: it re-encodes byte-for-byte, rides field 32, and carries its
31// interval as whole milliseconds.
32func TestRemotePreviewWatchByteRoundTrip(t *testing.T) {
33	message := testRemotePreviewWatch()
34	raw, err := EncodeClientMessage(message)
35	require.NoError(t, err)
36	require.NoError(t, wire.ScanEnvelope(&wire.ClientEnvelope{}, raw))
37
38	var envelope wire.ClientEnvelope
39	require.NoError(t, proto.Unmarshal(raw, &envelope))
40	payload, ok := envelope.Payload.(*wire.ClientEnvelope_RemotePreviewWatch)
41	require.True(t, ok, "got %T", envelope.Payload)
42	require.Equal(t, uint32(125), payload.RemotePreviewWatch.GetMinIntervalMs())
43
44	decoded, err := DecodeClientEnvelope(raw)
45	require.NoError(t, err)
46	require.Equal(t, message, decoded)
47	reencoded, err := EncodeClientMessage(decoded)
48	require.NoError(t, err)
49	require.Equal(t, raw, reencoded, "RemotePreviewWatch must re-encode byte-for-byte")
50	require.Equal(t, protocol.DecodeMessageRemotePreview, ClientVariantKindForTest(raw))
51}
52
53func TestRemotePreviewWatchStrictScan(t *testing.T) {
54	valid, err := EncodeClientMessage(testRemotePreviewWatch())
55	require.NoError(t, err)
56	tests := []struct {
57		name string
58		raw  []byte
59	}{
60		{name: "trailing garbage", raw: append(append([]byte(nil), valid...), 0xFF)},
61		{name: "duplicate variant", raw: append(append([]byte(nil), valid...), valid...)},
62	}
63	for cut := 1; cut < len(valid); cut++ {
64		tests = append(tests, struct {
65			name string
66			raw  []byte
67		}{name: "truncated prefix", raw: valid[:cut]})
68	}
69	for _, tt := range tests {
70		t.Run(tt.name, func(t *testing.T) {
71			_, err := DecodeClientEnvelope(tt.raw)
72			require.Error(t, err)
73		})
74	}
75}
76
77func TestRemotePreviewWatchRejectsInvalidValues(t *testing.T) {
78	request, err := EncodeClientMessage(testRemotePreviewWatch())
79	require.NoError(t, err)
80	var envelope wire.ClientEnvelope
81	require.NoError(t, proto.Unmarshal(request, &envelope))
82	valid := envelope.Payload.(*wire.ClientEnvelope_RemotePreviewWatch).RemotePreviewWatch
83
84	tests := []struct {
85		name   string
86		mutate func(*wire.RemotePreviewWatch)
87	}{
88		{name: "zero interval", mutate: func(w *wire.RemotePreviewWatch) { w.MinIntervalMs = 0 }},
89		{name: "interval below bound", mutate: func(w *wire.RemotePreviewWatch) { w.MinIntervalMs = 15 }},
90		{name: "interval above bound", mutate: func(w *wire.RemotePreviewWatch) { w.MinIntervalMs = 1001 }},
91		{name: "oversized interval", mutate: func(w *wire.RemotePreviewWatch) { w.MinIntervalMs = ^uint32(0) }},
92		{name: "missing request", mutate: func(w *wire.RemotePreviewWatch) { w.Request = nil }},
93		{name: "oversized width", mutate: func(w *wire.RemotePreviewWatch) { w.Request.Width = protocol.RemotePreviewMaxWidth + 1 }},
94		{name: "zero height", mutate: func(w *wire.RemotePreviewWatch) { w.Request.Height = 0 }},
95	}
96	for _, tt := range tests {
97		t.Run(tt.name, func(t *testing.T) {
98			message := proto.Clone(valid).(*wire.RemotePreviewWatch)
99			tt.mutate(message)
100			_, err := remotePreviewWatchFromWire(message)
101			require.ErrorIs(t, err, protocol.ErrInvalidRemotePreviewWatch)
102		})
103	}
104
105	encodeTests := []struct {
106		name   string
107		mutate func(*protocol.RemotePreviewWatch)
108	}{
109		{name: "sub-millisecond interval", mutate: func(w *protocol.RemotePreviewWatch) { w.MinInterval += time.Microsecond }},
110		{name: "interval above bound", mutate: func(w *protocol.RemotePreviewWatch) { w.MinInterval = 2 * time.Second }},
111		{name: "stopped target", mutate: func(w *protocol.RemotePreviewWatch) { w.Request.Target.Stopped, w.Request.Target.LiveTabID = true, "" }},
112	}
113	for _, tt := range encodeTests {
114		t.Run("encode "+tt.name, func(t *testing.T) {
115			message := testRemotePreviewWatch()
116			tt.mutate(&message)
117			_, err := EncodeClientMessage(message)
118			require.Error(t, err)
119		})
120	}
121}

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