mirror of
https://github.com/router-for-me/CLIProxyAPIPlus.git
synced 2026-04-13 09:44:51 +00:00
Added comprehensive support for resolving proxy URLs from configuration based on API key and provider attributes. Introduced new helper functions and extended the test suite to validate fallback mechanisms and compatibility cases.
213 lines
5.7 KiB
Go
213 lines
5.7 KiB
Go
package management
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
|
coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
|
|
sdkconfig "github.com/router-for-me/CLIProxyAPI/v6/sdk/config"
|
|
)
|
|
|
|
func TestAPICallTransportDirectBypassesGlobalProxy(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
h := &Handler{
|
|
cfg: &config.Config{
|
|
SDKConfig: sdkconfig.SDKConfig{ProxyURL: "http://global-proxy.example.com:8080"},
|
|
},
|
|
}
|
|
|
|
transport := h.apiCallTransport(&coreauth.Auth{ProxyURL: "direct"})
|
|
httpTransport, ok := transport.(*http.Transport)
|
|
if !ok {
|
|
t.Fatalf("transport type = %T, want *http.Transport", transport)
|
|
}
|
|
if httpTransport.Proxy != nil {
|
|
t.Fatal("expected direct transport to disable proxy function")
|
|
}
|
|
}
|
|
|
|
func TestAPICallTransportInvalidAuthFallsBackToGlobalProxy(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
h := &Handler{
|
|
cfg: &config.Config{
|
|
SDKConfig: sdkconfig.SDKConfig{ProxyURL: "http://global-proxy.example.com:8080"},
|
|
},
|
|
}
|
|
|
|
transport := h.apiCallTransport(&coreauth.Auth{ProxyURL: "bad-value"})
|
|
httpTransport, ok := transport.(*http.Transport)
|
|
if !ok {
|
|
t.Fatalf("transport type = %T, want *http.Transport", transport)
|
|
}
|
|
|
|
req, errRequest := http.NewRequest(http.MethodGet, "https://example.com", nil)
|
|
if errRequest != nil {
|
|
t.Fatalf("http.NewRequest returned error: %v", errRequest)
|
|
}
|
|
|
|
proxyURL, errProxy := httpTransport.Proxy(req)
|
|
if errProxy != nil {
|
|
t.Fatalf("httpTransport.Proxy returned error: %v", errProxy)
|
|
}
|
|
if proxyURL == nil || proxyURL.String() != "http://global-proxy.example.com:8080" {
|
|
t.Fatalf("proxy URL = %v, want http://global-proxy.example.com:8080", proxyURL)
|
|
}
|
|
}
|
|
|
|
func TestAPICallTransportAPIKeyAuthFallsBackToConfigProxyURL(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
h := &Handler{
|
|
cfg: &config.Config{
|
|
SDKConfig: sdkconfig.SDKConfig{ProxyURL: "http://global-proxy.example.com:8080"},
|
|
GeminiKey: []config.GeminiKey{{
|
|
APIKey: "gemini-key",
|
|
ProxyURL: "http://gemini-proxy.example.com:8080",
|
|
}},
|
|
ClaudeKey: []config.ClaudeKey{{
|
|
APIKey: "claude-key",
|
|
ProxyURL: "http://claude-proxy.example.com:8080",
|
|
}},
|
|
CodexKey: []config.CodexKey{{
|
|
APIKey: "codex-key",
|
|
ProxyURL: "http://codex-proxy.example.com:8080",
|
|
}},
|
|
OpenAICompatibility: []config.OpenAICompatibility{{
|
|
Name: "bohe",
|
|
BaseURL: "https://bohe.example.com",
|
|
APIKeyEntries: []config.OpenAICompatibilityAPIKey{{
|
|
APIKey: "compat-key",
|
|
ProxyURL: "http://compat-proxy.example.com:8080",
|
|
}},
|
|
}},
|
|
},
|
|
}
|
|
|
|
cases := []struct {
|
|
name string
|
|
auth *coreauth.Auth
|
|
wantProxy string
|
|
}{
|
|
{
|
|
name: "gemini",
|
|
auth: &coreauth.Auth{
|
|
Provider: "gemini",
|
|
Attributes: map[string]string{"api_key": "gemini-key"},
|
|
},
|
|
wantProxy: "http://gemini-proxy.example.com:8080",
|
|
},
|
|
{
|
|
name: "claude",
|
|
auth: &coreauth.Auth{
|
|
Provider: "claude",
|
|
Attributes: map[string]string{"api_key": "claude-key"},
|
|
},
|
|
wantProxy: "http://claude-proxy.example.com:8080",
|
|
},
|
|
{
|
|
name: "codex",
|
|
auth: &coreauth.Auth{
|
|
Provider: "codex",
|
|
Attributes: map[string]string{"api_key": "codex-key"},
|
|
},
|
|
wantProxy: "http://codex-proxy.example.com:8080",
|
|
},
|
|
{
|
|
name: "openai-compatibility",
|
|
auth: &coreauth.Auth{
|
|
Provider: "bohe",
|
|
Attributes: map[string]string{
|
|
"api_key": "compat-key",
|
|
"compat_name": "bohe",
|
|
"provider_key": "bohe",
|
|
},
|
|
},
|
|
wantProxy: "http://compat-proxy.example.com:8080",
|
|
},
|
|
}
|
|
|
|
for _, tc := range cases {
|
|
tc := tc
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
transport := h.apiCallTransport(tc.auth)
|
|
httpTransport, ok := transport.(*http.Transport)
|
|
if !ok {
|
|
t.Fatalf("transport type = %T, want *http.Transport", transport)
|
|
}
|
|
|
|
req, errRequest := http.NewRequest(http.MethodGet, "https://example.com", nil)
|
|
if errRequest != nil {
|
|
t.Fatalf("http.NewRequest returned error: %v", errRequest)
|
|
}
|
|
|
|
proxyURL, errProxy := httpTransport.Proxy(req)
|
|
if errProxy != nil {
|
|
t.Fatalf("httpTransport.Proxy returned error: %v", errProxy)
|
|
}
|
|
if proxyURL == nil || proxyURL.String() != tc.wantProxy {
|
|
t.Fatalf("proxy URL = %v, want %s", proxyURL, tc.wantProxy)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAuthByIndexDistinguishesSharedAPIKeysAcrossProviders(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
manager := coreauth.NewManager(nil, nil, nil)
|
|
geminiAuth := &coreauth.Auth{
|
|
ID: "gemini:apikey:123",
|
|
Provider: "gemini",
|
|
Attributes: map[string]string{
|
|
"api_key": "shared-key",
|
|
},
|
|
}
|
|
compatAuth := &coreauth.Auth{
|
|
ID: "openai-compatibility:bohe:456",
|
|
Provider: "bohe",
|
|
Label: "bohe",
|
|
Attributes: map[string]string{
|
|
"api_key": "shared-key",
|
|
"compat_name": "bohe",
|
|
"provider_key": "bohe",
|
|
},
|
|
}
|
|
|
|
if _, errRegister := manager.Register(context.Background(), geminiAuth); errRegister != nil {
|
|
t.Fatalf("register gemini auth: %v", errRegister)
|
|
}
|
|
if _, errRegister := manager.Register(context.Background(), compatAuth); errRegister != nil {
|
|
t.Fatalf("register compat auth: %v", errRegister)
|
|
}
|
|
|
|
geminiIndex := geminiAuth.EnsureIndex()
|
|
compatIndex := compatAuth.EnsureIndex()
|
|
if geminiIndex == compatIndex {
|
|
t.Fatalf("shared api key produced duplicate auth_index %q", geminiIndex)
|
|
}
|
|
|
|
h := &Handler{authManager: manager}
|
|
|
|
gotGemini := h.authByIndex(geminiIndex)
|
|
if gotGemini == nil {
|
|
t.Fatal("expected gemini auth by index")
|
|
}
|
|
if gotGemini.ID != geminiAuth.ID {
|
|
t.Fatalf("authByIndex(gemini) returned %q, want %q", gotGemini.ID, geminiAuth.ID)
|
|
}
|
|
|
|
gotCompat := h.authByIndex(compatIndex)
|
|
if gotCompat == nil {
|
|
t.Fatal("expected compat auth by index")
|
|
}
|
|
if gotCompat.ID != compatAuth.ID {
|
|
t.Fatalf("authByIndex(compat) returned %q, want %q", gotCompat.ID, compatAuth.ID)
|
|
}
|
|
}
|