package backend_test import ( "errors" "strings" "testing" "gitea.maximumdirect.net/eric/promptkit/internal/backend" "gitea.maximumdirect.net/eric/promptkit/internal/domain" ) const validEndpoint = "https://backend.example/v1" func TestRegistryIncludesExactBuiltInDefinitions(t *testing.T) { registry, err := backend.NewRegistry(nil) if err != nil { t.Fatalf("construct registry: %v", err) } tests := []struct { name string id string endpoint string apiKeyEnv string concurrent int }{ { name: "OpenRouter", id: backend.OpenRouterID, endpoint: "https://openrouter.ai/api/v1", apiKeyEnv: "OPENROUTER_API_KEY", concurrent: 16, }, { name: "Rakestrawhome", id: backend.RakestrawHomeID, endpoint: "https://inference.ai.rakestrawhome.com/v1", apiKeyEnv: "RAKESTRAWHOME_INFERENCE_API_KEY", concurrent: 4, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { definition, err := registry.GetBackend(tc.id) if err != nil { t.Fatalf("look up built-in: %v", err) } if definition.ID != tc.id || definition.Endpoint != tc.endpoint || definition.APIKeyEnv != tc.apiKeyEnv || definition.ConcurrencyLimit != tc.concurrent || definition.QueueCapacity != 1024 || !definition.QueueCapacitySet || definition.ExtraParams != nil { t.Fatalf("unexpected built-in definition: %#v", definition) } }) } policies := registry.CapacityPolicies() if len(policies) != 2 || policies[backend.OpenRouterID] != (domain.BackendCapacityPolicy{ ConcurrencyLimit: 16, QueueCapacity: 1024, }) || policies[backend.RakestrawHomeID] != (domain.BackendCapacityPolicy{ ConcurrencyLimit: 4, QueueCapacity: 1024, }) { t.Fatalf("unexpected built-in capacity policies: %#v", policies) } } func TestRegistryNormalizesUniqueAdditionsAndIsolatesMutations(t *testing.T) { nested := map[string]int{"limit": 2} extraParams := map[string]any{ "count": int64(7), "nested": nested, } registry, err := backend.NewRegistry([]domain.Backend{ { ID: " custom ", Endpoint: " https://custom.example/openai/v1 ", APIKeyEnv: " CUSTOM_API_KEY ", ExtraParams: extraParams, ConcurrencyLimit: 3, QueueCapacity: 2, QueueCapacitySet: true, }, { ID: "Custom", Endpoint: validEndpoint, }, }) if err != nil { t.Fatalf("construct registry: %v", err) } nested["limit"] = 99 extraParams["added"] = true got, err := registry.GetBackend("custom") if err != nil { t.Fatalf("look up custom backend: %v", err) } if got.ID != "custom" || got.Endpoint != "https://custom.example/openai/v1" || got.APIKeyEnv != "CUSTOM_API_KEY" || got.ConcurrencyLimit != 3 || got.QueueCapacity != 2 || !got.QueueCapacitySet { t.Fatalf("unexpected normalized definition: %#v", got) } if count, ok := got.ExtraParams["count"].(int64); !ok || count != 7 { t.Fatalf("integer type or value changed: %#v", got.ExtraParams["count"]) } gotNested, ok := got.ExtraParams["nested"].(map[string]int) if !ok || gotNested["limit"] != 2 { t.Fatalf("container type or value changed: %#v", got.ExtraParams["nested"]) } if _, exists := got.ExtraParams["added"]; exists { t.Fatalf("registry retained caller map: %#v", got.ExtraParams) } gotNested["limit"] = 100 got.ExtraParams["added"] = true again, err := registry.GetBackend("custom") if err != nil { t.Fatalf("look up custom backend again: %v", err) } if again.ExtraParams["nested"].(map[string]int)["limit"] != 2 { t.Fatalf("lookup exposed registry nested map: %#v", again.ExtraParams) } if _, exists := again.ExtraParams["added"]; exists { t.Fatalf("lookup exposed registry map: %#v", again.ExtraParams) } if _, err := registry.GetBackend("Custom"); err != nil { t.Fatalf("backend IDs should be case-sensitive: %v", err) } policies := registry.CapacityPolicies() if len(policies) != 3 { t.Fatalf("unexpected capacity policy count: %#v", policies) } policies["custom"] = domain.BackendCapacityPolicy{} delete(policies, backend.OpenRouterID) delete(policies, backend.RakestrawHomeID) againPolicies := registry.CapacityPolicies() if againPolicies["custom"] != (domain.BackendCapacityPolicy{ ConcurrencyLimit: 3, QueueCapacity: 2, }) { t.Fatalf("capacity policy map mutated registry state: %#v", againPolicies) } if _, ok := againPolicies[backend.OpenRouterID]; !ok { t.Fatalf("OpenRouter capacity policy deletion mutated registry state: %#v", againPolicies) } if _, ok := againPolicies[backend.RakestrawHomeID]; !ok { t.Fatalf("Rakestrawhome capacity policy deletion mutated registry state: %#v", againPolicies) } } func TestNewRegistryNormalizesCapacityPolicy(t *testing.T) { maxInt := int(^uint(0) >> 1) tests := []struct { name string definition domain.Backend want domain.BackendCapacityPolicy wantSet bool wantError bool }{ { name: "unlimited when omitted", definition: domain.Backend{}, }, { name: "default queue", definition: domain.Backend{ ConcurrencyLimit: 2, }, want: domain.BackendCapacityPolicy{ ConcurrencyLimit: 2, QueueCapacity: 1024, }, wantSet: true, }, { name: "explicit zero queue", definition: domain.Backend{ ConcurrencyLimit: 2, QueueCapacitySet: true, }, want: domain.BackendCapacityPolicy{ ConcurrencyLimit: 2, }, wantSet: true, }, { name: "negative concurrency limit", definition: domain.Backend{ ConcurrencyLimit: -1, }, wantError: true, }, { name: "negative queue capacity", definition: domain.Backend{ ConcurrencyLimit: 1, QueueCapacity: -1, QueueCapacitySet: true, }, wantError: true, }, { name: "queue without limit", definition: domain.Backend{ QueueCapacitySet: true, }, wantError: true, }, { name: "total overflow", definition: domain.Backend{ ConcurrencyLimit: maxInt, QueueCapacity: 1, QueueCapacitySet: true, }, wantError: true, }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { tc.definition.ID = "custom" tc.definition.Endpoint = validEndpoint registry, err := backend.NewRegistry([]domain.Backend{tc.definition}) if tc.wantError { if err == nil { t.Fatal("expected invalid capacity policy error") } return } if err != nil { t.Fatalf("construct registry: %v", err) } definition, err := registry.GetBackend("custom") if err != nil { t.Fatalf("look up custom backend: %v", err) } if definition.ConcurrencyLimit != tc.want.ConcurrencyLimit || definition.QueueCapacity != tc.want.QueueCapacity || definition.QueueCapacitySet != tc.wantSet { t.Fatalf("normalized capacity=(%d, %d, %t), want (%d, %d, %t)", definition.ConcurrencyLimit, definition.QueueCapacity, definition.QueueCapacitySet, tc.want.ConcurrencyLimit, tc.want.QueueCapacity, tc.wantSet, ) } policies := registry.CapacityPolicies() got, ok := policies["custom"] if ok != tc.wantSet || got != tc.want { t.Fatalf("capacity policy=(%#v, %t), want (%#v, %t)", got, ok, tc.want, tc.wantSet) } }) } } func TestNewRegistryRejectsDuplicateIDs(t *testing.T) { tests := []struct { name string additions []domain.Backend wantID string }{ { name: "OpenRouter collision after normalization", additions: []domain.Backend{{ID: " openrouter "}}, wantID: backend.OpenRouterID, }, { name: "Rakestrawhome collision after normalization", additions: []domain.Backend{{ID: " rakestrawhome "}}, wantID: backend.RakestrawHomeID, }, { name: "consumer collision after normalization", additions: []domain.Backend{ {ID: "custom", Endpoint: validEndpoint}, {ID: " custom ", Endpoint: "https://other.example/v1"}, }, wantID: "custom", }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { _, err := backend.NewRegistry(tc.additions) if err == nil { t.Fatal("expected duplicate ID error") } if !strings.Contains(err.Error(), tc.wantID) { t.Fatalf("expected error to identify %q, got %v", tc.wantID, err) } }) } } func TestNewRegistryValidatesIDs(t *testing.T) { for _, id := range []string{"", " \t\n "} { t.Run(id, func(t *testing.T) { _, err := backend.NewRegistry([]domain.Backend{{ ID: id, Endpoint: validEndpoint, }}) if err == nil { t.Fatal("expected blank ID error") } }) } } func TestNewRegistryValidatesEndpoints(t *testing.T) { tests := []struct { name string endpoint string }{ {name: "blank", endpoint: ""}, {name: "relative", endpoint: "/v1"}, {name: "missing host", endpoint: "https:///v1"}, {name: "unsupported scheme", endpoint: "ftp://backend.example/v1"}, {name: "user information", endpoint: "https://user@backend.example/v1"}, {name: "query", endpoint: "https://backend.example/v1?mode=chat"}, {name: "empty query", endpoint: "https://backend.example/v1?"}, {name: "fragment", endpoint: "https://backend.example/v1#chat"}, {name: "empty fragment", endpoint: "https://backend.example/v1#"}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { _, err := backend.NewRegistry([]domain.Backend{{ ID: "custom", Endpoint: tc.endpoint, }}) if err == nil { t.Fatal("expected invalid endpoint error") } }) } } func TestNewRegistryValidatesEnvironmentVariableNames(t *testing.T) { for _, name := range []string{"1API_KEY", "API-KEY", "API KEY", "ÅPI_KEY"} { t.Run(name, func(t *testing.T) { _, err := backend.NewRegistry([]domain.Backend{{ ID: "custom", Endpoint: validEndpoint, APIKeyEnv: name, }}) if err == nil { t.Fatal("expected invalid environment-variable name error") } }) } } func TestNewRegistryRejectsInvalidAndReservedExtraParameters(t *testing.T) { tests := []struct { name string extraParams map[string]any }{ {name: "unsupported value", extraParams: map[string]any{"value": make(chan int)}}, {name: "reserved key", extraParams: map[string]any{"model": "override"}}, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { _, err := backend.NewRegistry([]domain.Backend{{ ID: "custom", Endpoint: validEndpoint, ExtraParams: tc.extraParams, }}) if err == nil { t.Fatal("expected invalid extra parameters error") } }) } } func TestRegistryLookupReportsNotFound(t *testing.T) { registry, err := backend.NewRegistry(nil) if err != nil { t.Fatalf("construct registry: %v", err) } _, err = registry.GetBackend("missing") if !errors.Is(err, backend.ErrBackendNotFound) { t.Fatalf("expected ErrBackendNotFound, got %v", err) } if !strings.Contains(err.Error(), "missing") { t.Fatalf("expected error to identify backend, got %v", err) } }