v0.33.2 57f21d6

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

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