251 lines
7.3 KiB
Go
251 lines
7.3 KiB
Go
package management
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/watcher/synthesizer"
|
|
coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
|
|
)
|
|
|
|
func synthesizeConfigAuths(t *testing.T, cfg *config.Config) []*coreauth.Auth {
|
|
t.Helper()
|
|
|
|
auths, errSynthesize := synthesizer.NewConfigSynthesizer().Synthesize(&synthesizer.SynthesisContext{
|
|
Config: cfg,
|
|
Now: time.Unix(0, 0),
|
|
IDGenerator: synthesizer.NewStableIDGenerator(),
|
|
})
|
|
if errSynthesize != nil {
|
|
t.Fatalf("synthesize config auths: %v", errSynthesize)
|
|
}
|
|
return auths
|
|
}
|
|
|
|
func findAuth(t *testing.T, auths []*coreauth.Auth, predicate func(*coreauth.Auth) bool) *coreauth.Auth {
|
|
t.Helper()
|
|
for _, auth := range auths {
|
|
if predicate(auth) {
|
|
return auth
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func TestConfigAuthIndexResolvesLiveIndexes(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cfg := &config.Config{
|
|
GeminiKey: []config.GeminiKey{
|
|
{APIKey: "shared-key", BaseURL: "https://a.example.com"},
|
|
{APIKey: "shared-key", BaseURL: "https://b.example.com"},
|
|
},
|
|
ClaudeKey: []config.ClaudeKey{
|
|
{APIKey: "claude-key", BaseURL: "https://claude.example.com"},
|
|
},
|
|
CodexKey: []config.CodexKey{
|
|
{APIKey: "codex-key", BaseURL: "https://codex.example.com/v1"},
|
|
},
|
|
VertexCompatAPIKey: []config.VertexCompatKey{
|
|
{APIKey: "vertex-key", BaseURL: "https://vertex.example.com", ProxyURL: "http://proxy.example.com:8080"},
|
|
},
|
|
OpenAICompatibility: []config.OpenAICompatibility{
|
|
{
|
|
Name: "bohe",
|
|
BaseURL: "https://bohe.example.com/v1",
|
|
APIKeyEntries: []config.OpenAICompatibilityAPIKey{
|
|
{APIKey: "compat-key"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
auths := synthesizeConfigAuths(t, cfg)
|
|
manager := coreauth.NewManager(nil, nil, nil)
|
|
for _, auth := range auths {
|
|
if auth == nil {
|
|
continue
|
|
}
|
|
if _, errRegister := manager.Register(context.Background(), auth); errRegister != nil {
|
|
t.Fatalf("register auth %q: %v", auth.ID, errRegister)
|
|
}
|
|
}
|
|
|
|
h := &Handler{cfg: cfg, authManager: manager}
|
|
|
|
geminiAuthA := findAuth(t, auths, func(auth *coreauth.Auth) bool {
|
|
if auth == nil {
|
|
return false
|
|
}
|
|
return auth.Provider == "gemini" && auth.Attributes["api_key"] == "shared-key" && auth.Attributes["base_url"] == "https://a.example.com"
|
|
})
|
|
if geminiAuthA == nil {
|
|
t.Fatal("expected synthesized gemini auth (base a)")
|
|
}
|
|
geminiAuthB := findAuth(t, auths, func(auth *coreauth.Auth) bool {
|
|
if auth == nil {
|
|
return false
|
|
}
|
|
return auth.Provider == "gemini" && auth.Attributes["api_key"] == "shared-key" && auth.Attributes["base_url"] == "https://b.example.com"
|
|
})
|
|
if geminiAuthB == nil {
|
|
t.Fatal("expected synthesized gemini auth (base b)")
|
|
}
|
|
|
|
gemini := h.geminiKeysWithAuthIndex()
|
|
if len(gemini) != 2 {
|
|
t.Fatalf("gemini keys = %d, want 2", len(gemini))
|
|
}
|
|
if got, want := gemini[0].AuthIndex, geminiAuthA.EnsureIndex(); got != want {
|
|
t.Fatalf("gemini[0] auth-index = %q, want %q", got, want)
|
|
}
|
|
if got, want := gemini[1].AuthIndex, geminiAuthB.EnsureIndex(); got != want {
|
|
t.Fatalf("gemini[1] auth-index = %q, want %q", got, want)
|
|
}
|
|
if gemini[0].AuthIndex == gemini[1].AuthIndex {
|
|
t.Fatalf("duplicate gemini entries returned the same auth-index %q", gemini[0].AuthIndex)
|
|
}
|
|
|
|
claudeAuth := findAuth(t, auths, func(auth *coreauth.Auth) bool {
|
|
if auth == nil {
|
|
return false
|
|
}
|
|
return auth.Provider == "claude" && auth.Attributes["api_key"] == "claude-key"
|
|
})
|
|
if claudeAuth == nil {
|
|
t.Fatal("expected synthesized claude auth")
|
|
}
|
|
|
|
claude := h.claudeKeysWithAuthIndex()
|
|
if len(claude) != 1 {
|
|
t.Fatalf("claude keys = %d, want 1", len(claude))
|
|
}
|
|
if got, want := claude[0].AuthIndex, claudeAuth.EnsureIndex(); got != want {
|
|
t.Fatalf("claude auth-index = %q, want %q", got, want)
|
|
}
|
|
|
|
codexAuth := findAuth(t, auths, func(auth *coreauth.Auth) bool {
|
|
if auth == nil {
|
|
return false
|
|
}
|
|
return auth.Provider == "codex" && auth.Attributes["api_key"] == "codex-key"
|
|
})
|
|
if codexAuth == nil {
|
|
t.Fatal("expected synthesized codex auth")
|
|
}
|
|
|
|
codex := h.codexKeysWithAuthIndex()
|
|
if len(codex) != 1 {
|
|
t.Fatalf("codex keys = %d, want 1", len(codex))
|
|
}
|
|
if got, want := codex[0].AuthIndex, codexAuth.EnsureIndex(); got != want {
|
|
t.Fatalf("codex auth-index = %q, want %q", got, want)
|
|
}
|
|
|
|
vertexAuth := findAuth(t, auths, func(auth *coreauth.Auth) bool {
|
|
if auth == nil {
|
|
return false
|
|
}
|
|
return auth.Provider == "vertex" && auth.Attributes["api_key"] == "vertex-key"
|
|
})
|
|
if vertexAuth == nil {
|
|
t.Fatal("expected synthesized vertex auth")
|
|
}
|
|
|
|
vertex := h.vertexCompatKeysWithAuthIndex()
|
|
if len(vertex) != 1 {
|
|
t.Fatalf("vertex keys = %d, want 1", len(vertex))
|
|
}
|
|
if got, want := vertex[0].AuthIndex, vertexAuth.EnsureIndex(); got != want {
|
|
t.Fatalf("vertex auth-index = %q, want %q", got, want)
|
|
}
|
|
|
|
compatAuth := findAuth(t, auths, func(auth *coreauth.Auth) bool {
|
|
if auth == nil {
|
|
return false
|
|
}
|
|
if auth.Provider != "bohe" {
|
|
return false
|
|
}
|
|
if auth.Attributes["provider_key"] != "bohe" || auth.Attributes["compat_name"] != "bohe" {
|
|
return false
|
|
}
|
|
return auth.Attributes["api_key"] == "compat-key"
|
|
})
|
|
if compatAuth == nil {
|
|
t.Fatal("expected synthesized openai-compat auth")
|
|
}
|
|
|
|
compat := h.openAICompatibilityWithAuthIndex()
|
|
if len(compat) != 1 {
|
|
t.Fatalf("openai-compat providers = %d, want 1", len(compat))
|
|
}
|
|
if len(compat[0].APIKeyEntries) != 1 {
|
|
t.Fatalf("openai-compat api-key-entries = %d, want 1", len(compat[0].APIKeyEntries))
|
|
}
|
|
if compat[0].AuthIndex != "" {
|
|
t.Fatalf("provider-level auth-index should be empty when api-key-entries exist, got %q", compat[0].AuthIndex)
|
|
}
|
|
if got, want := compat[0].APIKeyEntries[0].AuthIndex, compatAuth.EnsureIndex(); got != want {
|
|
t.Fatalf("openai-compat auth-index = %q, want %q", got, want)
|
|
}
|
|
}
|
|
|
|
func TestConfigAuthIndexOmitsIndexesNotInManager(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
cfg := &config.Config{
|
|
GeminiKey: []config.GeminiKey{
|
|
{APIKey: "gemini-key", BaseURL: "https://a.example.com"},
|
|
},
|
|
OpenAICompatibility: []config.OpenAICompatibility{
|
|
{
|
|
Name: "bohe",
|
|
BaseURL: "https://bohe.example.com/v1",
|
|
APIKeyEntries: []config.OpenAICompatibilityAPIKey{
|
|
{APIKey: "compat-key"},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
auths := synthesizeConfigAuths(t, cfg)
|
|
geminiAuth := findAuth(t, auths, func(auth *coreauth.Auth) bool {
|
|
if auth == nil {
|
|
return false
|
|
}
|
|
return auth.Provider == "gemini" && auth.Attributes["api_key"] == "gemini-key"
|
|
})
|
|
if geminiAuth == nil {
|
|
t.Fatal("expected synthesized gemini auth")
|
|
}
|
|
|
|
manager := coreauth.NewManager(nil, nil, nil)
|
|
if _, errRegister := manager.Register(context.Background(), geminiAuth); errRegister != nil {
|
|
t.Fatalf("register gemini auth: %v", errRegister)
|
|
}
|
|
|
|
h := &Handler{cfg: cfg, authManager: manager}
|
|
|
|
gemini := h.geminiKeysWithAuthIndex()
|
|
if len(gemini) != 1 {
|
|
t.Fatalf("gemini keys = %d, want 1", len(gemini))
|
|
}
|
|
if gemini[0].AuthIndex == "" {
|
|
t.Fatal("expected gemini auth-index to be set")
|
|
}
|
|
|
|
compat := h.openAICompatibilityWithAuthIndex()
|
|
if len(compat) != 1 {
|
|
t.Fatalf("openai-compat providers = %d, want 1", len(compat))
|
|
}
|
|
if len(compat[0].APIKeyEntries) != 1 {
|
|
t.Fatalf("openai-compat api-key-entries = %d, want 1", len(compat[0].APIKeyEntries))
|
|
}
|
|
if compat[0].APIKeyEntries[0].AuthIndex != "" {
|
|
t.Fatalf("openai-compat auth-index = %q, want empty", compat[0].APIKeyEntries[0].AuthIndex)
|
|
}
|
|
}
|