package config import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func env(values map[string]string) func(string) string { return func(key string) string { return values[key] } } func validEnv() map[string]string { return map[string]string{ "DB_HOST": "localhost", "DB_PORT": "5432", "DB_USERNAME": "user", "DB_PASSWORD": "pass", "DB_NAME": "music", "MUSIC_PATH": "/music", "CHARACTERS_PATH": "/characters", } } func TestLoadDefaults(t *testing.T) { cfg, err := load(env(validEnv())) require.NoError(t, err) assert.Equal(t, 8080, cfg.Port) assert.Equal(t, "info", cfg.LogLevel) assert.Equal(t, "songs", cfg.SoundCheckPath) assert.Equal(t, DefaultReleasesURL, cfg.ReleasesURL) assert.Empty(t, cfg.TrustedProxies) assert.Empty(t, cfg.CORSAllowedOrigins) assert.Equal(t, DefaultMetricsPort, cfg.MetricsPort) assert.Empty(t, cfg.CoversPath, "covers are off by default") assert.Empty(t, cfg.SteamGridDBAPIKey) } func TestLoadUploadLimits(t *testing.T) { cfg, err := load(env(validEnv())) require.NoError(t, err) assert.Equal(t, int64(DefaultUploadMaxFileMB<<20), cfg.UploadMaxFileSize) assert.Equal(t, int64(DefaultUploadMaxTotalMB<<20), cfg.UploadMaxTotalSize) values := validEnv() values["UPLOAD_MAX_FILE_MB"] = "100" values["UPLOAD_MAX_TOTAL_MB"] = "500" cfg, err = load(env(values)) require.NoError(t, err) assert.Equal(t, int64(100<<20), cfg.UploadMaxFileSize) assert.Equal(t, int64(500<<20), cfg.UploadMaxTotalSize) for _, invalid := range []string{"0", "-5", "lots", "1.5"} { values["UPLOAD_MAX_FILE_MB"] = invalid _, err = load(env(values)) assert.ErrorContains(t, err, "UPLOAD_MAX_FILE_MB", invalid) } } func TestLoadCovers(t *testing.T) { values := validEnv() values["COVERS_PATH"] = "/covers" values["STEAMGRIDDB_API_KEY"] = "key" cfg, err := load(env(values)) require.NoError(t, err) assert.Equal(t, "/covers", cfg.CoversPath) assert.Equal(t, "key", cfg.SteamGridDBAPIKey) } func TestLoadMetricsPort(t *testing.T) { values := validEnv() values["METRICS_PORT"] = "9100" cfg, err := load(env(values)) require.NoError(t, err) assert.Equal(t, 9100, cfg.MetricsPort) values["METRICS_PORT"] = "off" cfg, err = load(env(values)) require.NoError(t, err) assert.Zero(t, cfg.MetricsPort) for _, invalid := range []string{"abc", "0", "70000", "-1", "OFF"} { values["METRICS_PORT"] = invalid _, err = load(env(values)) assert.ErrorContains(t, err, "METRICS_PORT", invalid) } } func TestLoadMissingRequired(t *testing.T) { values := validEnv() delete(values, "MUSIC_PATH") delete(values, "DB_HOST") _, err := load(env(values)) require.Error(t, err) assert.Contains(t, err.Error(), "MUSIC_PATH is required") assert.Contains(t, err.Error(), "DB_HOST is required") } func TestLoadTrustedProxies(t *testing.T) { values := validEnv() values["TRUSTED_PROXIES"] = "10.0.0.0/8, 172.16.0.0/12" cfg, err := load(env(values)) require.NoError(t, err) require.Len(t, cfg.TrustedProxies, 2) assert.Equal(t, "10.0.0.0/8", cfg.TrustedProxies[0].String()) values["TRUSTED_PROXIES"] = "not-a-cidr" _, err = load(env(values)) assert.ErrorContains(t, err, "TRUSTED_PROXIES") } func TestLoadCORSAllowedOrigins(t *testing.T) { values := validEnv() values["CORS_ALLOWED_ORIGINS"] = "https://music.example.com, http://localhost:5173," cfg, err := load(env(values)) require.NoError(t, err) assert.Equal(t, []string{"https://music.example.com", "http://localhost:5173"}, cfg.CORSAllowedOrigins) for _, invalid := range []string{"music.example.com", "ftp://example.com", "https://example.com/app", "https://*.example.com", "https://*", "*", "https://example.com?x=1", "https://user@example.com"} { values["CORS_ALLOWED_ORIGINS"] = invalid _, err = load(env(values)) assert.ErrorContains(t, err, "CORS_ALLOWED_ORIGINS", invalid) } } func TestLoadInvalidPort(t *testing.T) { values := validEnv() values["PORT"] = "abc" _, err := load(env(values)) assert.ErrorContains(t, err, "PORT") }