154 lines
3.6 KiB
Go
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")
|
|
}
|
|
}
|