Files
ttstd-infinite-canvas/backend/internal/service/channel_models_test.go

131 lines
5.0 KiB
Go

package service
import (
"testing"
"infinite-canvas/backend/internal/model"
)
func TestNormalizeChannelModelContract(t *testing.T) {
channel := &model.ModelChannel{APIKey: "test-key"}
modelKey, providerModelKey, capability, protocol, err := normalizeChannelModelContract(channel, ChannelModelRequest{
ModelKey: "models/gpt-test", Capability: "text", Protocol: string(model.ChannelInterfaceChatCompletion),
})
if err != nil {
t.Fatalf("normalizeChannelModelContract() error = %v", err)
}
if modelKey != "gpt-test" || providerModelKey != "gpt-test" || capability != "text" || protocol != model.ChannelInterfaceChatCompletion {
t.Fatalf("contract = %q, %q, %q, %q", modelKey, providerModelKey, capability, protocol)
}
}
func TestNormalizeChannelModelContractPreservesProviderModelKey(t *testing.T) {
channel := &model.ModelChannel{APIKey: "test-key"}
modelKey, providerModelKey, _, _, err := normalizeChannelModelContract(channel, ChannelModelRequest{
ModelKey: "seedance-2-5-480p", ProviderModelKey: "models/doubao-seedance-2-5", Capability: "video", Protocol: string(model.ChannelInterfaceVolcengineArkVideo),
})
if err != nil {
t.Fatalf("normalizeChannelModelContract() error = %v", err)
}
if modelKey != "seedance-2-5-480p" || providerModelKey != "doubao-seedance-2-5" {
t.Fatalf("contract = %q, %q", modelKey, providerModelKey)
}
}
func TestNormalizeChannelModelContractRejectsCapabilityMismatch(t *testing.T) {
channel := &model.ModelChannel{APIKey: "test-key"}
_, _, _, _, err := normalizeChannelModelContract(channel, ChannelModelRequest{
ModelKey: "image-test", Capability: "text", Protocol: string(model.ChannelInterfaceOpenAIImage),
})
if err == nil {
t.Fatal("normalizeChannelModelContract() should reject a mismatched capability")
}
}
func TestNormalizeChannelModelContractRequiresJiMengSecret(t *testing.T) {
channel := &model.ModelChannel{APIKey: "access-key"}
_, _, _, _, err := normalizeChannelModelContract(channel, ChannelModelRequest{
ModelKey: "jimeng-test", Capability: "image", Protocol: string(model.ChannelInterfaceVolcengineJiMengImage),
})
if err == nil {
t.Fatal("normalizeChannelModelContract() should require JiMeng credentials")
}
}
func TestSaveAdminChannelModelPersistsAndPublishesIcon(t *testing.T) {
svc, db := newChannelModelTestService(t)
admin := &model.User{ID: "admin", Role: model.UserRoleAdmin}
channel := model.ModelChannel{ID: "channel-1", UserID: admin.ID, Scope: model.ChannelScopeSystem, Enabled: true, Name: "Test", BaseURL: "https://example.com/v1", APIKey: "key", APIFormat: "openai", ModelsJSON: `[]`}
if err := db.Create(&channel).Error; err != nil {
t.Fatal(err)
}
enabled := true
saved, err := svc.SaveAdminChannelModel(admin, channel.ID, "", ChannelModelRequest{
ModelKey: "gpt-test", DisplayName: "GPT Test", Icon: "OpenAI", Capability: "text", Protocol: string(model.ChannelInterfaceChatCompletion),
CapabilityConfig: DefaultModelCapabilityConfigForModel(string(model.ChannelInterfaceChatCompletion), "gpt-test"),
PriceTiers: []ChannelModelPriceTierRequest{{BillingMode: "fixed_request", PriceConfigured: true, Enabled: &enabled}}, Enabled: &enabled,
})
if err != nil {
t.Fatal(err)
}
if saved.Icon != "OpenAI" {
t.Fatalf("saved icon = %q, want OpenAI", saved.Icon)
}
var stored model.ChannelModel
if err := db.First(&stored, "id = ?", saved.ID).Error; err != nil {
t.Fatal(err)
}
if stored.Icon != "OpenAI" {
t.Fatalf("stored icon = %q, want OpenAI", stored.Icon)
}
if public := svc.sanitizeChannelModel(saved); public.Icon != "OpenAI" {
t.Fatalf("public icon = %q, want OpenAI", public.Icon)
}
legacyPublic := publicChannel(channel, false, []model.ChannelModel{*saved})
if len(legacyPublic.ModelCosts) != 1 || legacyPublic.ModelCosts[0].Icon != "OpenAI" {
t.Fatalf("legacy public model costs = %#v", legacyPublic.ModelCosts)
}
}
func TestImageTestDefaultsUseModelCapability(t *testing.T) {
tests := []struct {
name string
profile *ImageCapabilityConfig
wantSize string
wantQuality string
}{
{name: "legacy fallback", wantSize: "1024x1024", wantQuality: "auto"},
{
name: "fixed 2k model",
profile: &ImageCapabilityConfig{
Size: ImageSizeConfig{Parameter: "size", Default: "2048x2048"},
Quality: ImageQualityConfig{Supported: false, Default: "auto"},
},
wantSize: "2048x2048",
},
{
name: "provider selected size",
profile: &ImageCapabilityConfig{
Size: ImageSizeConfig{Parameter: "none", Default: "auto"},
Quality: ImageQualityConfig{Supported: false},
},
},
{
name: "gpt image capability",
profile: &ImageCapabilityConfig{
Size: ImageSizeConfig{Parameter: "size", Default: "1024x1536"},
Quality: ImageQualityConfig{Supported: true, Default: "high"},
},
wantSize: "1024x1536", wantQuality: "high",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
size, quality := imageTestDefaults(test.profile)
if size != test.wantSize || quality != test.wantQuality {
t.Fatalf("imageTestDefaults() = %q, %q; want %q, %q", size, quality, test.wantSize, test.wantQuality)
}
})
}
}