Vellum/internal/core/config_test.go
mithral eb1ad6d920 Phase 0: skeleton, config, migrations, health check, container
Bootstraps Vellum as a single Go binary with one SQLite database.

- core: env-driven config, slog logging, SQLite (WAL) with pooled pragmas,
  embedded migration runner keyed on PRAGMA user_version
- migrations/0001_core.sql: identity, media, user state, infra. Media items
  are global; all per-user state (progress, favorites, grants) is a join.
  One polymorphic progress table covers every media kind.
- httpapi: request-ID, structured request logging, panic recovery, JSON
  endpoints for /healthz and /api/v1/version
- multi-arch Dockerfile (pure-Go SQLite, CGO_ENABLED=0) with an entrypoint
  that honours PUID/PGID like the rest of the self-hosted stack
- tests for migration idempotency, FK enforcement, WAL, config, middleware

Media does not exist yet. Nothing is exposed beyond health and version.
2026-10-09 16:26:08 -04:00

77 lines
1.9 KiB
Go

package core
import (
"path/filepath"
"strings"
"testing"
)
func TestLoadConfigDefaults(t *testing.T) {
// No environment set: every field should have a usable default.
cfg, err := LoadConfig()
if err != nil {
t.Fatalf("LoadConfig: %v", err)
}
if cfg.Listen != ":7788" {
t.Errorf("Listen = %q, want :7788", cfg.Listen)
}
if !filepath.IsAbs(cfg.DataDir) {
t.Errorf("DataDir = %q, want absolute", cfg.DataDir)
}
if cfg.DBPath != filepath.Join(cfg.DataDir, "vellum.db") {
t.Errorf("DBPath = %q, want <DataDir>/vellum.db", cfg.DBPath)
}
if cfg.LogLevel != "info" {
t.Errorf("LogLevel = %q, want info", cfg.LogLevel)
}
}
func TestLoadConfigFromEnv(t *testing.T) {
t.Setenv("VELLUM_LISTEN", "127.0.0.1:9999")
t.Setenv("VELLUM_DATA_DIR", "/tmp/vellum-data")
t.Setenv("VELLUM_MEDIA_DIRS", "/media/a:/media/b")
t.Setenv("VELLUM_SESSION_TTL", "48h")
cfg, err := LoadConfig()
if err != nil {
t.Fatalf("LoadConfig: %v", err)
}
if cfg.Listen != "127.0.0.1:9999" {
t.Errorf("Listen = %q", cfg.Listen)
}
if cfg.DataDir != "/tmp/vellum-data" {
t.Errorf("DataDir = %q", cfg.DataDir)
}
if len(cfg.MediaDirs) != 2 || cfg.MediaDirs[0] != "/media/a" {
t.Errorf("MediaDirs = %v", cfg.MediaDirs)
}
if cfg.SessionTTL.Hours() != 48 {
t.Errorf("SessionTTL = %v, want 48h", cfg.SessionTTL)
}
}
func TestValidateRejectsMissingMediaDir(t *testing.T) {
cfg := Config{
DataDir: t.TempDir(),
ConfigDir: t.TempDir(),
MediaDirs: []string{"/definitely/not/a/real/path"},
}
err := cfg.Validate()
if err == nil {
t.Fatal("expected error for missing media dir")
}
if !strings.Contains(err.Error(), "/definitely/not/a/real/path") {
t.Errorf("error %q should name the offending path", err)
}
}
func TestValidateCreatesDirs(t *testing.T) {
base := t.TempDir()
cfg := Config{
DataDir: filepath.Join(base, "data"),
ConfigDir: filepath.Join(base, "config"),
}
if err := cfg.Validate(); err != nil {
t.Fatalf("Validate: %v", err)
}
}