after_frame_test.go RawHistoryFolder

1package daemon
2
3import (
4	"testing"
5	"time"
6
7	"github.com/stretchr/testify/require"
8)
9
10func TestAfterFrameQueueReleasesOnlyAfterALaterCapture(t *testing.T) {
11	tests := []struct {
12		name    string
13		steps   []string // "add:<id>", "capture", "emit:<n>"
14		wantRan []string
15	}{
16		{name: "nothing emitted", steps: []string{"add:a", "capture"}},
17		{name: "capture started before registration", steps: []string{"capture", "add:a", "capture", "emit:1"}},
18		{name: "capture started after registration", steps: []string{"capture", "add:a", "capture", "emit:2"}, wantRan: []string{"a"}},
19		{name: "unnumbered emission", steps: []string{"add:a", "capture", "emit:0"}},
20		{name: "partial release keeps later work", steps: []string{"add:a", "capture", "add:b", "capture", "emit:1"}, wantRan: []string{"a"}},
21		{name: "later emission releases the rest", steps: []string{"add:a", "capture", "add:b", "capture", "emit:1", "emit:2"}, wantRan: []string{"a", "b"}},
22	}
23	for _, tt := range tests {
24		t.Run(tt.name, func(t *testing.T) {
25			var q afterFrameQueue
26			ran := make(chan string, len(tt.steps))
27			for _, step := range tt.steps {
28				switch {
29				case step == "capture":
30					q.beginCapture()
31				case step[:4] == "add:":
32					id := step[4:]
33					q.add(func() { ran <- id })
34				case step[:5] == "emit:":
35					q.emitted(uint64(step[5] - '0'))
36				}
37			}
38			q.runReady()
39			q.runReady()
40			var got []string
41			for range tt.wantRan {
42				got = append(got, awaitTestValue(t, ran, "released work did not run"))
43			}
44			require.ElementsMatch(t, tt.wantRan, got)
45			select {
46			case extra := <-ran:
47				t.Fatalf("unexpected work %q ran", extra)
48			case <-time.After(50 * time.Millisecond):
49			}
50		})
51	}
52}
53
54// Work registered through afterNextFrame runs once a later capture is emitted
55// on the same attachment, and is dropped once the attachment reconnected.
56func TestAfterNextFrameRunsOrDropsByCapability(t *testing.T) {
57	tests := []struct {
58		name      string
59		reconnect bool
60		freeze    bool
61		wantRun   bool
62	}{
63		{name: "same attachment runs", wantRun: true},
64		{name: "reconnected attachment drops", reconnect: true},
65		{name: "transient freeze delays until thaw", freeze: true, wantRun: true},
66	}
67	for _, tt := range tests {
68		t.Run(tt.name, func(t *testing.T) {
69			d, source, ac, _, _, releases, _ := setupMovePickerSessionsCore(t, stubClock{}, 0)
70			defer releaseAll(releases)
71			effect, admitted := ac.beginAttachmentEffect(captureAttachmentCapability(source, ac, ac.transport()))
72			require.True(t, admitted)
73			ran := make(chan struct{}, 1)
74			d.queueAfterNextFrame(ac, effect, func(*attachmentEffect) { ran <- struct{}{} })
75			effect.End()
76			if tt.reconnect {
77				ac.replaceTransport(ac.transport())
78				ac.installTestAttachmentCapability(captureAttachmentCapability(source, ac, ac.transport()))
79			}
80			var frozen attachmentTransitionGuard
81			if tt.freeze {
82				frozen = freezeAttachmentEffectGates(ac)
83				require.True(t, frozen.acquired)
84			}
85			ac.afterFrame.emitted(ac.afterFrame.beginCapture())
86			ac.afterFrame.runReady()
87			if tt.freeze {
88				// Released while frozen: it waits, with no further paint needed.
89				select {
90				case <-ran:
91					t.Fatal("work ran while the attachment was frozen")
92				case <-time.After(50 * time.Millisecond):
93				}
94				frozen.unfreeze()
95			}
96			if tt.wantRun {
97				awaitTestValue(t, ran, "queued work did not run after the frame")
98				return
99			}
100			select {
101			case <-ran:
102				t.Fatal("work ran for a reconnected attachment")
103			case <-time.After(100 * time.Millisecond):
104			}
105		})
106	}
107}

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