zzet--gortex
a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
196 行
5.5 KiB
Go
196 行
5.5 KiB
Go
package registry
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/zzet/gortex/internal/llm"
|
|
)
|
|
|
|
// isolate points the global providers.json at a temp config dir so the
|
|
// registry never touches the developer's real ~/.gortex.
|
|
func isolate(t *testing.T) {
|
|
t.Helper()
|
|
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
|
t.Setenv(LocalOptInEnv, "")
|
|
}
|
|
|
|
func TestAdd_List_Get_Remove(t *testing.T) {
|
|
isolate(t)
|
|
|
|
if err := Add("groq", llm.CustomProvider{BaseURL: "https://api.groq.com/openai/v1", Model: "llama-3.3-70b", APIKeyEnv: "GROQ_API_KEY"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := Add("local-vllm", llm.CustomProvider{BaseURL: "http://localhost:8000/v1", Model: "qwen"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
entries, err := List()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(entries) != 2 {
|
|
t.Fatalf("expected 2 entries, got %d", len(entries))
|
|
}
|
|
// List is sorted by name.
|
|
if entries[0].Name != "groq" || entries[1].Name != "local-vllm" {
|
|
t.Errorf("entries not sorted: %v", entries)
|
|
}
|
|
|
|
cp, ok, err := Get("groq")
|
|
if err != nil || !ok {
|
|
t.Fatalf("Get groq: ok=%v err=%v", ok, err)
|
|
}
|
|
if cp.Model != "llama-3.3-70b" {
|
|
t.Errorf("model=%q", cp.Model)
|
|
}
|
|
|
|
removed, err := Remove("groq")
|
|
if err != nil || !removed {
|
|
t.Fatalf("Remove groq: removed=%v err=%v", removed, err)
|
|
}
|
|
if _, ok, _ := Get("groq"); ok {
|
|
t.Error("groq should be gone after remove")
|
|
}
|
|
if removed, _ := Remove("groq"); removed {
|
|
t.Error("removing an absent provider should report removed=false")
|
|
}
|
|
}
|
|
|
|
func TestAdd_RejectsBuiltinShadow(t *testing.T) {
|
|
isolate(t)
|
|
if err := Add("openai", llm.CustomProvider{BaseURL: "https://x/v1", Model: "m"}); err == nil {
|
|
t.Fatal("expected an error when shadowing a built-in provider")
|
|
}
|
|
}
|
|
|
|
func TestAdd_RejectsBadSchemeAndMissingFields(t *testing.T) {
|
|
isolate(t)
|
|
cases := map[string]llm.CustomProvider{
|
|
"bad scheme": {BaseURL: "ftp://x/v1", Model: "m"},
|
|
"no base_url": {Model: "m"},
|
|
"no model": {BaseURL: "https://x/v1"},
|
|
"bad schema": {BaseURL: "https://x/v1", Model: "m", SchemaMode: "wat"},
|
|
}
|
|
for name, cp := range cases {
|
|
t.Run(name, func(t *testing.T) {
|
|
if err := Add("custom", cp); err == nil {
|
|
t.Errorf("expected an error for %s", name)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLoad_SkipsInvalidEntriesWithWarning(t *testing.T) {
|
|
isolate(t)
|
|
// Write a providers.json by hand with one valid and one shadowing
|
|
// (invalid) entry.
|
|
dir := filepath.Dir(GlobalPath())
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
body := `{
|
|
"good": {"base_url": "https://api.example.com/v1", "model": "m"},
|
|
"openai": {"base_url": "https://evil/v1", "model": "m"}
|
|
}`
|
|
if err := os.WriteFile(GlobalPath(), []byte(body), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
providers, warnings, err := Load()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, ok := providers["good"]; !ok {
|
|
t.Error("valid entry should load")
|
|
}
|
|
if _, ok := providers["openai"]; ok {
|
|
t.Error("an entry shadowing a built-in must be skipped")
|
|
}
|
|
if len(warnings) == 0 {
|
|
t.Error("expected a warning for the skipped entry")
|
|
}
|
|
}
|
|
|
|
func TestAugment_FileFillsConfig_InlineWins(t *testing.T) {
|
|
isolate(t)
|
|
if err := Add("fromfile", llm.CustomProvider{BaseURL: "https://file/v1", Model: "file-model"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := Add("shared", llm.CustomProvider{BaseURL: "https://file/v1", Model: "file-shared"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
cfg := llm.Config{Custom: map[string]llm.CustomProvider{
|
|
"shared": {BaseURL: "https://inline/v1", Model: "inline-shared"},
|
|
"inline": {BaseURL: "https://inline/v1", Model: "inline-only"},
|
|
}}
|
|
got, _ := Augment(cfg)
|
|
if got.Custom["fromfile"].Model != "file-model" {
|
|
t.Error("file-only provider should be merged in")
|
|
}
|
|
if got.Custom["inline"].Model != "inline-only" {
|
|
t.Error("inline-only provider should survive")
|
|
}
|
|
if got.Custom["shared"].Model != "inline-shared" {
|
|
t.Errorf("inline must win for a name in both, got %q", got.Custom["shared"].Model)
|
|
}
|
|
}
|
|
|
|
func TestLoad_LocalOptIn(t *testing.T) {
|
|
isolate(t)
|
|
dir := t.TempDir()
|
|
t.Chdir(dir)
|
|
localDir := filepath.Join(dir, ".gortex")
|
|
if err := os.MkdirAll(localDir, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
body := `{"repolocal": {"base_url": "https://repo/v1", "model": "m"}}`
|
|
if err := os.WriteFile(filepath.Join(localDir, "providers.json"), []byte(body), 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Without the opt-in env, the repo-local file is ignored.
|
|
providers, _, err := Load()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, ok := providers["repolocal"]; ok {
|
|
t.Error("repo-local providers must not load without the opt-in env")
|
|
}
|
|
|
|
// With the opt-in env set, it loads.
|
|
t.Setenv(LocalOptInEnv, "1")
|
|
providers, _, err = Load()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, ok := providers["repolocal"]; !ok {
|
|
t.Error("repo-local provider should load with GORTEX_ALLOW_LOCAL_PROVIDERS=1")
|
|
}
|
|
}
|
|
|
|
func TestEstimateCost(t *testing.T) {
|
|
cp := llm.CustomProvider{Pricing: llm.ProviderPricing{Input: 3.0, Output: 15.0}}
|
|
// 1M input + 1M output = $3 + $15 = $18.
|
|
if got := EstimateCost(cp, 1_000_000, 1_000_000); got != 18.0 {
|
|
t.Errorf("EstimateCost=%v want 18", got)
|
|
}
|
|
if got := EstimateCost(llm.CustomProvider{}, 1_000_000, 1_000_000); got != 0 {
|
|
t.Errorf("zero pricing should yield zero cost, got %v", got)
|
|
}
|
|
}
|
|
|
|
func TestLoad_PlaintextHTTPWarning(t *testing.T) {
|
|
isolate(t)
|
|
if err := Add("insecure", llm.CustomProvider{BaseURL: "http://remote.example.com/v1", Model: "m"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, warnings, err := Load()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(warnings) == 0 {
|
|
t.Error("expected a cleartext-http warning for a non-loopback host")
|
|
}
|
|
}
|