protection_fence_test.go RawHistoryFolder

1package drm
2
3import (
4	"context"
5	"errors"
6	"os"
7	"testing"
8	"time"
9
10	portsmocks "github.com/bnema/neferwl/internal/mocks/ports"
11	"github.com/bnema/neferwl/internal/ports"
12	"github.com/stretchr/testify/mock"
13)
14
15func TestProtectedModesetWaitsForClearFence(t *testing.T) {
16	o, k, commits, mu := testOutputMu(t)
17	k.EXPECT().createBlob(mock.Anything).Return(99, nil).Once()
18	r := portsmocks.NewMockRenderer(t)
19	f, w := protectionFence(t, false)
20	rendered := make(chan struct{})
21	r.EXPECT().UseTarget(0).Return().Once()
22	r.EXPECT().Render(mock.Anything, mock.Anything).RunAndReturn(func(ports.Scene, map[ports.WindowID]ports.SurfaceContent) (*os.File, error) {
23		close(rendered)
24		return f, nil
25	}).Once()
26	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
27	defer cancel()
28	done := make(chan error, 1)
29	go func() { done <- o.protectedModeset(ctx, r) }()
30	<-rendered
31	// The fence remains unreadable; activation must not be queued behind it.
32	select {
33	case err := <-done:
34		t.Fatalf("returned before clear fence signalled: %v", err)
35	case <-time.After(20 * time.Millisecond):
36	}
37	mu.Lock()
38	n := len(*commits)
39	mu.Unlock()
40	if n != 1 {
41		t.Errorf("committed activation before fence signalled: %d commits", n)
42	}
43	if _, err := w.Write([]byte{1}); err != nil {
44		t.Fatal(err)
45	}
46	if err := <-done; err != nil {
47		t.Fatal(err)
48	}
49	if len(*commits) != 2 || o.back != 1 || o.off {
50		t.Fatal("signalled clear did not activate")
51	}
52}
53
54func TestProtectedModesetPreservesUncommittedGPUReads(t *testing.T) {
55	for _, fail := range []bool{false, true} {
56		t.Run(map[bool]string{false: "success", true: "clear-failure"}[fail], func(t *testing.T) {
57			o, k, _ := testOutput(t)
58			clientFence, _ := protectionFence(t, false)
59			o.holdRead(clientFence)
60			owned := o.readFences[0]
61			r := portsmocks.NewMockRenderer(t)
62			r.EXPECT().UseTarget(0).Return().Once()
63			clearFence, _ := protectionFence(t, true)
64			var renderErr error
65			if fail {
66				renderErr = errors.New("clear failed")
67			} else {
68				k.EXPECT().createBlob(mock.Anything).Return(99, nil).Once()
69			}
70			r.EXPECT().Render(mock.Anything, mock.Anything).Return(clearFence, renderErr).Once()
71			err := o.protectedModeset(context.Background(), r)
72			if (err != nil) != fail {
73				t.Fatalf("clear result: %v", err)
74			}
75			if o.readDone() || len(o.readFences) != 1 || o.readFences[0] != owned {
76				t.Fatal("KMS detachment released an uncommitted GPU read")
77			}
78			if _, err := owned.Stat(); err != nil {
79				t.Fatalf("owned client read fence closed: %v", err)
80			}
81			o.dropRead() // test cleanup only
82		})
83	}
84}
85
86func TestProtectedCloseCommitFailureDoesNotRestoreDesktop(t *testing.T) {
87	o, k, commits := testOutput(t, errors.New("no DRM master"))
88	o.protected = true
89	o.saved = modeCrtc{crtcID: tCrtc, fbID: 123, modeValid: 1, mode: o.mode}
90	k.EXPECT().rmFB(mock.Anything).Return(nil)
91	o.Close()
92	if len(*commits) != 1 || !o.protected {
93		t.Fatal("failed close dropped protection or retried restore")
94	}
95	checkProtectedDisable(t, (*commits)[0], tPrimary, tCursor)
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 25

Tags 10

↑↓ moveenter openesc close