Files
MyGoNavi/internal/ai/service/service_test.go
Syngnat 29ee21e9d7 feat(query-editor): 增强 SQL 编辑器 AI 内联补全与独立模型配置
- 新增独立内联补全模型配置与服务端透传
- 优化 SQL 编辑器 Alt+\\ 触发、ghost 延续与对象位补全
- 引入基于已存查询和执行日志的 SQL 记忆补全
- 补充前后端本地化、快捷键与补全回归测试
2026-07-03 20:44:33 +08:00

188 lines
6.0 KiB
Go

package aiservice
import (
"reflect"
"testing"
"GoNavi-Wails/internal/ai"
)
func TestResolveModelsURL_UsesMoonshotOpenAIModelsEndpointForKimiAnthropicBaseURL(t *testing.T) {
url := resolveModelsURL(ai.ProviderConfig{
Type: "anthropic",
BaseURL: "https://api.moonshot.cn/anthropic",
})
if url != "https://api.moonshot.cn/v1/models" {
t.Fatalf("expected moonshot models endpoint, got %q", url)
}
}
func TestResolveModelsURL_UsesAnthropicModelsEndpointForOfficialAnthropic(t *testing.T) {
url := resolveModelsURL(ai.ProviderConfig{
Type: "anthropic",
BaseURL: "https://api.anthropic.com",
})
if url != "https://api.anthropic.com/v1/models" {
t.Fatalf("expected anthropic models endpoint, got %q", url)
}
}
func TestResolveModelsURL_UsesOpenAIModelsEndpointForOpenAICompatibleProvider(t *testing.T) {
url := resolveModelsURL(ai.ProviderConfig{
Type: "openai",
BaseURL: "https://api.openai.com/v1",
})
if url != "https://api.openai.com/v1/models" {
t.Fatalf("expected openai models endpoint, got %q", url)
}
}
func TestResolveModelsURL_UsesVersionedVolcengineCodingPlanPath(t *testing.T) {
url := resolveModelsURL(ai.ProviderConfig{
Type: "openai",
BaseURL: "https://ark.cn-beijing.volces.com/api/coding/v3",
})
if url != "https://ark.cn-beijing.volces.com/api/coding/v3/models" {
t.Fatalf("expected volcengine coding plan models endpoint, got %q", url)
}
}
func TestResolveModelsURL_UsesVersionedZhipuPath(t *testing.T) {
url := resolveModelsURL(ai.ProviderConfig{
Type: "openai",
BaseURL: "https://open.bigmodel.cn/api/paas/v4",
})
if url != "https://open.bigmodel.cn/api/paas/v4/models" {
t.Fatalf("expected zhipu models endpoint, got %q", url)
}
}
func TestNewModelsRequest_StripsChatCompletionsSuffixForOpenAICompatibleProvider(t *testing.T) {
req, err := newModelsRequest(ai.ProviderConfig{
Type: "openai",
BaseURL: "https://ark.cn-beijing.volces.com/api/v3/chat/completions",
APIKey: "sk-test",
}, nil)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if req.URL.String() != "https://ark.cn-beijing.volces.com/api/v3/models" {
t.Fatalf("expected normalized models endpoint, got %q", req.URL.String())
}
if got := req.Header.Get("Authorization"); got != "Bearer sk-test" {
t.Fatalf("expected bearer auth header, got %q", got)
}
}
func TestDefaultStaticModelsForProvider_ReturnsMiniMaxAnthropicModels(t *testing.T) {
models := defaultStaticModelsForProvider(ai.ProviderConfig{
Type: "anthropic",
BaseURL: "https://api.minimaxi.com/anthropic",
})
expected := []string{
"MiniMax-M3",
"MiniMax-M2.7",
"MiniMax-M2.7-highspeed",
}
if !reflect.DeepEqual(models, expected) {
t.Fatalf("expected MiniMax static models %v, got %v", expected, models)
}
}
func TestDefaultStaticModelsForProvider_DoesNotReturnDashScopeBailianStaticModels(t *testing.T) {
models := defaultStaticModelsForProvider(ai.ProviderConfig{
Type: "anthropic",
BaseURL: "https://dashscope.aliyuncs.com/apps/anthropic",
})
if len(models) != 0 {
t.Fatalf("expected Bailian provider to fetch models remotely, got %v", models)
}
}
func TestApplyChatSendOptionsToProviderConfig_OverridesModelForSingleRequest(t *testing.T) {
config := applyChatSendOptionsToProviderConfig(ai.ProviderConfig{
Model: "chat-model",
}, ai.ChatSendOptions{
Model: "inline-model",
})
if config.Model != "inline-model" {
t.Fatalf("expected inline model override, got %q", config.Model)
}
}
func TestApplyChatSendOptionsToProviderConfig_KeepsConfiguredModelWhenOverrideEmpty(t *testing.T) {
config := applyChatSendOptionsToProviderConfig(ai.ProviderConfig{
Model: "chat-model",
}, ai.ChatSendOptions{
Model: " ",
})
if config.Model != "chat-model" {
t.Fatalf("expected configured model to be kept, got %q", config.Model)
}
}
func TestNormalizeChatSendOptions_TrimsModelAndClampsNegativeNumbers(t *testing.T) {
options := normalizeChatSendOptions(ai.ChatSendOptions{
Model: " inline-model ",
MaxTokens: -1,
Temperature: -0.5,
})
if options.Model != "inline-model" {
t.Fatalf("expected trimmed model, got %q", options.Model)
}
if options.MaxTokens != 0 {
t.Fatalf("expected negative max tokens to be clamped, got %d", options.MaxTokens)
}
if options.Temperature != 0 {
t.Fatalf("expected negative temperature to be clamped, got %f", options.Temperature)
}
}
func TestNewProviderHealthCheckRequest_UsesMessagesEndpointForMiniMaxAnthropic(t *testing.T) {
req, err := newProviderHealthCheckRequest(ai.ProviderConfig{
Type: "anthropic",
BaseURL: "https://api.minimaxi.com/anthropic",
Model: "MiniMax-M2.7",
APIKey: "sk-test",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if req.Method != "POST" {
t.Fatalf("expected POST request, got %s", req.Method)
}
if req.URL.String() != "https://api.minimaxi.com/anthropic/v1/messages" {
t.Fatalf("expected MiniMax messages endpoint, got %q", req.URL.String())
}
if got := req.Header.Get("x-api-key"); got != "sk-test" {
t.Fatalf("expected x-api-key header to be set, got %q", got)
}
}
func TestNewProviderHealthCheckRequest_UsesMessagesEndpointForDashScopeAnthropic(t *testing.T) {
req, err := newProviderHealthCheckRequest(ai.ProviderConfig{
Type: "anthropic",
BaseURL: "https://dashscope.aliyuncs.com/apps/anthropic",
Model: "qwen3.5-plus",
APIKey: "sk-test",
})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if req.Method != "POST" {
t.Fatalf("expected POST request, got %s", req.Method)
}
if req.URL.String() != "https://dashscope.aliyuncs.com/apps/anthropic/v1/messages" {
t.Fatalf("expected DashScope messages endpoint, got %q", req.URL.String())
}
if got := req.Header.Get("x-api-key"); got != "sk-test" {
t.Fatalf("expected x-api-key header to be set, got %q", got)
}
if got := req.Header.Get("Authorization"); got != "Bearer sk-test" {
t.Fatalf("expected bearer authorization header, got %q", got)
}
if got := req.Header.Get("anthropic-version"); got != "" {
t.Fatalf("expected no anthropic-version header for DashScope, got %q", got)
}
}