| package diff |
|
|
| import ( |
| "strings" |
| "testing" |
|
|
| "github.com/router-for-me/CLIProxyAPI/v6/internal/config" |
| ) |
|
|
| func TestDiffOpenAICompatibility(t *testing.T) { |
| oldList := []config.OpenAICompatibility{ |
| { |
| Name: "provider-a", |
| APIKeyEntries: []config.OpenAICompatibilityAPIKey{ |
| {APIKey: "key-a"}, |
| }, |
| Models: []config.OpenAICompatibilityModel{ |
| {Name: "m1"}, |
| }, |
| }, |
| } |
| newList := []config.OpenAICompatibility{ |
| { |
| Name: "provider-a", |
| APIKeyEntries: []config.OpenAICompatibilityAPIKey{ |
| {APIKey: "key-a"}, |
| {APIKey: "key-b"}, |
| }, |
| Models: []config.OpenAICompatibilityModel{ |
| {Name: "m1"}, |
| {Name: "m2"}, |
| }, |
| Headers: map[string]string{"X-Test": "1"}, |
| }, |
| { |
| Name: "provider-b", |
| APIKeyEntries: []config.OpenAICompatibilityAPIKey{{APIKey: "key-b"}}, |
| }, |
| } |
|
|
| changes := DiffOpenAICompatibility(oldList, newList) |
| expectContains(t, changes, "provider added: provider-b (api-keys=1, models=0)") |
| expectContains(t, changes, "provider updated: provider-a (api-keys 1 -> 2, models 1 -> 2, headers updated)") |
| } |
|
|
| func TestDiffOpenAICompatibility_RemovedAndUnchanged(t *testing.T) { |
| oldList := []config.OpenAICompatibility{ |
| { |
| Name: "provider-a", |
| APIKeyEntries: []config.OpenAICompatibilityAPIKey{{APIKey: "key-a"}}, |
| Models: []config.OpenAICompatibilityModel{{Name: "m1"}}, |
| }, |
| } |
| newList := []config.OpenAICompatibility{ |
| { |
| Name: "provider-a", |
| APIKeyEntries: []config.OpenAICompatibilityAPIKey{{APIKey: "key-a"}}, |
| Models: []config.OpenAICompatibilityModel{{Name: "m1"}}, |
| }, |
| } |
| if changes := DiffOpenAICompatibility(oldList, newList); len(changes) != 0 { |
| t.Fatalf("expected no changes, got %v", changes) |
| } |
|
|
| newList = nil |
| changes := DiffOpenAICompatibility(oldList, newList) |
| expectContains(t, changes, "provider removed: provider-a (api-keys=1, models=1)") |
| } |
|
|
| func TestOpenAICompatKeyFallbacks(t *testing.T) { |
| entry := config.OpenAICompatibility{ |
| BaseURL: "http://base", |
| Models: []config.OpenAICompatibilityModel{{Alias: "alias-only"}}, |
| } |
| key, label := openAICompatKey(entry, 0) |
| if key != "base:http://base" || label != "http://base" { |
| t.Fatalf("expected base key, got %s/%s", key, label) |
| } |
|
|
| entry.BaseURL = "" |
| key, label = openAICompatKey(entry, 1) |
| if key != "alias:alias-only" || label != "alias-only" { |
| t.Fatalf("expected alias fallback, got %s/%s", key, label) |
| } |
|
|
| entry.Models = nil |
| key, label = openAICompatKey(entry, 2) |
| if key != "index:2" || label != "entry-3" { |
| t.Fatalf("expected index fallback, got %s/%s", key, label) |
| } |
| } |
|
|
| func TestOpenAICompatKey_UsesName(t *testing.T) { |
| entry := config.OpenAICompatibility{Name: "My-Provider"} |
| key, label := openAICompatKey(entry, 0) |
| if key != "name:My-Provider" || label != "My-Provider" { |
| t.Fatalf("expected name key, got %s/%s", key, label) |
| } |
| } |
|
|
| func TestOpenAICompatKey_SignatureFallbackWhenOnlyAPIKeys(t *testing.T) { |
| entry := config.OpenAICompatibility{ |
| APIKeyEntries: []config.OpenAICompatibilityAPIKey{{APIKey: "k1"}, {APIKey: "k2"}}, |
| } |
| key, label := openAICompatKey(entry, 0) |
| if !strings.HasPrefix(key, "sig:") || !strings.HasPrefix(label, "compat-") { |
| t.Fatalf("expected signature key, got %s/%s", key, label) |
| } |
| } |
|
|
| func TestOpenAICompatSignature_EmptyReturnsEmpty(t *testing.T) { |
| if got := openAICompatSignature(config.OpenAICompatibility{}); got != "" { |
| t.Fatalf("expected empty signature, got %q", got) |
| } |
| } |
|
|
| func TestOpenAICompatSignature_StableAndNormalized(t *testing.T) { |
| a := config.OpenAICompatibility{ |
| Name: " Provider ", |
| BaseURL: "http://base", |
| Models: []config.OpenAICompatibilityModel{ |
| {Name: "m1"}, |
| {Name: " "}, |
| {Alias: "A1"}, |
| }, |
| Headers: map[string]string{ |
| "X-Test": "1", |
| " ": "ignored", |
| }, |
| APIKeyEntries: []config.OpenAICompatibilityAPIKey{ |
| {APIKey: "k1"}, |
| {APIKey: " "}, |
| }, |
| } |
| b := config.OpenAICompatibility{ |
| Name: "provider", |
| BaseURL: "http://base", |
| Models: []config.OpenAICompatibilityModel{ |
| {Alias: "a1"}, |
| {Name: "m1"}, |
| }, |
| Headers: map[string]string{ |
| "x-test": "2", |
| }, |
| APIKeyEntries: []config.OpenAICompatibilityAPIKey{ |
| {APIKey: "k2"}, |
| }, |
| } |
|
|
| sigA := openAICompatSignature(a) |
| sigB := openAICompatSignature(b) |
| if sigA == "" || sigB == "" { |
| t.Fatalf("expected non-empty signatures, got %q / %q", sigA, sigB) |
| } |
| if sigA != sigB { |
| t.Fatalf("expected normalized signatures to match, got %s / %s", sigA, sigB) |
| } |
|
|
| c := b |
| c.Models = append(c.Models, config.OpenAICompatibilityModel{Name: "m2"}) |
| if sigC := openAICompatSignature(c); sigC == sigB { |
| t.Fatalf("expected signature to change when models change, got %s", sigC) |
| } |
| } |
|
|
| func TestCountOpenAIModelsSkipsBlanks(t *testing.T) { |
| models := []config.OpenAICompatibilityModel{ |
| {Name: "m1"}, |
| {Name: ""}, |
| {Alias: ""}, |
| {Name: " "}, |
| {Alias: "a1"}, |
| } |
| if got := countOpenAIModels(models); got != 2 { |
| t.Fatalf("expected 2 counted models, got %d", got) |
| } |
| } |
|
|
| func TestOpenAICompatKeyUsesModelNameWhenAliasEmpty(t *testing.T) { |
| entry := config.OpenAICompatibility{ |
| Models: []config.OpenAICompatibilityModel{{Name: "model-name"}}, |
| } |
| key, label := openAICompatKey(entry, 5) |
| if key != "alias:model-name" || label != "model-name" { |
| t.Fatalf("expected model-name fallback, got %s/%s", key, label) |
| } |
| } |
|
|