v0.3.0 cf370a0

seat_disable_test.go RawHistoryFolder

1package drm
2
3import (
4	"context"
5	"testing"
6	"time"
7
8	portsmocks "github.com/bnema/neferwl/internal/mocks/ports"
9	"github.com/bnema/neferwl/internal/ports"
10	"github.com/stretchr/testify/mock"
11)
12
13func applyPipelines(o *Output) {
14	for _, p := range []*plane{o.primary, o.overlay} {
15		p.colorKnown, p.colorApplied = true, colorSDRToPQ
16	}
17}
18
19// Before the seat is disabled a plane that applies the pipeline is put back
20// on Bypass, in a blocking commit of the planes alone.
21func TestSeatDisableBypassesAppliedPipeline(t *testing.T) {
22	o, _, commits := colorOutput(t, true, nil)
23	applyPipelines(o)
24	o.bypassForSeatDisable()
25	if len(*commits) != 1 {
26		t.Fatalf("%d commits", len(*commits))
27	}
28	c := (*commits)[0]
29	if c.flags != 0 || c.user != 0 {
30		t.Fatalf("not a blocking commit: flags %#x user %d", c.flags, c.user)
31	}
32	for _, p := range []struct{ plane, prop uint32 }{{tPrimary, pColorPipe}, {tOverlay, pColorPipeOverlay}} {
33		if v, ok := c.req.value(p.plane, p.prop); !ok || v != 0 {
34			t.Errorf("plane %d COLOR_PIPELINE %d %v, want Bypass", p.plane, v, ok)
35		}
36	}
37	if len(c.req.objs) != 2 || o.pipelineApplied() {
38		t.Fatalf("objects %v, applied %v", c.req.objs, o.pipelineApplied())
39	}
40	// Done: a second request has nothing to do.
41	o.bypassForSeatDisable()
42	if len(*commits) != 1 {
43		t.Fatal("commit with Bypass applied")
44	}
45}
46
47// With nothing applied (or nothing known) no commit is made.
48func TestSeatDisableWithoutPipelineDoesNotCommit(t *testing.T) {
49	for name, setup := range map[string]func(*Output){
50		"bypass":  func(o *Output) { o.colorBypassed() },
51		"unknown": func(o *Output) { o.forgetColor() },
52		"no pipeline plane": func(o *Output) {
53			o.primary.props = maps0(planeProps)
54			o.overlay.props = maps0(planeProps)
55		},
56	} {
57		t.Run(name, func(t *testing.T) {
58			o, _, commits := colorOutput(t, true, nil)
59			setup(o)
60			o.bypassForSeatDisable()
61			if len(*commits) != 0 {
62				t.Fatalf("%d commits", len(*commits))
63			}
64		})
65	}
66}
67
68// Run answers the request: the commit is made by the output's goroutine and
69// the caller is acked after it. The output stops drawing until the next enable.
70func TestRunPreparesSeatDisable(t *testing.T) {
71	o, k, commits, mu := testOutputMu(t)
72	o.cursor, o.tearing, o.fbs = nil, false, [2]uint32{}
73	props := maps0(planeProps)
74	props["COLOR_PIPELINE"] = pColorPipe
75	o.primary.props = props
76	o.primary.pipeline = &colorPipeline{}
77	o.primary.colorKnown, o.primary.colorApplied = true, colorSDRToPQ
78	r := portsmocks.NewMockRenderer(t)
79	r.EXPECT().SetHDR(float64(0)).Return().Maybe()
80	r.EXPECT().Close().Return().Once()
81	k.EXPECT().rmFB(mock.Anything).Return(nil).Maybe()
82	k.EXPECT().destroyBlob(mock.Anything).Return(nil).Maybe()
83	active := make(chan bool, 1)
84	active <- false // switched away: no modeset resets the state
85	ctx, cancel := context.WithCancel(context.Background())
86	done := make(chan error, 1)
87	go func() {
88		done <- o.Run(ctx, func(int, int) (ports.Renderer, error) { return r, nil }, nil, active, nil, nil, nil, make(chan ports.OutputPresented, 1), nil, nil)
89	}()
90	if !o.PrepareSeatDisable(5 * time.Second) {
91		t.Fatal("no ack")
92	}
93	mu.Lock()
94	n := len(*commits)
95	var v uint64
96	var ok bool
97	if n > 0 {
98		v, ok = (*commits)[0].req.value(tPrimary, pColorPipe)
99	}
100	mu.Unlock()
101	if n != 1 || !ok || v != 0 {
102		t.Fatalf("commits %d, COLOR_PIPELINE %d %v", n, v, ok)
103	}
104	cancel()
105	if err := <-done; err != nil {
106		t.Fatal(err)
107	}
108}
109
110// An output that is not running cannot answer: the caller is not held.
111func TestPrepareSeatDisableTimesOut(t *testing.T) {
112	o, _, _ := testOutput(t)
113	if o.PrepareSeatDisable(5 * time.Millisecond) {
114		t.Fatal("acked without a running output")
115	}
116}

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 25

Tags 10

↑↓ moveenter openesc close