v0.30.0 eb3068f

engine_init_test.go RawHistoryFolder

1package cef
2
3import (
4	"bytes"
5	"os"
6	"path/filepath"
7	"testing"
8
9	"github.com/bnema/dumber/internal/application/port"
10	"github.com/bnema/dumber/internal/infrastructure/audio/factory"
11	"github.com/bnema/dumber/internal/infrastructure/runtimeprofile"
12	"github.com/rs/zerolog"
13	"github.com/stretchr/testify/require"
14)
15
16func TestResolvedStateRoot_PrefersCacheDir(t *testing.T) {
17	profile := testCEFDevProfile(t)
18	root := resolvedStateRoot(profile.CEFUserDataDir(), port.EngineOptions{DataDir: "/tmp/data", CacheDir: "/tmp/cache"})
19	require.Equal(t, "/tmp/cache", root)
20}
21
22func TestResolvedStateRoot_UsesEnvOverride(t *testing.T) {
23	profile := testCEFDevProfile(t)
24	t.Setenv(CEFRootCachePathEnvVar, "/tmp/override")
25
26	root := resolvedStateRoot(profile.CEFUserDataDir(), port.EngineOptions{})
27	require.Equal(t, "/tmp/override", root)
28
29	root = resolvedStateRoot(profile.CEFUserDataDir(), port.EngineOptions{DataDir: "/tmp/data", CacheDir: "/tmp/cache"})
30	require.Equal(t, "/tmp/override", root)
31}
32
33func TestResolvedStateRoot_UsesProfileDefault(t *testing.T) {
34	profile := testCEFProdProfile(t)
35	root := resolvedStateRoot(profile.CEFUserDataDir(), port.EngineOptions{})
36	require.Equal(t, profile.CEFUserDataDir(), root)
37}
38
39func TestPrepareCEFSettings_UsesResolvedProfilePaths(t *testing.T) {
40	logger := zerolog.Nop()
41	profile := testCEFDevProfile(t)
42	settings, err := prepareCEFSettings(port.EngineOptions{}, RuntimePaths{StateRoot: profile.CEFUserDataDir(), LogFile: profile.CEFLogFile()}, RuntimeConfig{}, &logger)
43	require.NoError(t, err)
44	require.Equal(t, profile.CEFUserDataDir(), settings.RootCachePath)
45	require.Equal(t, profile.CEFLogFile(), settings.LogFile)
46	require.Empty(t, settings.BrowserSubprocessPath)
47}
48
49func TestParseLoadedLibCEFPath(t *testing.T) {
50	maps := "7f5fd4000000-7f5fd4200000 r--p 00000000 00:00 0 /usr/lib/libvulkan.so.1\n" +
51		"7f5fe0000000-7f5fe8200000 r-xp 00000000 00:00 0 /opt/cef-vaapi-runtime/usr/lib/cef/libcef.so\n" +
52		"7f5fe8200000-7f5fe8400000 r--p 08200000 00:00 0 /opt/cef-vaapi-runtime/usr/lib/cef/libcef.so\n"
53
54	require.Equal(t, "/opt/cef-vaapi-runtime/usr/lib/cef/libcef.so", parseLoadedLibCEFPath(maps))
55}
56
57func TestParseLoadedLibCEFPath_ReturnsEmptyWhenAbsent(t *testing.T) {
58	require.Empty(t, parseLoadedLibCEFPath("7f5fd4000000-7f5fd4200000 r--p 00000000 00:00 0 /usr/lib/libvulkan.so.1\n"))
59}
60
61func TestPrepareCEFSettings_RejectsNonDefaultCookiePolicy(t *testing.T) {
62	logger := zerolog.Nop()
63	profile := testCEFDevProfile(t)
64	_, err := prepareCEFSettings(port.EngineOptions{CookiePolicy: port.CookiePolicyNever}, RuntimePaths{StateRoot: profile.CEFUserDataDir(), LogFile: profile.CEFLogFile()}, RuntimeConfig{}, &logger)
65	require.ErrorIs(t, err, ErrCookiePolicyUnsupported)
66}
67
68func TestPrepareCEFSettings_AllowsNoThirdPartyCookiePolicy(t *testing.T) {
69	logger := zerolog.Nop()
70	profile := testCEFDevProfile(t)
71	_, err := prepareCEFSettings(port.EngineOptions{CookiePolicy: port.CookiePolicyNoThirdParty}, RuntimePaths{StateRoot: profile.CEFUserDataDir(), LogFile: profile.CEFLogFile()}, RuntimeConfig{}, &logger)
72	require.NoError(t, err)
73}
74
75func TestResolveCEFInitTraceFile_EmptyWithoutLogPath(t *testing.T) {
76	require.Empty(t, resolveCEFInitTraceFile("", ""))
77}
78
79func TestPrepareCEFLogFile_CreatesPrivateDirectoryAndFile(t *testing.T) {
80	logFile := filepath.Join(t.TempDir(), "private", "cef_runtime.log")
81
82	path, err := prepareCEFLogFile("", logFile)
83	require.NoError(t, err)
84	require.Equal(t, logFile, path)
85
86	dirInfo, err := os.Stat(filepath.Dir(logFile))
87	require.NoError(t, err)
88	require.Equal(t, os.FileMode(dirPerm), dirInfo.Mode().Perm())
89
90	fileInfo, err := os.Stat(logFile)
91	require.NoError(t, err)
92	require.Equal(t, os.FileMode(filePerm), fileInfo.Mode().Perm())
93}
94
95func TestPrepareCEFLogFile_TightensExistingFilePermissions(t *testing.T) {
96	logFile := filepath.Join(t.TempDir(), "private", "cef_runtime.log")
97	require.NoError(t, os.MkdirAll(filepath.Dir(logFile), dirPerm))
98	require.NoError(t, os.WriteFile(logFile, []byte("existing"), 0o644))
99
100	path, err := prepareCEFLogFile("", logFile)
101	require.NoError(t, err)
102	require.Equal(t, logFile, path)
103
104	fileInfo, err := os.Stat(logFile)
105	require.NoError(t, err)
106	require.Equal(t, os.FileMode(filePerm), fileInfo.Mode().Perm())
107}
108
109func TestPrepareCEFLogFile_RejectsSymlink(t *testing.T) {
110	target := filepath.Join(t.TempDir(), "target.log")
111	require.NoError(t, os.WriteFile(target, []byte("existing"), 0o644))
112
113	logFile := filepath.Join(t.TempDir(), "private", "cef_runtime.log")
114	require.NoError(t, os.MkdirAll(filepath.Dir(logFile), dirPerm))
115	require.NoError(t, os.Symlink(target, logFile))
116
117	path, err := prepareCEFLogFile("", logFile)
118	require.ErrorContains(t, err, "must not be a symlink")
119	require.Empty(t, path)
120
121	targetInfo, statErr := os.Stat(target)
122	require.NoError(t, statErr)
123	require.Equal(t, os.FileMode(0o644), targetInfo.Mode().Perm())
124}
125
126func TestPrepareCEFLogFile_RejectsDirectoryPath(t *testing.T) {
127	logFile := filepath.Join(t.TempDir(), "private", "cef_runtime.log")
128	require.NoError(t, os.MkdirAll(logFile, dirPerm))
129
130	path, err := prepareCEFLogFile("", logFile)
131	require.ErrorContains(t, err, "not a regular file")
132	require.Empty(t, path)
133}
134
135func TestResolveCEFInitTraceFile_UsesExplicitLogFile(t *testing.T) {
136	logFile := filepath.Join(t.TempDir(), "custom", "cef_runtime.log")
137
138	path := resolveCEFInitTraceFile("", logFile)
139	require.Equal(t, filepath.Join(filepath.Dir(logFile), "cef_runtime.bootstrap.log"), path)
140}
141
142func TestResolveCEFInitTraceFile_UsesResolvedProfileLogDirByDefault(t *testing.T) {
143	profile := testCEFDevProfile(t)
144
145	path := resolveCEFInitTraceFile(profile.CEFLogFile(), "")
146	require.Equal(t, filepath.Join(profile.EnginePaths.LogDir, "cef_runtime.bootstrap.log"), path)
147}
148
149func TestPrepareCEFSettings_IgnoresInitTraceRequestWithoutTouchingFilesystem(t *testing.T) {
150	t.Setenv(puregoCEFInitTraceEnvVar, "1")
151	profile := testCEFDevProfile(t)
152	bootstrapLogFile := resolveCEFInitTraceFile(profile.CEFLogFile(), "")
153
154	var logs bytes.Buffer
155	logger := zerolog.New(&logs)
156
157	settings, err := prepareCEFSettings(
158		port.EngineOptions{},
159		RuntimePaths{StateRoot: profile.CEFUserDataDir(), LogFile: profile.CEFLogFile()},
160		RuntimeConfig{},
161		&logger,
162	)
163	require.NoError(t, err)
164	require.Equal(t, profile.CEFLogFile(), settings.LogFile)
165
166	_, statErr := os.Stat(bootstrapLogFile)
167	require.ErrorIs(t, statErr, os.ErrNotExist)
168	require.Contains(t, logs.String(), puregoCEFInitTraceEnvVar)
169	require.Contains(t, logs.String(), bootstrapLogFile)
170}
171
172// TestCreateAudioOutputFactory_CreatesUsableFactory verifies that the audio
173// factory can be created and produces working streams. This tests the runtime
174// wiring decision to create the factory during CEF engine setup.
175func TestCreateAudioOutputFactory_ReturnsFactory(t *testing.T) {
176	audioFactory := factory.NewAudioOutputFactory()
177
178	require.NotNil(t, audioFactory, "Audio factory should not be nil")
179}
180
181func testCEFDevProfile(t *testing.T) runtimeprofile.Profile {
182	t.Helper()
183	cwd := t.TempDir()
184	runtimeDir := shortRuntimeDir(t)
185	t.Setenv("XDG_RUNTIME_DIR", runtimeDir)
186	profile, err := runtimeprofile.Resolve(runtimeprofile.ResolveInput{
187		Env: func(key string) string {
188			switch key {
189			case "ENV":
190				return "dev"
191			case "XDG_RUNTIME_DIR":
192				return runtimeDir
193			default:
194				return ""
195			}
196		},
197		Engine: "cef",
198		CWD:    func() (string, error) { return cwd, nil },
199	})
200	require.NoError(t, err)
201	return profile
202}
203
204func shortRuntimeDir(t *testing.T) string {
205	t.Helper()
206
207	dir, err := os.MkdirTemp("", "dbr-")
208	require.NoError(t, err)
209	t.Cleanup(func() {
210		_ = os.RemoveAll(dir)
211	})
212	return dir
213}
214
215func testCEFProdProfile(t *testing.T) runtimeprofile.Profile {
216	t.Helper()
217	root := t.TempDir()
218	profile, err := runtimeprofile.Resolve(runtimeprofile.ResolveInput{
219		Env:    func(string) string { return "" },
220		Engine: "cef",
221		CWD:    func() (string, error) { return root, nil },
222		Base: runtimeprofile.BasePaths{
223			ConfigHome: filepath.Join(root, "config"),
224			DataHome:   filepath.Join(root, "data"),
225			StateHome:  filepath.Join(root, "state"),
226			CacheHome:  filepath.Join(root, "cache"),
227		},
228	})
229	require.NoError(t, err)
230	return profile
231}

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