Files
memby/server/internal/config/config_test.go
2026-08-28 23:00:02 +12:00

183 lines
5.3 KiB
Go

package config
import (
"net/netip"
"os"
"path/filepath"
"testing"
"time"
"github.com/ponzischeme89/memby/server/internal/emby"
)
func TestReleasePublishTokenCanComeFromSecretFile(t *testing.T) {
t.Setenv("MEMBY_EMBY_URL", "http://emby")
t.Setenv("MEMBY_DATABASE_URL", "postgres://memby")
t.Setenv("MEMBY_PUBLIC_URL", "https://memby.example")
t.Setenv("MEMBY_RELEASE_PUBLISH_TOKEN", "legacy-environment-value")
path := filepath.Join(t.TempDir(), "release-token")
if err := os.WriteFile(path, []byte("file-backed-token\n"), 0o600); err != nil {
t.Fatal(err)
}
t.Setenv("MEMBY_RELEASE_PUBLISH_TOKEN_FILE", path)
cfg, err := Load()
if err != nil {
t.Fatal(err)
}
if cfg.ReleasePublishToken != "file-backed-token" {
t.Fatalf("release token = %q, want the file-backed value", cfg.ReleasePublishToken)
}
}
func TestConfiguredReleaseSecretFileMustBeReadable(t *testing.T) {
t.Setenv("MEMBY_EMBY_URL", "http://emby")
t.Setenv("MEMBY_DATABASE_URL", "postgres://memby")
t.Setenv("MEMBY_RELEASE_PUBLISH_TOKEN_FILE", filepath.Join(t.TempDir(), "missing"))
if _, err := Load(); err == nil {
t.Fatal("expected a missing release token secret to fail")
}
}
func TestTracearrURLAndKeyMustBeConfiguredTogether(t *testing.T) {
t.Setenv("MEMBY_EMBY_URL", "http://emby")
t.Setenv("MEMBY_DATABASE_URL", "postgres://memby")
t.Setenv("MEMBY_TRACEARR_URL", "http://tracearr")
t.Setenv("MEMBY_TRACEARR_API_KEY", "")
if _, err := Load(); err == nil {
t.Fatal("expected incomplete Tracearr configuration to fail")
}
}
func TestRadarrURLAndKeyMustBeConfiguredTogether(t *testing.T) {
t.Setenv("MEMBY_EMBY_URL", "http://emby")
t.Setenv("MEMBY_DATABASE_URL", "postgres://memby")
t.Setenv("MEMBY_RADARR_URL", "http://radarr")
t.Setenv("MEMBY_RADARR_API_KEY", "")
if _, err := Load(); err == nil {
t.Fatal("expected incomplete Radarr configuration to fail")
}
}
func TestForYouDefaultsToDailyOffPeakRebuild(t *testing.T) {
t.Setenv("MEMBY_EMBY_URL", "http://emby")
t.Setenv("MEMBY_DATABASE_URL", "postgres://memby")
t.Setenv("MEMBY_FOR_YOU_MIN_REBUILD_AGE", "")
t.Setenv("MEMBY_FOR_YOU_REFRESH_INTERVAL", "")
t.Setenv("MEMBY_FOR_YOU_REBUILD_HOUR", "")
cfg, err := Load()
if err != nil {
t.Fatal(err)
}
if cfg.ForYouMinRebuildAge != 24*time.Hour ||
cfg.ForYouRefreshInterval != 24*time.Hour ||
cfg.ForYouRebuildHour != 4 {
t.Fatalf("For You schedule = %v/%v hour %d",
cfg.ForYouMinRebuildAge, cfg.ForYouRefreshInterval, cfg.ForYouRebuildHour)
}
}
func TestForYouRebuildHourIsValidated(t *testing.T) {
t.Setenv("MEMBY_EMBY_URL", "http://emby")
t.Setenv("MEMBY_DATABASE_URL", "postgres://memby")
t.Setenv("MEMBY_FOR_YOU_REBUILD_HOUR", "24")
if _, err := Load(); err == nil {
t.Fatal("expected invalid rebuild hour to fail")
}
}
func TestTrustedProxiesDefaultToLoopbackAndPrivateRanges(t *testing.T) {
t.Setenv("MEMBY_EMBY_URL", "http://emby")
t.Setenv("MEMBY_DATABASE_URL", "postgres://memby")
t.Setenv("MEMBY_TRUSTED_PROXIES", "")
cfg, err := Load()
if err != nil {
t.Fatal(err)
}
trusts := func(ip string) bool {
addr := netip.MustParseAddr(ip)
for _, prefix := range cfg.TrustedProxies {
if prefix.Contains(addr) {
return true
}
}
return false
}
for _, want := range []string{"127.0.0.1", "10.0.0.2", "192.168.1.5"} {
if !trusts(want) {
t.Fatalf("%s should be trusted by default", want)
}
}
if trusts("203.0.113.9") {
t.Fatal("a public address must not be trusted by default")
}
}
func TestTrustedProxiesNoneClearsTheList(t *testing.T) {
t.Setenv("MEMBY_EMBY_URL", "http://emby")
t.Setenv("MEMBY_DATABASE_URL", "postgres://memby")
t.Setenv("MEMBY_TRUSTED_PROXIES", "none")
cfg, err := Load()
if err != nil {
t.Fatal(err)
}
if cfg.TrustedProxies == nil || len(cfg.TrustedProxies) != 0 {
t.Fatalf("trusted proxies = %v, want an empty non-nil list", cfg.TrustedProxies)
}
}
func TestTrustedProxiesRejectGarbage(t *testing.T) {
t.Setenv("MEMBY_EMBY_URL", "http://emby")
t.Setenv("MEMBY_DATABASE_URL", "postgres://memby")
t.Setenv("MEMBY_TRUSTED_PROXIES", "10.0.0.0/8, not-an-address")
if _, err := Load(); err == nil {
t.Fatal("expected an unparseable trusted proxy entry to fail")
}
}
func TestRecommendationWeightsMustBeJSON(t *testing.T) {
t.Setenv("MEMBY_EMBY_URL", "http://emby")
t.Setenv("MEMBY_DATABASE_URL", "postgres://memby")
t.Setenv("MEMBY_RECOMMENDATION_WEIGHTS", "{broken")
if _, err := Load(); err == nil {
t.Fatal("expected invalid recommendation weights to fail")
}
}
func TestAnalyticsRetentionCannotDropBelowThirtyDays(t *testing.T) {
t.Setenv("MEMBY_EMBY_URL", "http://emby")
t.Setenv("MEMBY_DATABASE_URL", "postgres://memby")
t.Setenv("MEMBY_ANALYTICS_RETENTION", "168h")
cfg, err := Load()
if err != nil {
t.Fatal(err)
}
if cfg.AnalyticsRetention != 30*24*time.Hour {
t.Fatalf("analytics retention = %v, want 30 days", cfg.AnalyticsRetention)
}
}
func TestLegacyClientNameOverrideIsIgnored(t *testing.T) {
t.Setenv("MEMBY_EMBY_URL", "http://emby")
t.Setenv("MEMBY_DATABASE_URL", "postgres://memby")
t.Setenv("MEMBY_CLIENT_NAME", "Memby")
cfg, err := Load()
if err != nil {
t.Fatal(err)
}
if cfg.ClientName != emby.DefaultClientName {
t.Fatalf("client name = %q, want %q", cfg.ClientName, emby.DefaultClientName)
}
if cfg.IgnoredClientName != "Memby" {
t.Fatalf("ignored client name = %q, want Memby", cfg.IgnoredClientName)
}
}