93 lines
3.1 KiB
Go
93 lines
3.1 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
)
|
|
|
|
// Config is read once at startup, so a mistyped env key fails silently: the
|
|
// service boots on a default and points at the wrong host, or ships with a
|
|
// security switch left off. Cheap to pin.
|
|
|
|
func setEnv(t *testing.T, key, value string) {
|
|
t.Helper()
|
|
previous, had := os.LookupEnv(key)
|
|
if value == "" {
|
|
_ = os.Unsetenv(key)
|
|
} else {
|
|
_ = os.Setenv(key, value)
|
|
}
|
|
t.Cleanup(func() {
|
|
if had {
|
|
_ = os.Setenv(key, previous)
|
|
} else {
|
|
_ = os.Unsetenv(key)
|
|
}
|
|
})
|
|
}
|
|
|
|
// The geocoder settings added for the customer app. GEOCODER_URL is what the
|
|
// place search proxies through — the app is never handed a map key, after the
|
|
// legacy rider app's key had to be revoked.
|
|
func TestGeocoderDefaultsAndOverrides(t *testing.T) {
|
|
setEnv(t, "GEOCODER_URL", "")
|
|
setEnv(t, "GEOCODER_EMAIL", "")
|
|
|
|
cfg := Load()
|
|
if cfg.GeocoderURL != "https://nominatim.openstreetmap.org" {
|
|
t.Errorf("GeocoderURL default = %q, want the Nominatim host", cfg.GeocoderURL)
|
|
}
|
|
if cfg.GeocoderEmail != "" {
|
|
t.Errorf("GeocoderEmail default = %q, want empty", cfg.GeocoderEmail)
|
|
}
|
|
|
|
setEnv(t, "GEOCODER_URL", "https://nominatim.internal")
|
|
setEnv(t, "GEOCODER_EMAIL", "ops@doormile.com")
|
|
|
|
cfg = Load()
|
|
if cfg.GeocoderURL != "https://nominatim.internal" {
|
|
t.Errorf("GEOCODER_URL was not read: got %q", cfg.GeocoderURL)
|
|
}
|
|
if cfg.GeocoderEmail != "ops@doormile.com" {
|
|
t.Errorf("GEOCODER_EMAIL was not read: got %q", cfg.GeocoderEmail)
|
|
}
|
|
}
|
|
|
|
// Every env key the service reads must actually take effect. A typo in the key
|
|
// name means the override is ignored and the default is used — which is how a
|
|
// deploy silently points at the wrong database.
|
|
func TestEnvironmentOverridesAreRead(t *testing.T) {
|
|
cases := []struct {
|
|
key string
|
|
value string
|
|
read func(*Config) string
|
|
}{
|
|
{"ENV", "production", func(c *Config) string { return c.Env }},
|
|
{"APP_PORT", "9999", func(c *Config) string { return c.Port }},
|
|
{"DB_HOST", "db.internal", func(c *Config) string { return c.DBHost }},
|
|
{"DB_NAME", "logistics_staging", func(c *Config) string { return c.DBName }},
|
|
{"DB_PORT", "6543", func(c *Config) string { return c.DBPort }},
|
|
{"REDIS_HOST", "redis.internal", func(c *Config) string { return c.RedisHost }},
|
|
{"JWT_SECRET_KEY", "a-different-secret", func(c *Config) string { return c.JWTSecret }},
|
|
{"TRUSTED_PROXIES", "10.0.0.0/8", func(c *Config) string { return c.TrustedProxies }},
|
|
{"AI_LAYER_BASE_URL", "http://ai.internal", func(c *Config) string { return c.AILayerBaseURL }},
|
|
{"ROUTE_OPTIMIZER_URL", "http://routes.internal", func(c *Config) string { return c.RouteOptimizerURL }},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
setEnv(t, tc.key, tc.value)
|
|
if got := tc.read(Load()); got != tc.value {
|
|
t.Errorf("%s set to %q but Load() read %q", tc.key, tc.value, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
// An empty env var must fall through to the default rather than blanking the
|
|
// setting — an empty DB host is a service that cannot start with no clue why.
|
|
func TestEmptyEnvFallsBackToTheDefault(t *testing.T) {
|
|
setEnv(t, "DB_NAME", "")
|
|
if got := Load().DBName; got == "" {
|
|
t.Error("DBName is empty when DB_NAME is unset; a default is required")
|
|
}
|
|
}
|