v0.8.0 446d1e3

pace_inline_test.go RawHistoryFolder

1package wayland
2
3import (
4	"testing"
5	"time"
6
7	"github.com/bnema/go-wayland-bindings/server/wayland"
8	"github.com/bnema/neferwl/internal/ports"
9)
10
11// paceFixture is a server whose surface waits on an output whose next
12// frame is an hour away: a commit queues its callback and nothing fires.
13func paceFixture(timer bool) (*Server, *surface) {
14	out := &output{place: ports.OutputPlacement{Info: ports.OutputInfo{Name: "DP-2", RefreshMilli: 60000}}}
15	s := &Server{
16		outputs:      []*output{out},
17		awaiting:     map[string][]*wayland.Callback{},
18		frameDue:     map[string]time.Time{"DP-2": time.Now().Add(time.Hour)},
19		fifoSurfaces: map[*surface]struct{}{},
20		lastFlip:     map[string]time.Time{},
21		flips:        map[string]ports.FlipInfo{},
22		reports:      map[string]ports.OutputPresented{},
23		frameReady:   make(chan struct{}, 1),
24	}
25	if timer {
26		s.paceTimer = time.NewTimer(time.Hour)
27		s.paceTimer.Stop()
28	}
29	w := &window{hasLast: true, last: ports.ConfigureWindow{Output: "DP-2", Visible: true}}
30	surf := &surface{server: s, xdg: &xdgSurface{window: w}}
31	surf.next.callbacks = []*wayland.Callback{new(wayland.Callback)}
32	return s, surf
33}
34
35// A commit on the display goroutine ticks the pacer inline: it arms the
36// pacer's timer itself and does not wake the pacer goroutine, which would
37// only call display.Do to get back to the display goroutine.
38func TestCommitTicksPacerInline(t *testing.T) {
39	s, surf := paceFixture(true)
40	surf.queueAndTick()
41	if len(s.awaiting["DP-2"]) != 1 {
42		t.Fatalf("callback not queued: %+v", s.awaiting)
43	}
44	if len(s.frameReady) != 0 {
45		t.Fatal("commit woke the pacer goroutine")
46	}
47	waitArmed(t, s, "inline tick did not arm the pacer timer for the next deadline")
48	if s.paceDepth != 0 || s.paceDirty {
49		t.Fatalf("pace state leaked: depth %d dirty %v", s.paceDepth, s.paceDirty)
50	}
51}
52
53// Without a running pacer (no timer) the wake falls back to the channel.
54func TestCommitWakesPacerWithoutTimer(t *testing.T) {
55	s, surf := paceFixture(false)
56	surf.queueAndTick()
57	if len(s.frameReady) != 1 {
58		t.Fatal("pacer not woken")
59	}
60}
61
62// Wakes inside a tick coalesce into one more pass, not one channel wake each.
63func TestWakePacerDefersInsideTick(t *testing.T) {
64	s, _ := paceFixture(true)
65	s.paceDepth = 1
66	s.wakePacer()
67	s.wakePacer()
68	if len(s.frameReady) != 0 || !s.paceDirty {
69		t.Fatalf("wake inside a tick: queued %d dirty %v", len(s.frameReady), s.paceDirty)
70	}
71	s.paceDepth = 0
72	s.wakePacer()
73	if len(s.frameReady) != 1 {
74		t.Fatal("wake outside a tick lost")
75	}
76}
77
78// A commit that waits (a fifo barrier) is timed by the inline tick.
79func TestCommitWaitingOnBarrierArmsTimer(t *testing.T) {
80	s, surf := paceFixture(true)
81	surf.next.callbacks = nil
82	surf.barrier, surf.barrierAt = true, time.Now()
83	surf.next.wait = true
84	surf.queueAndTick()
85	if len(surf.queue) != 1 || len(s.frameReady) != 0 {
86		t.Fatalf("queued %d, pacer wakes %d", len(surf.queue), len(s.frameReady))
87	}
88	waitArmed(t, s, "timer not armed for the barrier deadline")
89}
90
91// waitArmed asserts the timer was armed: it is pending, or it already
92// fired and holds its value.
93func waitArmed(t *testing.T, s *Server, msg string) {
94	t.Helper()
95	if s.paceTimer.Stop() {
96		return
97	}
98	select {
99	case <-s.paceTimer.C:
100	default:
101		t.Fatal(msg)
102	}
103}
104
105// A synchronized subsurface commit waits for its parent's commit: it does
106// not tick the pacer, so a burst of child commits costs no ticks.
107func TestSyncedCommitDoesNotTick(t *testing.T) {
108	s, surf := paceFixture(true)
109	surf.sub.parent = &surface{server: s}
110	surf.sub.synced = true
111	surf.queueAndTick()
112	if len(surf.queue) != 1 || !surf.queue[0].synced {
113		t.Fatalf("synced commit not queued: %d", len(surf.queue))
114	}
115	if len(s.frameReady) != 0 || s.paceTimer.Stop() {
116		t.Fatal("synced commit ticked the pacer")
117	}
118}

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 23

Tags 10

↑↓ moveenter openesc close