1
0
Files
nex/backend/tests/migration_test.go
lanyuanxiaoyao 395887667d feat: 实现统一模型 ID 机制
实现统一模型 ID 格式 (provider_id/model_name),支持跨协议模型标识和 Smart Passthrough。

核心变更:
- 新增 pkg/modelid 包:解析、格式化、校验统一模型 ID
- 数据库迁移:models 表使用 UUID 主键 + UNIQUE(provider_id, model_name) 约束
- Repository 层:FindByProviderAndModelName、ListEnabled 方法
- Service 层:联合唯一校验、provider ID 字符集校验
- Conversion 层:ExtractModelName、RewriteRequestModelName/RewriteResponseModelName 方法
- Handler 层:统一模型 ID 路由、Smart Passthrough、Models API 本地聚合
- 新增 error-responses、unified-model-id 规范

测试覆盖:
- 单元测试:modelid、conversion、handler、service、repository
- 集成测试:统一模型 ID 路由、Smart Passthrough 保真性、跨协议转换
- 迁移测试:UUID 主键、UNIQUE 约束、级联删除

OpenSpec:
- 归档 unified-model-id 变更到 archive/2026-04-21-unified-model-id
- 同步 11 个 delta specs 到 main specs
- 新增 error-responses、unified-model-id 规范文件
2026-04-21 18:14:10 +08:00

80 lines
2.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package tests
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"nex/backend/internal/config"
)
func TestMigration_ModelsUUIDPrimaryKey(t *testing.T) {
db := SetupTestDB(t)
defer CleanupTestDB(t, db)
// 创建供应商
_ = CreateTestProvider(t, db, "openai")
// 创建模型使用 UUID 作为 id
model, err := CreateTestModel(t, db, "550e8400-e29b-41d4-a716-446655440000", "openai", "gpt-4")
require.NoError(t, err)
// 通过 UUID 查询
var result config.Model
require.NoError(t, db.First(&result, "id = ?", model.ID).Error)
assert.Equal(t, "gpt-4", result.ModelName)
}
func TestMigration_UniqueProviderModelConstraint(t *testing.T) {
db := SetupTestDB(t)
defer CleanupTestDB(t, db)
// 创建供应商
_ = CreateTestProvider(t, db, "openai")
// 创建第一个模型
_, err := CreateTestModel(t, db, "uuid-1", "openai", "gpt-4")
require.NoError(t, err)
// 尝试创建相同 (provider_id, model_name) 的模型应失败
_, err = CreateTestModel(t, db, "uuid-2", "openai", "gpt-4")
assert.Error(t, err, "UNIQUE(provider_id, model_name) 约束应阻止重复")
// 不同 provider_id 下相同 model_name 应成功
_ = CreateTestProvider(t, db, "anthropic")
_, err = CreateTestModel(t, db, "uuid-3", "anthropic", "gpt-4")
require.NoError(t, err, "不同 provider_id 下相同 model_name 应允许")
}
func TestMigration_CascadeDelete(t *testing.T) {
db := SetupTestDB(t)
defer CleanupTestDB(t, db)
// 创建供应商和模型
provider := CreateTestProvider(t, db, "openai")
_, err := CreateTestModel(t, db, "uuid-1", "openai", "gpt-4")
require.NoError(t, err)
// 删除供应商应级联删除模型
require.NoError(t, db.Delete(&provider).Error)
var count int64
db.Model(&config.Model{}).Where("provider_id = ?", "openai").Count(&count)
assert.Equal(t, int64(0), count, "删除供应商后其模型应被级联删除")
}
func TestMigration_ModelDefaultEnabled(t *testing.T) {
db := SetupTestDB(t)
defer CleanupTestDB(t, db)
_ = CreateTestProvider(t, db, "openai")
// 创建模型不指定 enabled应默认为 true
_, err := CreateTestModel(t, db, "uuid-1", "openai", "gpt-4")
require.NoError(t, err)
var result config.Model
require.NoError(t, db.First(&result, "id = ?", "uuid-1").Error)
assert.True(t, result.Enabled, "enabled 字段默认应为 true")
}