mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-03 04:50:52 +08:00
265 lines
6.1 KiB
Go
265 lines
6.1 KiB
Go
package synthesizer
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/router-for-me/CLIProxyAPI/v6/internal/config"
|
|
coreauth "github.com/router-for-me/CLIProxyAPI/v6/sdk/cliproxy/auth"
|
|
)
|
|
|
|
func TestNewStableIDGenerator(t *testing.T) {
|
|
gen := NewStableIDGenerator()
|
|
if gen == nil {
|
|
t.Fatal("expected non-nil generator")
|
|
}
|
|
if gen.counters == nil {
|
|
t.Fatal("expected non-nil counters map")
|
|
}
|
|
}
|
|
|
|
func TestStableIDGenerator_Next(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
kind string
|
|
parts []string
|
|
wantPrefix string
|
|
}{
|
|
{
|
|
name: "basic gemini apikey",
|
|
kind: "gemini:apikey",
|
|
parts: []string{"test-key", ""},
|
|
wantPrefix: "gemini:apikey:",
|
|
},
|
|
{
|
|
name: "claude with base url",
|
|
kind: "claude:apikey",
|
|
parts: []string{"sk-ant-xxx", "https://api.anthropic.com"},
|
|
wantPrefix: "claude:apikey:",
|
|
},
|
|
{
|
|
name: "empty parts",
|
|
kind: "codex:apikey",
|
|
parts: []string{},
|
|
wantPrefix: "codex:apikey:",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
gen := NewStableIDGenerator()
|
|
id, short := gen.Next(tt.kind, tt.parts...)
|
|
|
|
if !strings.Contains(id, tt.wantPrefix) {
|
|
t.Errorf("expected id to contain %q, got %q", tt.wantPrefix, id)
|
|
}
|
|
if short == "" {
|
|
t.Error("expected non-empty short id")
|
|
}
|
|
if len(short) != 12 {
|
|
t.Errorf("expected short id length 12, got %d", len(short))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStableIDGenerator_Stability(t *testing.T) {
|
|
gen1 := NewStableIDGenerator()
|
|
gen2 := NewStableIDGenerator()
|
|
|
|
id1, _ := gen1.Next("gemini:apikey", "test-key", "https://api.example.com")
|
|
id2, _ := gen2.Next("gemini:apikey", "test-key", "https://api.example.com")
|
|
|
|
if id1 != id2 {
|
|
t.Errorf("same inputs should produce same ID: got %q and %q", id1, id2)
|
|
}
|
|
}
|
|
|
|
func TestStableIDGenerator_CollisionHandling(t *testing.T) {
|
|
gen := NewStableIDGenerator()
|
|
|
|
id1, short1 := gen.Next("gemini:apikey", "same-key")
|
|
id2, short2 := gen.Next("gemini:apikey", "same-key")
|
|
|
|
if id1 == id2 {
|
|
t.Error("collision should be handled with suffix")
|
|
}
|
|
if short1 == short2 {
|
|
t.Error("short ids should differ")
|
|
}
|
|
if !strings.Contains(short2, "-1") {
|
|
t.Errorf("second short id should contain -1 suffix, got %q", short2)
|
|
}
|
|
}
|
|
|
|
func TestStableIDGenerator_NilReceiver(t *testing.T) {
|
|
var gen *StableIDGenerator = nil
|
|
id, short := gen.Next("test:kind", "part")
|
|
|
|
if id != "test:kind:000000000000" {
|
|
t.Errorf("expected test:kind:000000000000, got %q", id)
|
|
}
|
|
if short != "000000000000" {
|
|
t.Errorf("expected 000000000000, got %q", short)
|
|
}
|
|
}
|
|
|
|
func TestApplyAuthExcludedModelsMeta(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
auth *coreauth.Auth
|
|
cfg *config.Config
|
|
perKey []string
|
|
authKind string
|
|
wantHash bool
|
|
wantKind string
|
|
}{
|
|
{
|
|
name: "apikey with excluded models",
|
|
auth: &coreauth.Auth{
|
|
Provider: "gemini",
|
|
Attributes: make(map[string]string),
|
|
},
|
|
cfg: &config.Config{},
|
|
perKey: []string{"model-a", "model-b"},
|
|
authKind: "apikey",
|
|
wantHash: true,
|
|
wantKind: "apikey",
|
|
},
|
|
{
|
|
name: "oauth with provider excluded models",
|
|
auth: &coreauth.Auth{
|
|
Provider: "claude",
|
|
Attributes: make(map[string]string),
|
|
},
|
|
cfg: &config.Config{
|
|
OAuthExcludedModels: map[string][]string{
|
|
"claude": {"claude-2.0"},
|
|
},
|
|
},
|
|
perKey: nil,
|
|
authKind: "oauth",
|
|
wantHash: true,
|
|
wantKind: "oauth",
|
|
},
|
|
{
|
|
name: "nil auth",
|
|
auth: nil,
|
|
cfg: &config.Config{},
|
|
},
|
|
{
|
|
name: "nil config",
|
|
auth: &coreauth.Auth{Provider: "test"},
|
|
cfg: nil,
|
|
authKind: "apikey",
|
|
},
|
|
{
|
|
name: "nil attributes initialized",
|
|
auth: &coreauth.Auth{
|
|
Provider: "gemini",
|
|
Attributes: nil,
|
|
},
|
|
cfg: &config.Config{},
|
|
perKey: []string{"model-x"},
|
|
authKind: "apikey",
|
|
wantHash: true,
|
|
wantKind: "apikey",
|
|
},
|
|
{
|
|
name: "apikey with duplicate excluded models",
|
|
auth: &coreauth.Auth{
|
|
Provider: "gemini",
|
|
Attributes: make(map[string]string),
|
|
},
|
|
cfg: &config.Config{},
|
|
perKey: []string{"model-a", "MODEL-A", "model-b", "model-a"},
|
|
authKind: "apikey",
|
|
wantHash: true,
|
|
wantKind: "apikey",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ApplyAuthExcludedModelsMeta(tt.auth, tt.cfg, tt.perKey, tt.authKind)
|
|
|
|
if tt.auth != nil && tt.cfg != nil {
|
|
if tt.wantHash {
|
|
if _, ok := tt.auth.Attributes["excluded_models_hash"]; !ok {
|
|
t.Error("expected excluded_models_hash in attributes")
|
|
}
|
|
}
|
|
if tt.wantKind != "" {
|
|
if got := tt.auth.Attributes["auth_kind"]; got != tt.wantKind {
|
|
t.Errorf("expected auth_kind=%s, got %s", tt.wantKind, got)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestAddConfigHeadersToAttrs(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
headers map[string]string
|
|
attrs map[string]string
|
|
want map[string]string
|
|
}{
|
|
{
|
|
name: "basic headers",
|
|
headers: map[string]string{
|
|
"Authorization": "Bearer token",
|
|
"X-Custom": "value",
|
|
},
|
|
attrs: map[string]string{"existing": "key"},
|
|
want: map[string]string{
|
|
"existing": "key",
|
|
"header:Authorization": "Bearer token",
|
|
"header:X-Custom": "value",
|
|
},
|
|
},
|
|
{
|
|
name: "empty headers",
|
|
headers: map[string]string{},
|
|
attrs: map[string]string{"existing": "key"},
|
|
want: map[string]string{"existing": "key"},
|
|
},
|
|
{
|
|
name: "nil headers",
|
|
headers: nil,
|
|
attrs: map[string]string{"existing": "key"},
|
|
want: map[string]string{"existing": "key"},
|
|
},
|
|
{
|
|
name: "nil attrs",
|
|
headers: map[string]string{"key": "value"},
|
|
attrs: nil,
|
|
want: nil,
|
|
},
|
|
{
|
|
name: "skip empty keys and values",
|
|
headers: map[string]string{
|
|
"": "value",
|
|
"key": "",
|
|
" ": "value",
|
|
"valid": "valid-value",
|
|
},
|
|
attrs: make(map[string]string),
|
|
want: map[string]string{
|
|
"header:valid": "valid-value",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
addConfigHeadersToAttrs(tt.headers, tt.attrs)
|
|
if !reflect.DeepEqual(tt.attrs, tt.want) {
|
|
t.Errorf("expected %v, got %v", tt.want, tt.attrs)
|
|
}
|
|
})
|
|
}
|
|
}
|