package appview import ( "testing" "time" ) func TestParseTokenSubjectMap(t *testing.T) { tokens, err := ParseTokenSubjectMap("tokenA=did:plc:alice, tokenB=*") if err != nil { t.Fatalf("expected no error, got %v", err) } if got := tokens["tokenA"]; got != "did:plc:alice" { t.Fatalf("expected tokenA subject did:plc:alice, got %q", got) } if got := tokens["tokenB"]; got != "*" { t.Fatalf("expected tokenB subject *, got %q", got) } } func TestParseTokenSubjectMapRejectsInvalidMapping(t *testing.T) { if _, err := ParseTokenSubjectMap("missing-separator"); err == nil { t.Fatal("expected invalid mapping error") } } func TestConfigValidateRejectsWildcardCORS(t *testing.T) { cfg := validConfig() cfg.CORSOrigins = []string{"*"} if err := cfg.Validate(); err == nil { t.Fatal("expected wildcard CORS validation error") } } func TestConfigValidateRequiresAuthTokensWhenEnabled(t *testing.T) { cfg := validConfig() cfg.AuthReadTokens = nil cfg.AuthAdminTokens = nil if err := cfg.Validate(); err == nil { t.Fatal("expected auth token validation error") } } func TestConfigValidateAcceptsValidConfig(t *testing.T) { cfg := validConfig() if err := cfg.Validate(); err != nil { t.Fatalf("expected valid config, got %v", err) } } func TestConfigValidateRejectsMissingOpenConns(t *testing.T) { cfg := validConfig() cfg.DBMaxOpenConns = 0 if err := cfg.Validate(); err == nil { t.Fatal("expected error for zero max-open-conns") } } func TestConfigValidateRejectsIdleAboveOpen(t *testing.T) { cfg := validConfig() cfg.DBMaxIdleConns = cfg.DBMaxOpenConns + 1 if err := cfg.Validate(); err == nil { t.Fatal("expected error when idle exceeds open") } } func TestConfigValidateRejectsNegativeLifetime(t *testing.T) { cfg := validConfig() cfg.DBConnMaxLifetime = -1 if err := cfg.Validate(); err == nil { t.Fatal("expected error for negative lifetime") } } func validConfig() Config { return Config{ Bind: ":8080", DatabaseURL: "postgres://effem:effem@localhost:5432/effem?sslmode=disable", DBMaxOpenConns: 25, DBMaxIdleConns: 5, DBConnMaxLifetime: 5 * time.Minute, DBConnMaxIdleTime: 5 * time.Minute, RelayHost: "wss://bsky.network", PLCHost: "https://plc.directory", PIKey: "key", PISecret: "secret", FirehoseParallel: 5, FirehoseQueueLimit: 256, AuthRequired: true, AuthReadTokens: map[string]string{"token": "did:plc:alice"}, AuthAdminTokens: map[string]string{}, CORSOrigins: []string{"https://app.effem.xyz"}, RateLimitEnabled: true, RateLimitRPS: 5, RateLimitBurst: 20, } }