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.
 
 
 

190 lines
6.0 KiB

  1. package controller
  2. import (
  3. "bytes"
  4. "net/http"
  5. "net/http/httptest"
  6. "os"
  7. "strings"
  8. "testing"
  9. "time"
  10. "github.com/QuantumNous/new-api/common"
  11. "github.com/QuantumNous/new-api/constant"
  12. "github.com/QuantumNous/new-api/model"
  13. "github.com/gin-gonic/gin"
  14. "github.com/stretchr/testify/require"
  15. "gorm.io/gorm"
  16. "gorm.io/gorm/logger"
  17. )
  18. const chinaMobileAssetE2EImageURL = "https://bkimg.cdn.bcebos.com/pic/caef76094b36acaf2edd2133a78e9a1001e9380136fe?x-bce-process=image/format,f_auto/watermark,image_d2F0ZXIvYmFpa2UyNzI,g_7,xp_5,yp_5,P_20/resize,m_lfit,limit_1,h_1080"
  19. func TestChinaMobileAssetControllerWithRealUpstream(t *testing.T) {
  20. ak := strings.TrimSpace(os.Getenv("CHINAMOBILE_ASSET_AK"))
  21. sk := strings.TrimSpace(os.Getenv("CHINAMOBILE_ASSET_SK"))
  22. poolID := strings.TrimSpace(os.Getenv("CHINAMOBILE_ASSET_POOL_ID"))
  23. if ak == "" || sk == "" {
  24. t.Skip("CHINAMOBILE_ASSET_AK and CHINAMOBILE_ASSET_SK are required")
  25. }
  26. if poolID == "" {
  27. poolID = "CIDC-CORE-00"
  28. }
  29. db := setupRealAssetE2EDB(t)
  30. createDoubaoAssetProxyChannel(t, db, 7101, constant.ChannelTypeChinaMobileSeedance, "default", "video-generation-key", common.ChannelStatusEnabled)
  31. require.NoError(t, model.UpsertChannelAssetCredential(&model.ChannelAssetCredential{
  32. ChannelId: 7101,
  33. AccessKey: ak,
  34. SecretKey: sk,
  35. PoolID: poolID,
  36. }))
  37. router := setupRealAssetE2ERouter()
  38. suffix := time.Now().Format("20060102150405")
  39. groupName := "new-api-e2e-" + suffix
  40. assetName := "new-api-img-" + suffix
  41. var groupId string
  42. var assetId string
  43. defer func() {
  44. if assetId != "" {
  45. code, _ := performRealAssetE2EAction(t, router, "DeleteAsset", map[string]any{"Id": assetId})
  46. require.Equal(t, http.StatusOK, code, "cleanup DeleteAsset failed")
  47. }
  48. if groupId != "" {
  49. code, _ := performRealAssetE2EAction(t, router, "DeleteAssetGroup", map[string]any{"Id": groupId})
  50. require.Equal(t, http.StatusOK, code, "cleanup DeleteAssetGroup failed")
  51. }
  52. }()
  53. code, body := performRealAssetE2EAction(t, router, "CreateAssetGroup", map[string]any{
  54. "Name": groupName,
  55. "GroupType": "AIGC",
  56. "Description": "new-api real e2e test",
  57. })
  58. require.Equal(t, http.StatusOK, code)
  59. groupId = realAssetE2EString(t, body, "Result.GroupId")
  60. require.NotEmpty(t, groupId)
  61. code, body = performRealAssetE2EAction(t, router, "CreateAsset", map[string]any{
  62. "GroupId": groupId,
  63. "Name": assetName,
  64. "URL": chinaMobileAssetE2EImageURL,
  65. "AssetType": "Image",
  66. })
  67. require.Equal(t, http.StatusOK, code)
  68. assetId = realAssetE2EString(t, body, "Result")
  69. require.NotEmpty(t, assetId)
  70. var status string
  71. for i := 0; i < 6; i++ {
  72. code, body = performRealAssetE2EAction(t, router, "GetAsset", map[string]any{"Id": assetId})
  73. require.Equal(t, http.StatusOK, code)
  74. require.Equal(t, assetId, realAssetE2EString(t, body, "Result.Id"))
  75. status = realAssetE2EString(t, body, "Result.Status")
  76. if status != "Processing" {
  77. break
  78. }
  79. time.Sleep(3 * time.Second)
  80. }
  81. require.Equal(t, "Active", status)
  82. code, body = performRealAssetE2EAction(t, router, "ListAssets", map[string]any{
  83. "PageNumber": 1,
  84. "PageSize": 10,
  85. "Filter": map[string]any{
  86. "GroupType": "AIGC",
  87. "GroupIds": []string{groupId},
  88. },
  89. })
  90. require.Equal(t, http.StatusOK, code)
  91. require.Equal(t, float64(1), realAssetE2EValue(t, body, "Result.TotalCount"))
  92. }
  93. func setupRealAssetE2EDB(t *testing.T) *gorm.DB {
  94. t.Helper()
  95. oldDB := model.DB
  96. oldSQLitePath := common.SQLitePath
  97. oldMemoryCacheEnabled := common.MemoryCacheEnabled
  98. oldIsMasterNode := common.IsMasterNode
  99. oldUsingSQLite := common.UsingSQLite
  100. oldUsingMySQL := common.UsingMySQL
  101. oldUsingPostgreSQL := common.UsingPostgreSQL
  102. oldSQLDSN, hadSQLDSN := os.LookupEnv("SQL_DSN")
  103. common.SQLitePath = "file:" + strings.NewReplacer("/", "_", " ", "_").Replace(t.Name()) + "?mode=memory&cache=shared"
  104. common.MemoryCacheEnabled = false
  105. common.IsMasterNode = false
  106. common.UsingSQLite = false
  107. common.UsingMySQL = false
  108. common.UsingPostgreSQL = false
  109. require.NoError(t, os.Setenv("SQL_DSN", "local"))
  110. require.NoError(t, model.InitDB())
  111. model.DB = model.DB.Session(&gorm.Session{Logger: logger.Default.LogMode(logger.Silent)})
  112. db := model.DB
  113. sqlDB, err := db.DB()
  114. require.NoError(t, err)
  115. sqlDB.SetMaxOpenConns(1)
  116. require.NoError(t, db.AutoMigrate(&model.Channel{}, &model.Ability{}, &model.UserAssetChannel{}, &model.ChannelAssetCredential{}))
  117. t.Cleanup(func() {
  118. _ = sqlDB.Close()
  119. model.DB = oldDB
  120. common.SQLitePath = oldSQLitePath
  121. common.MemoryCacheEnabled = oldMemoryCacheEnabled
  122. common.IsMasterNode = oldIsMasterNode
  123. common.UsingSQLite = oldUsingSQLite
  124. common.UsingMySQL = oldUsingMySQL
  125. common.UsingPostgreSQL = oldUsingPostgreSQL
  126. if hadSQLDSN {
  127. _ = os.Setenv("SQL_DSN", oldSQLDSN)
  128. } else {
  129. _ = os.Unsetenv("SQL_DSN")
  130. }
  131. })
  132. return db
  133. }
  134. func setupRealAssetE2ERouter() *gin.Engine {
  135. router := gin.New()
  136. router.Use(func(c *gin.Context) {
  137. c.Set("id", 10)
  138. common.SetContextKey(c, constant.ContextKeyUsingGroup, "default")
  139. c.Next()
  140. })
  141. router.POST("/api/v1/volcengine/asset", DoubaoAssetProxy)
  142. return router
  143. }
  144. func performRealAssetE2EAction(t *testing.T, router *gin.Engine, action string, payload map[string]any) (int, string) {
  145. t.Helper()
  146. data, err := common.Marshal(payload)
  147. require.NoError(t, err)
  148. req := httptest.NewRequest(http.MethodPost, "/api/v1/volcengine/asset?Action="+action, bytes.NewReader(data))
  149. req.Header.Set("Content-Type", "application/json")
  150. w := httptest.NewRecorder()
  151. router.ServeHTTP(w, req)
  152. return w.Code, w.Body.String()
  153. }
  154. func realAssetE2EString(t *testing.T, data string, path string) string {
  155. t.Helper()
  156. value := realAssetE2EValue(t, data, path)
  157. s, ok := value.(string)
  158. require.Truef(t, ok, "%s is not a string: %#v", path, value)
  159. return s
  160. }
  161. func realAssetE2EValue(t *testing.T, data string, path string) any {
  162. t.Helper()
  163. var payload map[string]any
  164. require.NoError(t, common.Unmarshal([]byte(data), &payload))
  165. current := any(payload)
  166. for _, part := range strings.Split(path, ".") {
  167. m, ok := current.(map[string]any)
  168. require.Truef(t, ok, "%s is not an object at %s", path, part)
  169. current = m[part]
  170. }
  171. return current
  172. }