nub/internal/config/load_test.go
Tom a97013d876 initial commit
- v 0.1.0 siehe CHANGELOG.md
2026-07-25 11:08:01 +02:00

154 lines
3.6 KiB
Go

package config
import (
"os"
"path/filepath"
"testing"
)
func writeConfig(t *testing.T, path, content string) {
t.Helper()
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
t.Fatal(err)
}
}
func TestLoad_LayerPrecedence_RepoOverridesHome(t *testing.T) {
home := t.TempDir()
repo := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("XDG_CONFIG_HOME", "") // macOS UserHomeDir ignores this, aber sauber halten
t.Setenv("NUB_MODEL", "")
t.Setenv("NUB_BASE_URL", "")
t.Setenv("NUB_API_KEY", "")
t.Setenv("OPENAI_API_KEY", "")
writeConfig(t, filepath.Join(home, ".config", "nub", "config.toml"), `
version = 1
[model]
default = "from-home"
endpoint = "openai"
`)
writeConfig(t, filepath.Join(repo, ".nub", "config.toml"), `
version = 1
[model]
default = "from-repo"
endpoint = "openai"
`)
cfg, err := Load(repo)
if err != nil {
t.Fatal(err)
}
if cfg.Model.Default != "from-repo" {
t.Errorf("model.default = %q, want from-repo (repo layer must win over home)", cfg.Model.Default)
}
}
func TestLoad_EnvOverridesFiles(t *testing.T) {
home := t.TempDir()
repo := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("NUB_MODEL", "from-env")
t.Setenv("NUB_BASE_URL", "")
t.Setenv("NUB_API_KEY", "")
t.Setenv("OPENAI_API_KEY", "")
writeConfig(t, filepath.Join(repo, ".nub", "config.toml"), `
version = 1
[model]
default = "from-repo"
endpoint = "openai"
`)
cfg, err := Load(repo)
if err != nil {
t.Fatal(err)
}
if cfg.Model.Default != "from-env" {
t.Errorf("model.default = %q, want from-env (env must win over repo file)", cfg.Model.Default)
}
}
func TestLoad_DefaultsApplyWithoutAnyConfigFile(t *testing.T) {
home := t.TempDir()
repo := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("NUB_MODEL", "")
t.Setenv("NUB_BASE_URL", "")
t.Setenv("NUB_API_KEY", "")
t.Setenv("OPENAI_API_KEY", "")
cfg, err := Load(repo)
if err != nil {
t.Fatal(err)
}
if cfg.Model.Default != "gpt-4o" {
t.Errorf("model.default = %q, want default gpt-4o", cfg.Model.Default)
}
if len(cfg.Context.Files) != 2 {
t.Errorf("context.files = %v, want 2 defaults", cfg.Context.Files)
}
}
func TestLoad_RejectsUnsupportedVersion(t *testing.T) {
home := t.TempDir()
repo := t.TempDir()
t.Setenv("HOME", home)
writeConfig(t, filepath.Join(repo, ".nub", "config.toml"), `version = 2`)
if _, err := Load(repo); err == nil {
t.Fatal("expected error for unsupported config version")
}
}
func TestResolve_EnvKeyIndirection(t *testing.T) {
t.Setenv("MY_TEST_KEY", "sk-secret")
cfg := Defaults()
cfg.Endpoints[0].APIKey = "env:MY_TEST_KEY"
resolved, err := Resolve(cfg)
if err != nil {
t.Fatal(err)
}
if resolved.APIKey != "sk-secret" {
t.Errorf("api key = %q, want sk-secret", resolved.APIKey)
}
}
func TestResolve_MissingKeyOnRemoteEndpointErrors(t *testing.T) {
t.Setenv("OPENAI_API_KEY", "")
cfg := Defaults()
cfg.Endpoints[0].APIKey = "env:DOES_NOT_EXIST_ENV_VAR"
if _, err := Resolve(cfg); err == nil {
t.Fatal("expected error for missing API key on non-local endpoint")
}
}
func TestResolve_LocalEndpointWithoutKeyIsFine(t *testing.T) {
cfg := Defaults()
cfg.Endpoints[0].BaseURL = "http://localhost:11434/v1"
cfg.Endpoints[0].APIKey = "none"
resolved, err := Resolve(cfg)
if err != nil {
t.Fatal(err)
}
if resolved.APIKey != "" {
t.Errorf("api key = %q, want empty for local endpoint", resolved.APIKey)
}
}
func TestResolve_UnknownEndpointErrors(t *testing.T) {
cfg := Defaults()
cfg.Model.Endpoint = "does-not-exist"
if _, err := Resolve(cfg); err == nil {
t.Fatal("expected error for unknown model.endpoint reference")
}
}