browser_launch_prepare_test.go RawHistoryFolder

1package desktop
2
3import (
4	"context"
5	"net"
6	"os"
7	"path/filepath"
8	"testing"
9	"time"
10
11	"github.com/bnema/dumber/internal/application/port"
12	"github.com/stretchr/testify/require"
13)
14
15type prepareTestCloser struct{}
16
17func (*prepareTestCloser) Close() error { return nil }
18
19func TestBrowserLaunchRelayPrepareReservesUntilListen(t *testing.T) {
20	ipc := testIPC(shortTempDir(t))
21	relay := NewBrowserLaunchRelay(ipc)
22	reservation := &prepareTestCloser{}
23	err := relay.(port.BrowserLaunchRelayPreparer).Prepare(reservation)
24	require.NoError(t, err)
25	defer reservation.Close()
26
27	// A competing process must not steal the socket before GTK is ready.
28	competitor := NewBrowserLaunchRelay(ipc)
29	err = competitor.(port.BrowserLaunchRelayPreparer).Prepare(&prepareTestCloser{})
30	require.Error(t, err)
31
32	// Bound is not ready: requests must not be acknowledged yet.
33	conn, err := net.Dial("unix", ipc.BrowserLaunchSocket)
34	require.NoError(t, err)
35	defer conn.Close()
36	_, err = conn.Write([]byte("{\"url\":\"https://example.com\"}\n"))
37	require.NoError(t, err)
38	require.NoError(t, conn.SetReadDeadline(time.Now().Add(30*time.Millisecond)))
39	var response [1]byte
40	_, err = conn.Read(response[:])
41	require.Error(t, err)
42	var timeout net.Error
43	require.ErrorAs(t, err, &timeout)
44	require.True(t, timeout.Timeout())
45
46	received := make(chan string, 2)
47	closer, err := relay.Listen(t.Context(), browserWindowOpenerFunc(func(_ context.Context, url string) error {
48		received <- url
49		return nil
50	}))
51	require.NoError(t, err)
52	require.NotSame(t, reservation, closer)
53	select {
54	case url := <-received:
55		require.Equal(t, "https://example.com", url)
56	case <-time.After(time.Second):
57		t.Fatal("reserved socket was not activated")
58	}
59	require.NoError(t, closer.Close())
60	require.NoError(t, reservation.Close())
61	require.NoFileExists(t, ipc.BrowserLaunchSocket)
62}
63
64func TestBrowserLaunchRelayPrepareRecoversStalePathWhileLeaseHeld(t *testing.T) {
65	ipc := testIPC(shortTempDir(t))
66	require.NoError(t, os.MkdirAll(filepath.Dir(ipc.BrowserLaunchSocket), 0o700))
67	require.NoError(t, os.WriteFile(ipc.BrowserLaunchSocket, []byte("stale"), 0o600))
68	relay := NewBrowserLaunchRelay(ipc)
69	err := relay.(port.BrowserLaunchRelayPreparer).Prepare(&prepareTestCloser{})
70	require.NoError(t, err)
71	info, err := os.Stat(ipc.BrowserLaunchSocket)
72	require.NoError(t, err)
73	require.NotZero(t, info.Mode()&os.ModeSocket)
74}
75
76func TestBrowserLaunchRelayListenerStopsIndependentlyOfLease(t *testing.T) {
77	ipc := testIPC(shortTempDir(t))
78	relay := NewBrowserLaunchRelay(ipc)
79	lease := &prepareTestCloser{}
80	require.NoError(t, relay.(port.BrowserLaunchRelayPreparer).Prepare(lease))
81	listener, err := relay.Listen(t.Context(), browserWindowOpenerFunc(func(context.Context, string) error { return nil }))
82	require.NoError(t, err)
83
84	// Closing the listener unlinks its socket but does not own or release lease.
85	require.NoError(t, listener.Close())
86	require.NoFileExists(t, ipc.BrowserLaunchSocket)
87	require.NoError(t, lease.Close())
88
89	replacement := NewBrowserLaunchRelay(ipc)
90	require.NoError(t, replacement.(port.BrowserLaunchRelayPreparer).Prepare(&prepareTestCloser{}))
91	require.FileExists(t, ipc.BrowserLaunchSocket)
92	// Idempotent old close must not unlink the successor socket.
93	require.NoError(t, listener.Close())
94	require.FileExists(t, ipc.BrowserLaunchSocket)
95}

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 8

Tags 42

↑↓ moveenter openesc close