Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

240 строки
7.0 KiB

  1. package model
  2. import (
  3. "testing"
  4. "github.com/QuantumNous/new-api/common"
  5. "github.com/QuantumNous/new-api/constant"
  6. "github.com/glebarez/sqlite"
  7. "github.com/stretchr/testify/assert"
  8. "github.com/stretchr/testify/require"
  9. "gorm.io/gorm"
  10. )
  11. func setupChannelSelectDB(t *testing.T) *gorm.DB {
  12. t.Helper()
  13. db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
  14. require.NoError(t, err)
  15. sqlDB, err := db.DB()
  16. require.NoError(t, err)
  17. sqlDB.SetMaxOpenConns(1)
  18. origDB := DB
  19. origUsingSQLite := common.UsingSQLite
  20. origRedisEnabled := common.RedisEnabled
  21. origMemoryCache := common.MemoryCacheEnabled
  22. origGroupCol := commonGroupCol
  23. origTrueVal := commonTrueVal
  24. DB = db
  25. common.UsingSQLite = true
  26. common.RedisEnabled = false
  27. common.MemoryCacheEnabled = false
  28. // Set column quoting for SQLite
  29. commonGroupCol = "`group`"
  30. commonTrueVal = "1"
  31. require.NoError(t, db.AutoMigrate(&Channel{}, &Ability{}))
  32. t.Cleanup(func() {
  33. DB = origDB
  34. common.UsingSQLite = origUsingSQLite
  35. common.RedisEnabled = origRedisEnabled
  36. common.MemoryCacheEnabled = origMemoryCache
  37. commonGroupCol = origGroupCol
  38. commonTrueVal = origTrueVal
  39. sqlDB.Close()
  40. })
  41. return db
  42. }
  43. func int64Ptr(v int64) *int64 { return &v }
  44. func intPtr(v int) *int { return &v }
  45. func uintPtr(v uint) *uint { return &v }
  46. func createChannelForTest(t *testing.T, db *gorm.DB, id int, name, group, models string, priority int64) {
  47. t.Helper()
  48. ch := Channel{
  49. Id: id,
  50. Type: 1,
  51. Key: "test-key-" + name,
  52. Status: common.ChannelStatusEnabled,
  53. Name: name,
  54. Group: group,
  55. Models: models,
  56. Priority: int64Ptr(priority),
  57. Weight: uintPtr(10),
  58. AutoBan: intPtr(1),
  59. CreatedTime: 1,
  60. }
  61. require.NoError(t, db.Create(&ch).Error)
  62. }
  63. func createChannelWithTypeForTest(t *testing.T, db *gorm.DB, id int, name, group, models string, channelType int, priority int64) {
  64. t.Helper()
  65. ch := Channel{
  66. Id: id,
  67. Type: channelType,
  68. Key: "test-key-" + name,
  69. Status: common.ChannelStatusEnabled,
  70. Name: name,
  71. Group: group,
  72. Models: models,
  73. Priority: int64Ptr(priority),
  74. Weight: uintPtr(10),
  75. AutoBan: intPtr(1),
  76. CreatedTime: 1,
  77. }
  78. require.NoError(t, db.Create(&ch).Error)
  79. }
  80. func createAbilityForTest(t *testing.T, db *gorm.DB, group, modelName string, channelId int, priority int64, enabled bool) {
  81. t.Helper()
  82. ability := Ability{
  83. Group: group,
  84. Model: modelName,
  85. ChannelId: channelId,
  86. Enabled: enabled,
  87. Priority: int64Ptr(priority),
  88. Weight: 10,
  89. }
  90. require.NoError(t, db.Create(&ability).Error)
  91. }
  92. // --- GetChannel (DB path) tests ---
  93. func TestGetChannel_BasicSelection(t *testing.T) {
  94. db := setupChannelSelectDB(t)
  95. createChannelForTest(t, db, 1, "ch1", "default", "gpt-4", 10)
  96. createAbilityForTest(t, db, "default", "gpt-4", 1, 10, true)
  97. ch, err := GetChannel("default", "gpt-4", 0)
  98. require.NoError(t, err)
  99. assert.NotNil(t, ch)
  100. assert.Equal(t, 1, ch.Id)
  101. }
  102. func TestGetChannel_NoChannelForModel(t *testing.T) {
  103. db := setupChannelSelectDB(t)
  104. createChannelForTest(t, db, 1, "ch1", "default", "gpt-3.5", 10)
  105. createAbilityForTest(t, db, "default", "gpt-3.5", 1, 10, true)
  106. ch, err := GetChannel("default", "gpt-4", 0)
  107. assert.NoError(t, err)
  108. assert.Nil(t, ch)
  109. }
  110. func TestGetChannel_PrioritySelection(t *testing.T) {
  111. db := setupChannelSelectDB(t)
  112. // Two channels with different priorities
  113. createChannelForTest(t, db, 1, "ch-low", "default", "gpt-4", 0)
  114. createChannelForTest(t, db, 2, "ch-high", "default", "gpt-4", 10)
  115. createAbilityForTest(t, db, "default", "gpt-4", 1, 0, true)
  116. createAbilityForTest(t, db, "default", "gpt-4", 2, 10, true)
  117. // Retry=0 should get highest priority (10)
  118. ch, err := GetChannel("default", "gpt-4", 0)
  119. require.NoError(t, err)
  120. assert.NotNil(t, ch)
  121. assert.Equal(t, 2, ch.Id) // ch-high has priority 10
  122. // Retry=1 should get next priority (0)
  123. ch, err = GetChannel("default", "gpt-4", 1)
  124. require.NoError(t, err)
  125. assert.NotNil(t, ch)
  126. assert.Equal(t, 1, ch.Id) // ch-low has priority 0
  127. }
  128. func TestGetChannel_DifferentGroups(t *testing.T) {
  129. db := setupChannelSelectDB(t)
  130. // Channel in "default" group
  131. createChannelForTest(t, db, 1, "ch-default", "default", "gpt-4", 10)
  132. createAbilityForTest(t, db, "default", "gpt-4", 1, 10, true)
  133. // Channel in "vip" group
  134. createChannelForTest(t, db, 2, "ch-vip", "vip", "gpt-4", 10)
  135. createAbilityForTest(t, db, "vip", "gpt-4", 2, 10, true)
  136. // Query default group
  137. ch, err := GetChannel("default", "gpt-4", 0)
  138. require.NoError(t, err)
  139. assert.Equal(t, 1, ch.Id)
  140. // Query vip group
  141. ch, err = GetChannel("vip", "gpt-4", 0)
  142. require.NoError(t, err)
  143. assert.Equal(t, 2, ch.Id)
  144. }
  145. func TestGetChannel_DisabledAbility(t *testing.T) {
  146. db := setupChannelSelectDB(t)
  147. createChannelForTest(t, db, 1, "ch1", "default", "gpt-4", 10)
  148. createAbilityForTest(t, db, "default", "gpt-4", 1, 10, false) // disabled
  149. ch, err := GetChannel("default", "gpt-4", 0)
  150. assert.NoError(t, err)
  151. assert.Nil(t, ch) // no enabled ability
  152. }
  153. func TestGetChannel_MultipleChannelsWeighted(t *testing.T) {
  154. db := setupChannelSelectDB(t)
  155. createChannelForTest(t, db, 1, "ch1", "default", "gpt-4", 10)
  156. createChannelForTest(t, db, 2, "ch2", "default", "gpt-4", 10)
  157. createAbilityForTest(t, db, "default", "gpt-4", 1, 10, true)
  158. createAbilityForTest(t, db, "default", "gpt-4", 2, 10, true)
  159. // Run multiple times to verify both channels can be selected
  160. found := make(map[int]bool)
  161. for i := 0; i < 50; i++ {
  162. ch, err := GetChannel("default", "gpt-4", 0)
  163. require.NoError(t, err)
  164. require.NotNil(t, ch)
  165. found[ch.Id] = true
  166. }
  167. // With equal weights, both should appear at least once in 50 tries
  168. assert.True(t, found[1], "channel 1 should be selected at least once")
  169. assert.True(t, found[2], "channel 2 should be selected at least once")
  170. }
  171. func TestGetRandomSatisfiedChannelWithFilter_AllCandidatesRejected(t *testing.T) {
  172. db := setupChannelSelectDB(t)
  173. createChannelForTest(t, db, 1, "ch1", "default", "seedance-2", 10)
  174. createChannelForTest(t, db, 2, "ch2", "default", "seedance-2", 10)
  175. createAbilityForTest(t, db, "default", "seedance-2", 1, 10, true)
  176. createAbilityForTest(t, db, "default", "seedance-2", 2, 10, true)
  177. ch, err := GetRandomSatisfiedChannelWithFilter("default", "seedance-2", 0, func(*Channel) (bool, error) {
  178. return false, nil
  179. })
  180. require.NoError(t, err)
  181. assert.Nil(t, ch)
  182. }
  183. func TestGetRandomSatisfiedChannelWithFilter_SelectsOnlyAcceptedCandidate(t *testing.T) {
  184. db := setupChannelSelectDB(t)
  185. createChannelWithTypeForTest(t, db, 1, "openai", "default", "seedance-2", constant.ChannelTypeOpenAI, 10)
  186. createChannelWithTypeForTest(t, db, 2, "doubao", "default", "seedance-2", constant.ChannelTypeDoubaoVideo, 10)
  187. createAbilityForTest(t, db, "default", "seedance-2", 1, 10, true)
  188. createAbilityForTest(t, db, "default", "seedance-2", 2, 10, true)
  189. for i := 0; i < 20; i++ {
  190. ch, err := GetRandomSatisfiedChannelWithFilter("default", "seedance-2", 0, func(channel *Channel) (bool, error) {
  191. return channel.Type == constant.ChannelTypeDoubaoVideo, nil
  192. })
  193. require.NoError(t, err)
  194. require.NotNil(t, ch)
  195. assert.Equal(t, 2, ch.Id)
  196. }
  197. }