Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 

232 wiersze
8.8 KiB

  1. package service
  2. import (
  3. "fmt"
  4. "os"
  5. "strings"
  6. "testing"
  7. "github.com/QuantumNous/new-api/common"
  8. "github.com/QuantumNous/new-api/constant"
  9. "github.com/QuantumNous/new-api/model"
  10. "github.com/stretchr/testify/assert"
  11. "github.com/stretchr/testify/require"
  12. "gorm.io/gorm"
  13. "gorm.io/gorm/logger"
  14. )
  15. func setupDoubaoAssetChannelDB(t *testing.T) *gorm.DB {
  16. t.Helper()
  17. oldDB := model.DB
  18. oldSQLitePath := common.SQLitePath
  19. oldMemoryCacheEnabled := common.MemoryCacheEnabled
  20. oldIsMasterNode := common.IsMasterNode
  21. oldUsingSQLite := common.UsingSQLite
  22. oldUsingMySQL := common.UsingMySQL
  23. oldUsingPostgreSQL := common.UsingPostgreSQL
  24. oldSQLDSN, hadSQLDSN := os.LookupEnv("SQL_DSN")
  25. common.SQLitePath = "file:" + strings.NewReplacer("/", "_", " ", "_").Replace(t.Name()) + "?mode=memory&cache=shared"
  26. common.MemoryCacheEnabled = false
  27. common.IsMasterNode = false
  28. common.UsingSQLite = false
  29. common.UsingMySQL = false
  30. common.UsingPostgreSQL = false
  31. require.NoError(t, os.Setenv("SQL_DSN", "local"))
  32. require.NoError(t, model.InitDB())
  33. model.DB = model.DB.Session(&gorm.Session{Logger: logger.Default.LogMode(logger.Silent)})
  34. db := model.DB
  35. sqlDB, err := db.DB()
  36. require.NoError(t, err)
  37. sqlDB.SetMaxOpenConns(1)
  38. require.NoError(t, db.AutoMigrate(&model.Channel{}, &model.Ability{}, &model.UserAssetChannel{}))
  39. t.Cleanup(func() {
  40. _ = sqlDB.Close()
  41. model.DB = oldDB
  42. common.SQLitePath = oldSQLitePath
  43. common.MemoryCacheEnabled = oldMemoryCacheEnabled
  44. common.IsMasterNode = oldIsMasterNode
  45. common.UsingSQLite = oldUsingSQLite
  46. common.UsingMySQL = oldUsingMySQL
  47. common.UsingPostgreSQL = oldUsingPostgreSQL
  48. if hadSQLDSN {
  49. _ = os.Setenv("SQL_DSN", oldSQLDSN)
  50. } else {
  51. _ = os.Unsetenv("SQL_DSN")
  52. }
  53. })
  54. return db
  55. }
  56. func createDoubaoAssetChannelForTest(t *testing.T, db *gorm.DB, id int, channelType int, group string, key string, status int) {
  57. t.Helper()
  58. priority := int64(id)
  59. weight := uint(10)
  60. autoBan := 1
  61. channel := &model.Channel{
  62. Id: id,
  63. Type: channelType,
  64. Key: key,
  65. Status: status,
  66. Name: fmt.Sprintf("channel-%d", id),
  67. Group: group,
  68. Models: "seedance-2",
  69. Priority: &priority,
  70. Weight: &weight,
  71. AutoBan: &autoBan,
  72. CreatedTime: int64(id),
  73. }
  74. require.NoError(t, db.Create(channel).Error)
  75. }
  76. func createDoubaoAssetAbilityForTest(t *testing.T, db *gorm.DB, group string, modelName string, channelId int, enabled bool) {
  77. t.Helper()
  78. priority := int64(channelId)
  79. require.NoError(t, db.Create(&model.Ability{
  80. Group: group,
  81. Model: modelName,
  82. ChannelId: channelId,
  83. Enabled: enabled,
  84. Priority: &priority,
  85. Weight: 10,
  86. }).Error)
  87. }
  88. func TestResolveDoubaoAssetChannel_PrefersBoundChannelWithKey(t *testing.T) {
  89. db := setupDoubaoAssetChannelDB(t)
  90. createDoubaoAssetChannelForTest(t, db, 1, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default", "bound-key", common.ChannelStatusEnabled)
  91. createDoubaoAssetChannelForTest(t, db, 2, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default", "auto-key", common.ChannelStatusEnabled)
  92. require.NoError(t, model.BindUserAssetChannel(10, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default", 1))
  93. channel, err := ResolveDoubaoAssetChannel(10, "default")
  94. require.NoError(t, err)
  95. require.NotNil(t, channel)
  96. assert.Equal(t, 1, channel.Id)
  97. assert.Equal(t, "bound-key", channel.Key)
  98. }
  99. func TestResolveDoubaoAssetChannel_AutoMatchesAndPersistsWhenUnbound(t *testing.T) {
  100. db := setupDoubaoAssetChannelDB(t)
  101. createDoubaoAssetChannelForTest(t, db, 1, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default", "auto-key", common.ChannelStatusEnabled)
  102. channel, err := ResolveDoubaoAssetChannel(10, "default")
  103. require.NoError(t, err)
  104. require.NotNil(t, channel)
  105. assert.Equal(t, 1, channel.Id)
  106. binding, err := model.GetUserAssetChannel(10, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default")
  107. require.NoError(t, err)
  108. require.NotNil(t, binding)
  109. assert.Equal(t, 1, binding.ChannelId)
  110. }
  111. func TestResolveDoubaoAssetChannel_RebindsOpenAIMisbindToAiping(t *testing.T) {
  112. db := setupDoubaoAssetChannelDB(t)
  113. createDoubaoAssetChannelForTest(t, db, 1, constant.ChannelTypeOpenAI, "default", "openai-key", common.ChannelStatusEnabled)
  114. createDoubaoAssetChannelForTest(t, db, 2, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default", "aiping-key", common.ChannelStatusEnabled)
  115. require.NoError(t, model.BindUserAssetChannel(10, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default", 1))
  116. channel, err := ResolveDoubaoAssetChannel(10, "default")
  117. require.NoError(t, err)
  118. require.NotNil(t, channel)
  119. assert.Equal(t, 2, channel.Id)
  120. binding, err := model.GetUserAssetChannel(10, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default")
  121. require.NoError(t, err)
  122. require.NotNil(t, binding)
  123. assert.Equal(t, 2, binding.ChannelId)
  124. }
  125. func TestResolveDoubaoAssetChannel_RebindsOnlyCurrentGroupWhenBoundGroupMismatches(t *testing.T) {
  126. db := setupDoubaoAssetChannelDB(t)
  127. createDoubaoAssetChannelForTest(t, db, 1, constant.ChannelTypeDoubaoVideoCompatibleAiping, "vip", "vip-key", common.ChannelStatusEnabled)
  128. createDoubaoAssetChannelForTest(t, db, 2, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default", "default-key", common.ChannelStatusEnabled)
  129. require.NoError(t, model.BindUserAssetChannel(10, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default", 1))
  130. require.NoError(t, model.BindUserAssetChannel(10, constant.ChannelTypeDoubaoVideoCompatibleAiping, "vip", 1))
  131. channel, err := ResolveDoubaoAssetChannel(10, "default")
  132. require.NoError(t, err)
  133. require.NotNil(t, channel)
  134. assert.Equal(t, 2, channel.Id)
  135. defaultBinding, err := model.GetUserAssetChannel(10, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default")
  136. require.NoError(t, err)
  137. require.NotNil(t, defaultBinding)
  138. assert.Equal(t, 2, defaultBinding.ChannelId)
  139. vipBinding, err := model.GetUserAssetChannel(10, constant.ChannelTypeDoubaoVideoCompatibleAiping, "vip")
  140. require.NoError(t, err)
  141. require.NotNil(t, vipBinding)
  142. assert.Equal(t, 1, vipBinding.ChannelId)
  143. }
  144. func TestResolveDoubaoAssetChannel_AutoMatchScansPastFirstPage(t *testing.T) {
  145. db := setupDoubaoAssetChannelDB(t)
  146. createDoubaoAssetChannelForTest(t, db, 1, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default", "default-key", common.ChannelStatusEnabled)
  147. for i := 2; i <= DoubaoAssetChannelPageSize+1; i++ {
  148. createDoubaoAssetChannelForTest(t, db, i, constant.ChannelTypeDoubaoVideoCompatibleAiping, "vip", fmt.Sprintf("vip-key-%d", i), common.ChannelStatusEnabled)
  149. }
  150. channel, err := ResolveDoubaoAssetChannel(10, "default")
  151. require.NoError(t, err)
  152. require.NotNil(t, channel)
  153. assert.Equal(t, 1, channel.Id)
  154. }
  155. func TestResolveDoubaoAssetChannel_ReturnsErrorWhenBindingWriteFails(t *testing.T) {
  156. db := setupDoubaoAssetChannelDB(t)
  157. createDoubaoAssetChannelForTest(t, db, 1, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default", "auto-key", common.ChannelStatusEnabled)
  158. const callbackName = "doubao_asset_test:fail_user_asset_channel_create"
  159. require.NoError(t, db.Callback().Create().Before("gorm:create").Register(callbackName, func(tx *gorm.DB) {
  160. if _, ok := tx.Statement.Dest.(*model.UserAssetChannel); ok {
  161. tx.AddError(assert.AnError)
  162. }
  163. }))
  164. channel, err := ResolveDoubaoAssetChannel(10, "default")
  165. require.Error(t, err)
  166. assert.Nil(t, channel)
  167. }
  168. func TestHasDoubaoVideoChannelForGroupModel(t *testing.T) {
  169. db := setupDoubaoAssetChannelDB(t)
  170. createDoubaoAssetChannelForTest(t, db, 1, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default", "default-key", common.ChannelStatusEnabled)
  171. createDoubaoAssetChannelForTest(t, db, 2, constant.ChannelTypeDoubaoVideoCompatibleAiping, "vip", "vip-key", common.ChannelStatusEnabled)
  172. createDoubaoAssetChannelForTest(t, db, 3, constant.ChannelTypeOpenAI, "default", "openai-key", common.ChannelStatusEnabled)
  173. createDoubaoAssetAbilityForTest(t, db, "default", "seedance-2", 1, true)
  174. createDoubaoAssetAbilityForTest(t, db, "vip", "seedance-2", 2, true)
  175. createDoubaoAssetAbilityForTest(t, db, "default", "disabled-model", 1, false)
  176. createDoubaoAssetAbilityForTest(t, db, "default", "seedance-2", 3, true)
  177. assert.True(t, HasDoubaoVideoChannelForGroupModel("default", "seedance-2"))
  178. assert.False(t, HasDoubaoVideoChannelForGroupModel("default", "disabled-model"))
  179. assert.False(t, HasDoubaoVideoChannelForGroupModel("missing", "seedance-2"))
  180. }
  181. func TestAutoMatchDoubaoAssetChannel_IgnoresLegacyDoubaoVideoChannels(t *testing.T) {
  182. db := setupDoubaoAssetChannelDB(t)
  183. createDoubaoAssetChannelForTest(t, db, 1, constant.ChannelTypeDoubaoVideo, "default", "legacy-key", common.ChannelStatusEnabled)
  184. createDoubaoAssetChannelForTest(t, db, 2, constant.ChannelTypeDoubaoVideoCompatibleAiping, "default", "aiping-key", common.ChannelStatusEnabled)
  185. channel, err := AutoMatchDoubaoAssetChannel("default")
  186. require.NoError(t, err)
  187. require.NotNil(t, channel)
  188. assert.Equal(t, 2, channel.Id)
  189. assert.Equal(t, constant.ChannelTypeDoubaoVideoCompatibleAiping, channel.Type)
  190. }