You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

206 lines
6.3 KiB

  1. package middleware
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/http/httptest"
  6. "os"
  7. "strings"
  8. "testing"
  9. "github.com/QuantumNous/new-api/common"
  10. "github.com/QuantumNous/new-api/constant"
  11. "github.com/QuantumNous/new-api/model"
  12. relayconstant "github.com/QuantumNous/new-api/relay/constant"
  13. "github.com/gin-gonic/gin"
  14. "github.com/stretchr/testify/assert"
  15. "github.com/stretchr/testify/require"
  16. "gorm.io/gorm"
  17. "gorm.io/gorm/logger"
  18. )
  19. func setupDoubaoVideoBindingDB(t *testing.T) *gorm.DB {
  20. t.Helper()
  21. oldDB := model.DB
  22. oldLOGDB := model.LOG_DB
  23. oldSQLitePath := common.SQLitePath
  24. oldMemoryCacheEnabled := common.MemoryCacheEnabled
  25. oldIsMasterNode := common.IsMasterNode
  26. oldUsingSQLite := common.UsingSQLite
  27. oldUsingMySQL := common.UsingMySQL
  28. oldUsingPostgreSQL := common.UsingPostgreSQL
  29. oldSQLDSN, hadSQLDSN := os.LookupEnv("SQL_DSN")
  30. common.SQLitePath = "file:" + strings.NewReplacer("/", "_", " ", "_").Replace(t.Name()) + "?mode=memory&cache=shared"
  31. common.MemoryCacheEnabled = false
  32. common.IsMasterNode = false
  33. common.UsingSQLite = false
  34. common.UsingMySQL = false
  35. common.UsingPostgreSQL = false
  36. require.NoError(t, os.Setenv("SQL_DSN", "local"))
  37. require.NoError(t, model.InitDB())
  38. model.DB = model.DB.Session(&gorm.Session{Logger: logger.Default.LogMode(logger.Silent)})
  39. db := model.DB
  40. sqlDB, err := db.DB()
  41. require.NoError(t, err)
  42. sqlDB.SetMaxOpenConns(1)
  43. require.NoError(t, db.AutoMigrate(&model.Channel{}, &model.Ability{}, &model.UserAssetChannel{}))
  44. t.Cleanup(func() {
  45. _ = sqlDB.Close()
  46. model.DB = oldDB
  47. model.LOG_DB = oldLOGDB
  48. common.SQLitePath = oldSQLitePath
  49. common.MemoryCacheEnabled = oldMemoryCacheEnabled
  50. common.IsMasterNode = oldIsMasterNode
  51. common.UsingSQLite = oldUsingSQLite
  52. common.UsingMySQL = oldUsingMySQL
  53. common.UsingPostgreSQL = oldUsingPostgreSQL
  54. if hadSQLDSN {
  55. _ = os.Setenv("SQL_DSN", oldSQLDSN)
  56. } else {
  57. _ = os.Unsetenv("SQL_DSN")
  58. }
  59. })
  60. return db
  61. }
  62. func doubaoVideoChannelForBindingTest(id int, group string) *model.Channel {
  63. priority := int64(id)
  64. weight := uint(10)
  65. autoBan := 1
  66. return &model.Channel{
  67. Id: id,
  68. Type: constant.ChannelTypeDoubaoVideoCompatibleAiping,
  69. Key: fmt.Sprintf("key-%d", id),
  70. Status: common.ChannelStatusEnabled,
  71. Name: fmt.Sprintf("doubao-video-%d", id),
  72. Group: group,
  73. Models: "seedance-2",
  74. Priority: &priority,
  75. Weight: &weight,
  76. AutoBan: &autoBan,
  77. }
  78. }
  79. func tianyiyunVideoChannelForBindingTest(id int, group string) *model.Channel {
  80. channel := doubaoVideoChannelForBindingTest(id, group)
  81. channel.Type = constant.ChannelTypeDoubaoVideoCompatibleTianyiYun
  82. channel.Models = "cdance2.0-0611"
  83. return channel
  84. }
  85. func TestPreferBoundDoubaoVideoChannel(t *testing.T) {
  86. db := setupDoubaoVideoBindingDB(t)
  87. channel := doubaoVideoChannelForBindingTest(77, "default")
  88. priority := int64(channel.Id)
  89. require.NoError(t, db.Create(&model.Ability{
  90. Group: "default",
  91. Model: "seedance-2",
  92. ChannelId: channel.Id,
  93. Enabled: true,
  94. Priority: &priority,
  95. Weight: 10,
  96. }).Error)
  97. assert.True(t, shouldUseBoundDoubaoVideoChannel(nil, channel, "default", "seedance-2"))
  98. }
  99. func TestPersistDoubaoVideoBindingSkipsNonDoubaoWithoutDB(t *testing.T) {
  100. oldDB := model.DB
  101. model.DB = nil
  102. t.Cleanup(func() {
  103. model.DB = oldDB
  104. })
  105. err := persistDoubaoVideoBindingIfNeeded(10, "default", &model.Channel{
  106. Id: 88,
  107. Type: constant.ChannelTypeOpenAI,
  108. Status: common.ChannelStatusEnabled,
  109. Key: "openai-key",
  110. Group: "default",
  111. })
  112. require.NoError(t, err)
  113. }
  114. func TestPersistDoubaoVideoBindingSkipsBlankAndAutoGroupWithoutDB(t *testing.T) {
  115. oldDB := model.DB
  116. model.DB = nil
  117. t.Cleanup(func() {
  118. model.DB = oldDB
  119. })
  120. require.NoError(t, persistDoubaoVideoBindingIfNeeded(10, "", doubaoVideoChannelForBindingTest(89, "")))
  121. require.NoError(t, persistDoubaoVideoBindingIfNeeded(10, "auto", doubaoVideoChannelForBindingTest(90, "auto")))
  122. }
  123. func TestPersistDoubaoVideoBindingWritesBinding(t *testing.T) {
  124. setupDoubaoVideoBindingDB(t)
  125. channel := doubaoVideoChannelForBindingTest(99, "vip")
  126. require.NoError(t, persistDoubaoVideoBindingIfNeeded(10, "vip", channel))
  127. binding, err := model.GetUserAssetChannel(10, constant.ChannelTypeDoubaoVideoCompatibleAiping, "vip")
  128. require.NoError(t, err)
  129. require.NotNil(t, binding)
  130. assert.Equal(t, channel.Id, binding.ChannelId)
  131. }
  132. func TestPersistDoubaoVideoBindingWritesTianyiYunBindingByType(t *testing.T) {
  133. setupDoubaoVideoBindingDB(t)
  134. channel := tianyiyunVideoChannelForBindingTest(199, "vip")
  135. require.NoError(t, persistDoubaoVideoBindingIfNeeded(10, "vip", channel))
  136. binding, err := model.GetUserAssetChannel(10, constant.ChannelTypeDoubaoVideoCompatibleTianyiYun, "vip")
  137. require.NoError(t, err)
  138. require.NotNil(t, binding)
  139. assert.Equal(t, channel.Id, binding.ChannelId)
  140. }
  141. func TestShouldCheckDoubaoVideoBindingPreferenceSkipsNonVideoRelayMode(t *testing.T) {
  142. c, _ := gin.CreateTestContext(nil)
  143. c.Set("relay_mode", relayconstant.RelayModeChatCompletions)
  144. assert.False(t, shouldCheckDoubaoVideoBindingPreference(c, "default", "seedance-2"))
  145. }
  146. func TestShouldCheckDoubaoVideoBindingPreferenceRequiresVideoSubmitRelayMode(t *testing.T) {
  147. db := setupDoubaoVideoBindingDB(t)
  148. channel := doubaoVideoChannelForBindingTest(101, "default")
  149. require.NoError(t, db.Create(channel).Error)
  150. require.NoError(t, db.Create(&model.Ability{
  151. Group: "default",
  152. Model: "seedance-2",
  153. ChannelId: channel.Id,
  154. Enabled: true,
  155. }).Error)
  156. c, _ := gin.CreateTestContext(nil)
  157. c.Set("relay_mode", relayconstant.RelayModeVideoSubmit)
  158. assert.True(t, shouldCheckDoubaoVideoBindingPreference(c, "default", "seedance-2"))
  159. }
  160. func TestRequiredChannelTypeForSeedanceTasksUsesModelSpecificChannel(t *testing.T) {
  161. c, _ := gin.CreateTestContext(nil)
  162. c.Request = httptest.NewRequest(http.MethodPost, "/api/v3/contents/generations/tasks", strings.NewReader(`{}`))
  163. require.Equal(t, constant.ChannelTypeDoubaoVideoCompatibleTianyiYun, requiredChannelTypeForRequest(c, "cdance2.0-0611"))
  164. require.Equal(t, constant.ChannelTypeDoubaoVideoCompatibleAiping, requiredChannelTypeForRequest(c, "doubao-seedance-2-0-260128"))
  165. }
  166. func TestShouldPersistDoubaoVideoBindingRequiresVideoSubmitRelayMode(t *testing.T) {
  167. c, _ := gin.CreateTestContext(nil)
  168. c.Set("relay_mode", relayconstant.RelayModeChatCompletions)
  169. assert.False(t, shouldPersistDoubaoVideoBinding(c))
  170. c.Set("relay_mode", relayconstant.RelayModeVideoSubmit)
  171. assert.True(t, shouldPersistDoubaoVideoBinding(c))
  172. }