OLLAMA_URL and COMFY_URL no longer have defaults; each consumer (listener, client, startup probe, lock participation) is enabled by setting its URL and disabled by leaving it empty. At least one must be set. Ollama-only mode is a pure pass-through; ComfyUI-only mode skips the unload and warm-reload steps. /metrics is now served on both listeners. This is the extension pattern for future consumers such as local game detection.
119 lines
2.9 KiB
Go
119 lines
2.9 KiB
Go
package config
|
|
|
|
import (
|
|
"log/slog"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestDefaults(t *testing.T) {
|
|
cfg, err := Load(func(k string) string {
|
|
if k == "OLLAMA_URL" {
|
|
return "http://127.0.0.1:11435"
|
|
}
|
|
return ""
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if cfg.ListenOllama != ":11434" || cfg.ListenComfy != ":8188" {
|
|
t.Fatalf("listen addrs = %s %s", cfg.ListenOllama, cfg.ListenComfy)
|
|
}
|
|
if cfg.ComfyURL != "" {
|
|
t.Fatalf("ComfyURL default = %q, want empty (disabled)", cfg.ComfyURL)
|
|
}
|
|
if cfg.UnloadTimeout != time.Minute || cfg.JobTimeout != 15*time.Minute {
|
|
t.Fatalf("timeouts = %v %v", cfg.UnloadTimeout, cfg.JobTimeout)
|
|
}
|
|
if !cfg.AutoUpdate || cfg.UpdateInterval != 6*time.Hour {
|
|
t.Fatalf("update = %v %v", cfg.AutoUpdate, cfg.UpdateInterval)
|
|
}
|
|
if cfg.LogLevel != slog.LevelWarn {
|
|
t.Fatalf("log level = %v", cfg.LogLevel)
|
|
}
|
|
}
|
|
|
|
func TestLoadRequiresConsumer(t *testing.T) {
|
|
_, err := Load(func(string) string { return "" })
|
|
if err == nil || !strings.Contains(err.Error(), "OLLAMA_URL") {
|
|
t.Fatalf("err = %v, want missing-consumer error", err)
|
|
}
|
|
}
|
|
|
|
func TestParseEnvFile(t *testing.T) {
|
|
input := `# comment
|
|
OLLAMA_URL=http://host:11435
|
|
|
|
LOGLEVEL=debug
|
|
SPACED = value with spaces
|
|
`
|
|
values, err := ParseEnvFile(strings.NewReader(input))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if values["OLLAMA_URL"] != "http://host:11435" {
|
|
t.Fatalf("OLLAMA_URL = %q", values["OLLAMA_URL"])
|
|
}
|
|
if values["LOGLEVEL"] != "debug" {
|
|
t.Fatalf("LOGLEVEL = %q", values["LOGLEVEL"])
|
|
}
|
|
if values["SPACED"] != "value with spaces" {
|
|
t.Fatalf("SPACED = %q", values["SPACED"])
|
|
}
|
|
}
|
|
|
|
func TestParseEnvFileMalformed(t *testing.T) {
|
|
_, err := ParseEnvFile(strings.NewReader("OK=1\nNOT_A_PAIR\n"))
|
|
if err == nil || !strings.Contains(err.Error(), "line 2") {
|
|
t.Fatalf("err = %v, want line 2 error", err)
|
|
}
|
|
}
|
|
|
|
func TestEnvOverridesFile(t *testing.T) {
|
|
file := map[string]string{"OLLAMA_URL": "http://file:1", "UNLOAD_TIMEOUT": "42s"}
|
|
env := map[string]string{"OLLAMA_URL": "http://env:2"}
|
|
getenv := func(k string) string {
|
|
if v := env[k]; v != "" {
|
|
return v
|
|
}
|
|
return file[k]
|
|
}
|
|
cfg, err := Load(getenv)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if cfg.OllamaURL != "http://env:2" {
|
|
t.Fatalf("OllamaURL = %q, want env value", cfg.OllamaURL)
|
|
}
|
|
if cfg.UnloadTimeout != 42*time.Second {
|
|
t.Fatalf("UnloadTimeout = %v, want file value", cfg.UnloadTimeout)
|
|
}
|
|
}
|
|
|
|
func TestLoadErrors(t *testing.T) {
|
|
for _, tc := range []struct{ key, value string }{
|
|
{"UNLOAD_TIMEOUT", "bogus"},
|
|
{"PROMPT_CAPTURE_LIMIT", "-5"},
|
|
{"AUTO_UPDATE", "maybe"},
|
|
{"LOGLEVEL", "shouty"},
|
|
{"LOG_FORMAT", "yaml"},
|
|
{"LLM_BUSY_MODE", "bogus"},
|
|
{"LLM_BUSY_STATUS", "200"},
|
|
{"BUSY_RETRY_AFTER", "0"},
|
|
} {
|
|
_, err := Load(func(k string) string {
|
|
if k == tc.key {
|
|
return tc.value
|
|
}
|
|
if k == "OLLAMA_URL" {
|
|
return "http://127.0.0.1:11435"
|
|
}
|
|
return ""
|
|
})
|
|
if err == nil {
|
|
t.Errorf("%s=%s: expected error", tc.key, tc.value)
|
|
}
|
|
}
|
|
}
|