detached dbc9709

test(config): validate schema-backed engine settings

commit
dbc9709dd4e86f4c6e338abcc76e4d2d16376c97
author
brice · · 2026-06-25 12:31 UTC
parent
32b8423
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
2 files · +155 -0
M internal/infrastructure/config/validation.go +32 -0
@@ -32,6 +32,7 @@ func validateConfig(config *Config) error {
3232 validationErrors = append(validationErrors, validateLogging(config)...)
3333 validationErrors = append(validationErrors, validateWorkspaceNewPaneURL(config)...)
3434 validationErrors = append(validationErrors, validateOmnibox(config)...)
35+ validationErrors = append(validationErrors, validateEngine(config)...)
3536 validationErrors = append(validationErrors, validateRendering(config)...)
3637 validationErrors = append(validationErrors, validatePrivacy(config)...)
3738 validationErrors = append(validationErrors, validateColorScheme(config)...)
@@ -508,6 +509,18 @@ func validateOmnibox(config *Config) []string {
508509 return validationErrors
509510 }
510511
512+func validateEngine(config *Config) []string {
513+ switch config.Engine.Type {
514+ case "", EngineTypeCEF, EngineTypeWebKit:
515+ return nil
516+ default:
517+ return []string{fmt.Sprintf(
518+ "engine.type must be one of: cef, webkit (got: %s)",
519+ config.Engine.Type,
520+ )}
521+ }
522+}
523+
511524 func validateRendering(config *Config) []string {
512525 var validationErrors []string
513526
@@ -523,6 +536,25 @@ func validateRendering(config *Config) []string {
523536 )
524537 }
525538
539+ switch config.Engine.WebKit.GLRenderingMode {
540+ case GLRenderingModeAuto, GLRenderingModeGLES2, GLRenderingModeGL3, GLRenderingModeNone, "":
541+ default:
542+ validationErrors = append(
543+ validationErrors,
544+ fmt.Sprintf(
545+ "engine.webkit.gl_rendering_mode must be one of: auto, gles2, gl3, none (got: %s)",
546+ config.Engine.WebKit.GLRenderingMode,
547+ ),
548+ )
549+ }
550+
551+ if config.Engine.WebKit.GStreamerDebugLevel < 0 || config.Engine.WebKit.GStreamerDebugLevel > 5 {
552+ validationErrors = append(validationErrors, fmt.Sprintf(
553+ "engine.webkit.gstreamer_debug_level must be between 0 and 5 (got: %d)",
554+ config.Engine.WebKit.GStreamerDebugLevel,
555+ ))
556+ }
557+
526558 if config.Engine.WebKit.ForceCompositingMode && config.Engine.WebKit.DisableCompositingMode {
527559 validationErrors = append(validationErrors,
528560 "engine.webkit.force_compositing_mode and engine.webkit.disable_compositing_mode cannot both be true",
@@ -32,6 +32,7 @@ func validateConfig(config *Config) error {
32 validationErrors = append(validationErrors, validateLogging(config)...)32 validationErrors = append(validationErrors, validateLogging(config)...)
33 validationErrors = append(validationErrors, validateWorkspaceNewPaneURL(config)...)33 validationErrors = append(validationErrors, validateWorkspaceNewPaneURL(config)...)
34 validationErrors = append(validationErrors, validateOmnibox(config)...)34 validationErrors = append(validationErrors, validateOmnibox(config)...)
35+ validationErrors = append(validationErrors, validateEngine(config)...)
35 validationErrors = append(validationErrors, validateRendering(config)...)36 validationErrors = append(validationErrors, validateRendering(config)...)
36 validationErrors = append(validationErrors, validatePrivacy(config)...)37 validationErrors = append(validationErrors, validatePrivacy(config)...)
37 validationErrors = append(validationErrors, validateColorScheme(config)...)38 validationErrors = append(validationErrors, validateColorScheme(config)...)
@@ -508,6 +509,18 @@ func validateOmnibox(config *Config) []string {
508 return validationErrors509 return validationErrors
509 }510 }
510 511
512+func validateEngine(config *Config) []string {
513+ switch config.Engine.Type {
514+ case "", EngineTypeCEF, EngineTypeWebKit:
515+ return nil
516+ default:
517+ return []string{fmt.Sprintf(
518+ "engine.type must be one of: cef, webkit (got: %s)",
519+ config.Engine.Type,
520+ )}
521+ }
522+}
523+
511 func validateRendering(config *Config) []string {524 func validateRendering(config *Config) []string {
512 var validationErrors []string525 var validationErrors []string
513 526
@@ -523,6 +536,25 @@ func validateRendering(config *Config) []string {
523 )536 )
524 }537 }
525 538
539+ switch config.Engine.WebKit.GLRenderingMode {
540+ case GLRenderingModeAuto, GLRenderingModeGLES2, GLRenderingModeGL3, GLRenderingModeNone, "":
541+ default:
542+ validationErrors = append(
543+ validationErrors,
544+ fmt.Sprintf(
545+ "engine.webkit.gl_rendering_mode must be one of: auto, gles2, gl3, none (got: %s)",
546+ config.Engine.WebKit.GLRenderingMode,
547+ ),
548+ )
549+ }
550+
551+ if config.Engine.WebKit.GStreamerDebugLevel < 0 || config.Engine.WebKit.GStreamerDebugLevel > 5 {
552+ validationErrors = append(validationErrors, fmt.Sprintf(
553+ "engine.webkit.gstreamer_debug_level must be between 0 and 5 (got: %d)",
554+ config.Engine.WebKit.GStreamerDebugLevel,
555+ ))
556+ }
557+
526 if config.Engine.WebKit.ForceCompositingMode && config.Engine.WebKit.DisableCompositingMode {558 if config.Engine.WebKit.ForceCompositingMode && config.Engine.WebKit.DisableCompositingMode {
527 validationErrors = append(validationErrors,559 validationErrors = append(validationErrors,
528 "engine.webkit.force_compositing_mode and engine.webkit.disable_compositing_mode cannot both be true",560 "engine.webkit.force_compositing_mode and engine.webkit.disable_compositing_mode cannot both be true",
M internal/infrastructure/config/validation_test.go +123 -0
@@ -9,6 +9,59 @@ import (
99 "github.com/stretchr/testify/require"
1010 )
1111
12+func TestValidateConfig_EngineType(t *testing.T) {
13+ t.Setenv("DUMBER_ENGINE", "")
14+
15+ tests := []struct {
16+ name string
17+ engineType string
18+ wantErr bool
19+ }{
20+ {name: "cef", engineType: EngineTypeCEF, wantErr: false},
21+ {name: "webkit", engineType: EngineTypeWebKit, wantErr: false},
22+ {name: "empty defaults to cef", engineType: "", wantErr: false},
23+ {name: "invalid", engineType: "netscape", wantErr: true},
24+ }
25+
26+ for _, tt := range tests {
27+ t.Run(tt.name, func(t *testing.T) {
28+ cfg := DefaultConfig()
29+ cfg.Engine.Type = tt.engineType
30+
31+ err := validateConfig(cfg)
32+ if tt.wantErr {
33+ require.Error(t, err)
34+ assert.Contains(t, err.Error(), "engine.type")
35+ return
36+ }
37+ require.NoError(t, err)
38+ })
39+ }
40+}
41+
42+func TestValidateConfig_EngineTypeIgnoresEnvOverride(t *testing.T) {
43+ t.Run("invalid configured type is still rejected when env override is valid", func(t *testing.T) {
44+ t.Setenv("DUMBER_ENGINE", EngineTypeWebKit)
45+ cfg := DefaultConfig()
46+ cfg.Engine.Type = "netscape"
47+
48+ err := validateConfig(cfg)
49+
50+ require.Error(t, err)
51+ assert.Contains(t, err.Error(), "engine.type")
52+ })
53+
54+ t.Run("valid configured type is not rejected when env override is invalid", func(t *testing.T) {
55+ t.Setenv("DUMBER_ENGINE", "netscape")
56+ cfg := DefaultConfig()
57+ cfg.Engine.Type = EngineTypeCEF
58+
59+ err := validateConfig(cfg)
60+
61+ require.NoError(t, err)
62+ })
63+}
64+
1265 func TestValidateConfig_EngineCookiePolicy(t *testing.T) {
1366 tests := []struct {
1467 name string
@@ -37,6 +90,76 @@ func TestValidateConfig_EngineCookiePolicy(t *testing.T) {
3790 }
3891 }
3992
93+func TestValidateConfig_WebKitMediaSettings(t *testing.T) {
94+ tests := []struct {
95+ name string
96+ mutate func(*Config)
97+ wantErr bool
98+ wantField string
99+ }{
100+ {
101+ name: "valid gl rendering modes",
102+ mutate: func(cfg *Config) {
103+ cfg.Engine.WebKit.GLRenderingMode = GLRenderingModeGLES2
104+ },
105+ wantErr: false,
106+ },
107+ {
108+ name: "invalid gl rendering mode",
109+ mutate: func(cfg *Config) {
110+ cfg.Engine.WebKit.GLRenderingMode = GLRenderingMode("metal")
111+ },
112+ wantErr: true,
113+ wantField: "engine.webkit.gl_rendering_mode",
114+ },
115+ {
116+ name: "gstreamer debug level lower bound",
117+ mutate: func(cfg *Config) {
118+ cfg.Engine.WebKit.GStreamerDebugLevel = 0
119+ },
120+ wantErr: false,
121+ },
122+ {
123+ name: "gstreamer debug level upper bound",
124+ mutate: func(cfg *Config) {
125+ cfg.Engine.WebKit.GStreamerDebugLevel = 5
126+ },
127+ wantErr: false,
128+ },
129+ {
130+ name: "negative gstreamer debug level",
131+ mutate: func(cfg *Config) {
132+ cfg.Engine.WebKit.GStreamerDebugLevel = -1
133+ },
134+ wantErr: true,
135+ wantField: "engine.webkit.gstreamer_debug_level",
136+ },
137+ {
138+ name: "too high gstreamer debug level",
139+ mutate: func(cfg *Config) {
140+ cfg.Engine.WebKit.GStreamerDebugLevel = 6
141+ },
142+ wantErr: true,
143+ wantField: "engine.webkit.gstreamer_debug_level",
144+ },
145+ }
146+
147+ for _, tt := range tests {
148+ t.Run(tt.name, func(t *testing.T) {
149+ cfg := DefaultConfig()
150+ tt.mutate(cfg)
151+
152+ err := validateConfig(cfg)
153+ if tt.wantErr {
154+ require.Error(t, err)
155+ assert.Contains(t, err.Error(), tt.wantField)
156+ return
157+ }
158+ require.NoError(t, err)
159+ })
160+ }
161+}
162+
40163 func TestValidateConfig_CEFConfig(t *testing.T) {
41164 tests := []struct {
42165 name string
@@ -9,6 +9,59 @@ import (
9 "github.com/stretchr/testify/require"9 "github.com/stretchr/testify/require"
10 )10 )
11 11
12+func TestValidateConfig_EngineType(t *testing.T) {
13+ t.Setenv("DUMBER_ENGINE", "")
14+
15+ tests := []struct {
16+ name string
17+ engineType string
18+ wantErr bool
19+ }{
20+ {name: "cef", engineType: EngineTypeCEF, wantErr: false},
21+ {name: "webkit", engineType: EngineTypeWebKit, wantErr: false},
22+ {name: "empty defaults to cef", engineType: "", wantErr: false},
23+ {name: "invalid", engineType: "netscape", wantErr: true},
24+ }
25+
26+ for _, tt := range tests {
27+ t.Run(tt.name, func(t *testing.T) {
28+ cfg := DefaultConfig()
29+ cfg.Engine.Type = tt.engineType
30+
31+ err := validateConfig(cfg)
32+ if tt.wantErr {
33+ require.Error(t, err)
34+ assert.Contains(t, err.Error(), "engine.type")
35+ return
36+ }
37+ require.NoError(t, err)
38+ })
39+ }
40+}
41+
42+func TestValidateConfig_EngineTypeIgnoresEnvOverride(t *testing.T) {
43+ t.Run("invalid configured type is still rejected when env override is valid", func(t *testing.T) {
44+ t.Setenv("DUMBER_ENGINE", EngineTypeWebKit)
45+ cfg := DefaultConfig()
46+ cfg.Engine.Type = "netscape"
47+
48+ err := validateConfig(cfg)
49+
50+ require.Error(t, err)
51+ assert.Contains(t, err.Error(), "engine.type")
52+ })
53+
54+ t.Run("valid configured type is not rejected when env override is invalid", func(t *testing.T) {
55+ t.Setenv("DUMBER_ENGINE", "netscape")
56+ cfg := DefaultConfig()
57+ cfg.Engine.Type = EngineTypeCEF
58+
59+ err := validateConfig(cfg)
60+
61+ require.NoError(t, err)
62+ })
63+}
64+
12 func TestValidateConfig_EngineCookiePolicy(t *testing.T) {65 func TestValidateConfig_EngineCookiePolicy(t *testing.T) {
13 tests := []struct {66 tests := []struct {
14 name string67 name string
@@ -37,6 +90,76 @@ func TestValidateConfig_EngineCookiePolicy(t *testing.T) {
37 }90 }
38 }91 }
39 92
93+func TestValidateConfig_WebKitMediaSettings(t *testing.T) {
94+ tests := []struct {
95+ name string
96+ mutate func(*Config)
97+ wantErr bool
98+ wantField string
99+ }{
100+ {
101+ name: "valid gl rendering modes",
102+ mutate: func(cfg *Config) {
103+ cfg.Engine.WebKit.GLRenderingMode = GLRenderingModeGLES2
104+ },
105+ wantErr: false,
106+ },
107+ {
108+ name: "invalid gl rendering mode",
109+ mutate: func(cfg *Config) {
110+ cfg.Engine.WebKit.GLRenderingMode = GLRenderingMode("metal")
111+ },
112+ wantErr: true,
113+ wantField: "engine.webkit.gl_rendering_mode",
114+ },
115+ {
116+ name: "gstreamer debug level lower bound",
117+ mutate: func(cfg *Config) {
118+ cfg.Engine.WebKit.GStreamerDebugLevel = 0
119+ },
120+ wantErr: false,
121+ },
122+ {
123+ name: "gstreamer debug level upper bound",
124+ mutate: func(cfg *Config) {
125+ cfg.Engine.WebKit.GStreamerDebugLevel = 5
126+ },
127+ wantErr: false,
128+ },
129+ {
130+ name: "negative gstreamer debug level",
131+ mutate: func(cfg *Config) {
132+ cfg.Engine.WebKit.GStreamerDebugLevel = -1
133+ },
134+ wantErr: true,
135+ wantField: "engine.webkit.gstreamer_debug_level",
136+ },
137+ {
138+ name: "too high gstreamer debug level",
139+ mutate: func(cfg *Config) {
140+ cfg.Engine.WebKit.GStreamerDebugLevel = 6
141+ },
142+ wantErr: true,
143+ wantField: "engine.webkit.gstreamer_debug_level",
144+ },
145+ }
146+
147+ for _, tt := range tests {
148+ t.Run(tt.name, func(t *testing.T) {
149+ cfg := DefaultConfig()
150+ tt.mutate(cfg)
151+
152+ err := validateConfig(cfg)
153+ if tt.wantErr {
154+ require.Error(t, err)
155+ assert.Contains(t, err.Error(), tt.wantField)
156+ return
157+ }
158+ require.NoError(t, err)
159+ })
160+ }
161+}
162+
40 func TestValidateConfig_CEFConfig(t *testing.T) {163 func TestValidateConfig_CEFConfig(t *testing.T) {
41 tests := []struct {164 tests := []struct {
42 name string165 name string

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