migrate_engine_test.go RawHistoryFolder

1package config
2
3import (
4	"os"
5	"path/filepath"
6	"testing"
7
8	"github.com/pelletier/go-toml/v2"
9	"github.com/stretchr/testify/assert"
10	"github.com/stretchr/testify/require"
11)
12
13const oldFormatConfig = `
14[performance]
15profile = "balanced"
16zoom_cache_size = 50
17webview_pool_prewarm_count = 2
18skia_cpu_painting_threads = 4
19skia_gpu_painting_threads = 2
20skia_enable_cpu_rendering = false
21web_process_memory_limit_mb = 512
22web_process_memory_poll_interval_sec = 5.0
23web_process_memory_conservative_threshold = 0.7
24web_process_memory_strict_threshold = 0.9
25network_process_memory_limit_mb = 256
26network_process_memory_poll_interval_sec = 10.0
27network_process_memory_conservative_threshold = 0.6
28network_process_memory_strict_threshold = 0.85
29
30[privacy]
31cookie_policy = "accept_all"
32itp_enabled = true
33
34[rendering]
35mode = "auto"
36disable_dmabuf_renderer = false
37force_compositing_mode = true
38disable_compositing_mode = false
39gsk_renderer = "gl"
40disable_mipmaps = false
41prefer_gl = true
42draw_compositing_indicators = false
43show_fps = false
44sample_memory = false
45debug_frames = false
46
47[media]
48hardware_decoding = true
49prefer_av1 = false
50show_diagnostics = false
51force_vsync = true
52gl_rendering_mode = "auto"
53gstreamer_debug_level = 2
54
55[runtime]
56prefix = "/usr/local"
57`
58
59func TestMigrateToEngineConfig_OldFormat(t *testing.T) {
60	tmpDir := t.TempDir()
61	configFile := filepath.Join(tmpDir, "config.toml")
62
63	err := os.WriteFile(configFile, []byte(oldFormatConfig), 0o644)
64	require.NoError(t, err)
65
66	migrated, err := MigrateToEngineConfig(configFile)
67	require.NoError(t, err)
68	assert.True(t, migrated, "should report migration performed")
69
70	// Read the migrated config
71	data, err := os.ReadFile(configFile)
72	require.NoError(t, err)
73
74	var raw map[string]any
75	err = toml.Unmarshal(data, &raw)
76	require.NoError(t, err)
77
78	// [engine] section must exist
79	engineAny, ok := raw["engine"]
80	require.True(t, ok, "engine section must exist")
81	engine, ok := engineAny.(map[string]any)
82	require.True(t, ok, "engine must be a map")
83
84	// legacy engine migration preserves WebKit because the old rendering/media sections are WebKit-specific
85	assert.Equal(t, "webkit", engine["type"])
86
87	// [performance] -> [engine] universal fields
88	assert.Equal(t, "balanced", engine["profile"])
89	assert.Equal(t, int64(50), engine["zoom_cache_size"])
90	assert.Equal(t, int64(2), engine["pool_prewarm_count"])
91
92	// [privacy] -> [engine] universal field, translated to canonical schema value
93	assert.Equal(t, "always", engine["cookie_policy"])
94
95	// [engine.webkit] section
96	webkitAny, ok := engine["webkit"]
97	require.True(t, ok, "engine.webkit section must exist")
98	webkit, ok := webkitAny.(map[string]any)
99	require.True(t, ok, "engine.webkit must be a map")
100
101	// [privacy] -> [engine.webkit]
102	assert.Equal(t, true, webkit["itp_enabled"])
103
104	// [rendering] -> [engine.webkit] (excluding mode which is dropped)
105	assert.Equal(t, false, webkit["disable_dmabuf_renderer"])
106	assert.Equal(t, true, webkit["force_compositing_mode"])
107	assert.Equal(t, false, webkit["disable_compositing_mode"])
108	assert.Equal(t, "gl", webkit["gsk_renderer"])
109	assert.Equal(t, false, webkit["disable_mipmaps"])
110	assert.Equal(t, true, webkit["prefer_gl"])
111	assert.Equal(t, false, webkit["draw_compositing_indicators"])
112	assert.Equal(t, false, webkit["show_fps"])
113	assert.Equal(t, false, webkit["sample_memory"])
114	assert.Equal(t, false, webkit["debug_frames"])
115	// rendering.mode must be dropped (not present in webkit)
116	assert.NotContains(t, webkit, "mode")
117
118	// [performance] -> [engine.webkit] (webkit-specific)
119	assert.Equal(t, int64(4), webkit["skia_cpu_painting_threads"])
120	assert.Equal(t, int64(2), webkit["skia_gpu_painting_threads"])
121	assert.Equal(t, false, webkit["skia_enable_cpu_rendering"])
122	assert.Equal(t, int64(512), webkit["web_process_memory_limit_mb"])
123	assert.InDelta(t, 5.0, webkit["web_process_memory_poll_interval_sec"], 0.001)
124	assert.InDelta(t, 0.7, webkit["web_process_memory_conservative_threshold"], 0.001)
125	assert.InDelta(t, 0.9, webkit["web_process_memory_strict_threshold"], 0.001)
126	assert.Equal(t, int64(256), webkit["network_process_memory_limit_mb"])
127	assert.InDelta(t, 10.0, webkit["network_process_memory_poll_interval_sec"], 0.001)
128	assert.InDelta(t, 0.6, webkit["network_process_memory_conservative_threshold"], 0.001)
129	assert.InDelta(t, 0.85, webkit["network_process_memory_strict_threshold"], 0.001)
130
131	// [media] GStreamer fields -> [engine.webkit]
132	assert.Equal(t, true, webkit["force_vsync"])
133	assert.Equal(t, "auto", webkit["gl_rendering_mode"])
134	assert.Equal(t, int64(2), webkit["gstreamer_debug_level"])
135
136	// [runtime] -> [engine.webkit]
137	assert.Equal(t, "/usr/local", webkit["prefix"])
138
139	// Old top-level sections must be removed
140	assert.NotContains(t, raw, "performance")
141	assert.NotContains(t, raw, "rendering")
142	assert.NotContains(t, raw, "runtime")
143
144	// [privacy] should be removed (all fields migrated)
145	assert.NotContains(t, raw, "privacy")
146}
147
148func TestMigrateToEngineConfig_AlreadyMigrated(t *testing.T) {
149	tmpDir := t.TempDir()
150	configFile := filepath.Join(tmpDir, "config.toml")
151
152	alreadyMigrated := `
153[engine]
154type = "webkit"
155profile = "balanced"
156
157[engine.webkit]
158itp_enabled = true
159`
160	err := os.WriteFile(configFile, []byte(alreadyMigrated), 0o644)
161	require.NoError(t, err)
162
163	migrated, err := MigrateToEngineConfig(configFile)
164	require.NoError(t, err)
165	assert.False(t, migrated, "should not migrate when already migrated")
166
167	// Content should be unchanged
168	data, err := os.ReadFile(configFile)
169	require.NoError(t, err)
170	assert.Equal(t, alreadyMigrated, string(data))
171}
172
173func TestMigrateToEngineConfig_NoOldSections(t *testing.T) {
174	tmpDir := t.TempDir()
175	configFile := filepath.Join(tmpDir, "config.toml")
176
177	noOldSections := `
178[history]
179max_entries = 1000
180
181[logging]
182level = "info"
183`
184	err := os.WriteFile(configFile, []byte(noOldSections), 0o644)
185	require.NoError(t, err)
186
187	migrated, err := MigrateToEngineConfig(configFile)
188	require.NoError(t, err)
189	assert.False(t, migrated, "should not migrate when no old sections exist")
190
191	// Content should be unchanged
192	data, err := os.ReadFile(configFile)
193	require.NoError(t, err)
194	assert.Equal(t, noOldSections, string(data))
195}
196
197func TestMigrateToEngineConfig_PreservesNonMigratedMediaFields(t *testing.T) {
198	tmpDir := t.TempDir()
199	configFile := filepath.Join(tmpDir, "config.toml")
200
201	content := `
202[media]
203hardware_decoding = true
204prefer_av1 = false
205show_diagnostics = true
206force_vsync = true
207gl_rendering_mode = "auto"
208gstreamer_debug_level = 3
209
210[rendering]
211disable_dmabuf_renderer = false
212`
213	err := os.WriteFile(configFile, []byte(content), 0o644)
214	require.NoError(t, err)
215
216	migrated, err := MigrateToEngineConfig(configFile)
217	require.NoError(t, err)
218	assert.True(t, migrated)
219
220	data, err := os.ReadFile(configFile)
221	require.NoError(t, err)
222
223	var raw map[string]any
224	err = toml.Unmarshal(data, &raw)
225	require.NoError(t, err)
226
227	// media section must still exist with non-migrated fields
228	mediaAny, ok := raw["media"]
229	require.True(t, ok, "media section must still exist")
230	media, ok := mediaAny.(map[string]any)
231	require.True(t, ok)
232
233	assert.Equal(t, true, media["hardware_decoding"])
234	assert.Equal(t, false, media["prefer_av1"])
235	assert.Equal(t, true, media["show_diagnostics"])
236
237	// Migrated media fields should be removed from media
238	assert.NotContains(t, media, "force_vsync")
239	assert.NotContains(t, media, "gl_rendering_mode")
240	assert.NotContains(t, media, "gstreamer_debug_level")
241
242	// Migrated fields should be in engine.webkit
243	engineAny, ok := raw["engine"]
244	require.True(t, ok, "engine section must exist")
245	engine, ok := engineAny.(map[string]any)
246	require.True(t, ok, "engine section must be a map")
247	webkitAny, ok := engine["webkit"]
248	require.True(t, ok, "engine.webkit section must exist")
249	webkit, ok := webkitAny.(map[string]any)
250	require.True(t, ok, "engine.webkit section must be a map")
251	assert.Equal(t, true, webkit["force_vsync"])
252	assert.Equal(t, "auto", webkit["gl_rendering_mode"])
253	assert.Equal(t, int64(3), webkit["gstreamer_debug_level"])
254}
255
256func TestLegacyEngineAliasesMetadataCoverage(t *testing.T) {
257	require.NotEmpty(t, legacyEngineAliases)
258
259	aliases := make(map[string]legacyEngineAlias)
260	for _, alias := range legacyEngineAliases {
261		key := alias.legacyKey()
262		require.NotEmpty(t, alias.legacySection, "%s should have a legacy section", key)
263		require.NotEmpty(t, alias.legacyField, "%s should have a legacy field", key)
264		require.NotContains(t, aliases, key, "duplicate metadata for %s", key)
265		aliases[key] = alias
266
267		if alias.dropped {
268			assert.Empty(t, alias.targetSection, "%s is dropped and should not have a target section", key)
269			assert.Empty(t, alias.targetField, "%s is dropped and should not have a target field", key)
270			continue
271		}
272
273		require.Contains(t, []string{"engine", "engine.webkit"}, alias.targetSection, "%s should target a known engine section", key)
274		require.NotEmpty(t, alias.targetField, "%s should have a canonical target field", key)
275	}
276
277	for _, key := range []string{
278		"media.force_vsync",
279		"media.gl_rendering_mode",
280		"media.gstreamer_debug_level",
281		"runtime.prefix",
282		"performance.profile",
283		"privacy.cookie_policy",
284		"privacy.itp_enabled",
285		"rendering.disable_dmabuf_renderer",
286	} {
287		alias, ok := aliases[key]
288		require.True(t, ok, "missing metadata for %s", key)
289		require.False(t, alias.dropped, "%s should have a canonical target", key)
290	}
291
292	renderingMode, ok := aliases["rendering.mode"]
293	require.True(t, ok, "missing dropped metadata for rendering.mode")
294	assert.True(t, renderingMode.dropped)
295}
296
297func TestHasOldEngineSections_UsesMetadataForMigratedMediaKeys(t *testing.T) {
298	for _, field := range []string{"force_vsync", "gl_rendering_mode", "gstreamer_debug_level"} {
299		raw := map[string]any{"media": map[string]any{field: true}}
300		assert.True(t, hasOldEngineSections(raw), "media.%s should trigger engine migration", field)
301	}
302
303	raw := map[string]any{"media": map[string]any{"hardware_decoding": true}}
304	assert.False(t, hasOldEngineSections(raw), "non-migrated media keys should not trigger engine migration")
305}
306
307func TestMigrateToEngineConfig_MixedEngineAndMigratedMediaKey(t *testing.T) {
308	tmpDir := t.TempDir()
309	configFile := filepath.Join(tmpDir, "config.toml")
310
311	content := `
312[engine]
313type = "webkit"
314
315[media]
316gl_rendering_mode = "auto"
317`
318	err := os.WriteFile(configFile, []byte(content), 0o644)
319	require.NoError(t, err)
320
321	migrated, err := MigrateToEngineConfig(configFile)
322	require.Error(t, err)
323	assert.False(t, migrated)
324	assert.Contains(t, err.Error(), "media.gl_rendering_mode")
325}
326
327func TestMigrateToEngineConfig_EngineTypeDefault(t *testing.T) {
328	tmpDir := t.TempDir()
329	configFile := filepath.Join(tmpDir, "config.toml")
330
331	// Minimal old-format config to trigger migration
332	content := `
333[rendering]
334show_fps = true
335`
336	err := os.WriteFile(configFile, []byte(content), 0o644)
337	require.NoError(t, err)
338
339	migrated, err := MigrateToEngineConfig(configFile)
340	require.NoError(t, err)
341	assert.True(t, migrated)
342
343	data, err := os.ReadFile(configFile)
344	require.NoError(t, err)
345
346	var raw map[string]any
347	err = toml.Unmarshal(data, &raw)
348	require.NoError(t, err)
349
350	engineAny, ok := raw["engine"]
351	require.True(t, ok, "raw[\"engine\"] should exist")
352	engine, ok := engineAny.(map[string]any)
353	require.True(t, ok, "raw[\"engine\"] should be map[string]any, got %T", engineAny)
354	assert.Equal(t, EngineTypeWebKit, engine["type"], "legacy engine migration should preserve WebKit")
355}

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