Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 

251 Zeilen
9.1 KiB

  1. package controller
  2. import (
  3. "io"
  4. "net/http"
  5. "net/http/httptest"
  6. "strings"
  7. "testing"
  8. "github.com/QuantumNous/new-api/common"
  9. "github.com/QuantumNous/new-api/constant"
  10. "github.com/QuantumNous/new-api/dto"
  11. "github.com/QuantumNous/new-api/model"
  12. klingaiping "github.com/QuantumNous/new-api/relay/channel/task/kling/aiping"
  13. relaycommon "github.com/QuantumNous/new-api/relay/common"
  14. "github.com/QuantumNous/new-api/service"
  15. "github.com/gin-gonic/gin"
  16. "github.com/stretchr/testify/require"
  17. )
  18. func TestKlingAipingSubmitPreparationUsesModelNameBeforeModel(t *testing.T) {
  19. c := newControllerJSONContext(t, "/v1/videos/text2video", `{
  20. "model":"Kling-V1.6",
  21. "model_name":"Kling-V2.6",
  22. "prompt":"prompt"
  23. }`)
  24. payload, err := readJSONPayload(c)
  25. require.NoError(t, err)
  26. route, ok := klingaiping.FindRoute(http.MethodPost, "/v1/videos/text2video", klingaiping.RouteKindSubmit)
  27. require.True(t, ok)
  28. info := &relaycommon.RelayInfo{TaskRelayInfo: &relaycommon.TaskRelayInfo{}}
  29. modelName := resolveKlingAipingModel(payload, route)
  30. relaycommon.StoreTaskRequest(c, info, route.Action, relaycommon.TaskSubmitReq{
  31. Model: modelName,
  32. Prompt: stringFromMap(payload, "prompt"),
  33. Metadata: payload,
  34. })
  35. stored, err := relaycommon.GetTaskRequest(c)
  36. require.NoError(t, err)
  37. require.Equal(t, "Kling-V2.6", stored.Model)
  38. require.Equal(t, "prompt", stored.Prompt)
  39. require.Equal(t, "Kling-V1.6", stored.Metadata["model"])
  40. require.Equal(t, "Kling-V2.6", stored.Metadata["model_name"])
  41. }
  42. func TestKlingAipingSubmitPreparationDoesNotLockChannel(t *testing.T) {
  43. c := newControllerJSONContext(t, "/v1/general/custom-voices", `{
  44. "voice_url":"https://example.com/voice.mp3",
  45. "voice_name":"voice"
  46. }`)
  47. payload, err := readJSONPayload(c)
  48. require.NoError(t, err)
  49. route, ok := klingaiping.FindRoute(http.MethodPost, "/v1/general/custom-voices", klingaiping.RouteKindSubmit)
  50. require.True(t, ok)
  51. info := &relaycommon.RelayInfo{TaskRelayInfo: &relaycommon.TaskRelayInfo{}}
  52. info.OriginModelName = resolveKlingAipingModel(payload, route)
  53. info.Action = route.Action
  54. relaycommon.StoreTaskRequest(c, info, route.Action, relaycommon.TaskSubmitReq{
  55. Model: info.OriginModelName,
  56. Metadata: payload,
  57. })
  58. require.Equal(t, klingaiping.ModelCustomVoices, info.OriginModelName)
  59. require.Equal(t, klingaiping.ActionVoicesCreate, info.Action)
  60. require.Nil(t, info.LockedChannel)
  61. }
  62. func TestConfigureKlingAipingTaskRelayInfoForcesChannelSelection(t *testing.T) {
  63. c := newControllerJSONContext(t, "/v1/videos/text2video", `{"model_name":"Kling-V2.6","prompt":"prompt"}`)
  64. payload, err := readJSONPayload(c)
  65. require.NoError(t, err)
  66. route, ok := klingaiping.FindRoute(http.MethodPost, "/v1/videos/text2video", klingaiping.RouteKindSubmit)
  67. require.True(t, ok)
  68. info := &relaycommon.RelayInfo{TaskRelayInfo: &relaycommon.TaskRelayInfo{}}
  69. configureKlingAipingTaskRelayInfo(c, info, route, payload)
  70. require.NotNil(t, info.ChannelMeta)
  71. require.Zero(t, info.ChannelMeta.ChannelType)
  72. require.Equal(t, "Kling-V2.6", info.OriginModelName)
  73. require.Equal(t, klingaiping.ActionText2Video, info.Action)
  74. require.Nil(t, info.LockedChannel)
  75. }
  76. func TestConfigureKlingAipingTaskRelayInfoStoresDuration(t *testing.T) {
  77. c := newControllerJSONContext(t, "/v1/videos/text2video", `{"model_name":"Kling-V2.6","prompt":"prompt","duration":5}`)
  78. payload, err := readJSONPayload(c)
  79. require.NoError(t, err)
  80. route, ok := klingaiping.FindRoute(http.MethodPost, "/v1/videos/text2video", klingaiping.RouteKindSubmit)
  81. require.True(t, ok)
  82. info := &relaycommon.RelayInfo{TaskRelayInfo: &relaycommon.TaskRelayInfo{}}
  83. configureKlingAipingTaskRelayInfo(c, info, route, payload)
  84. stored, err := relaycommon.GetTaskRequest(c)
  85. require.NoError(t, err)
  86. require.Equal(t, 5, stored.Duration)
  87. require.Empty(t, stored.Seconds)
  88. }
  89. func TestRequiredTaskChannelTypeOnlyMatchesKlingAipingNativePaths(t *testing.T) {
  90. c := newControllerJSONContext(t, "/v1/videos/text2video", `{}`)
  91. c.Request.URL.Path = "/v1/videos/text2video"
  92. require.Zero(t, requiredTaskChannelTypeForRequest(c))
  93. require.ElementsMatch(t,
  94. service.VideoAssetChannelTypesForFamily(service.VideoAssetFamilyKling),
  95. allowedTaskChannelTypesForRequest(c),
  96. )
  97. c = newControllerJSONContext(t, "/v1/videos/video-extend", `{}`)
  98. c.Request.URL.Path = "/v1/videos/video-extend"
  99. require.Zero(t, requiredTaskChannelTypeForRequest(c))
  100. require.ElementsMatch(t,
  101. service.VideoAssetChannelTypesForFamily(service.VideoAssetFamilyKling),
  102. allowedTaskChannelTypesForRequest(c),
  103. )
  104. c = newControllerJSONContext(t, "/v1/videos/video_123/remix", `{}`)
  105. c.Request.URL.Path = "/v1/videos/video_123/remix"
  106. require.Zero(t, requiredTaskChannelTypeForRequest(c))
  107. require.Nil(t, allowedTaskChannelTypesForRequest(c))
  108. }
  109. func TestKlingAipingTaskDataObjectUsesPublicTaskIDAndWatermarkURL(t *testing.T) {
  110. task := &model.Task{
  111. TaskID: "task_public",
  112. Status: model.TaskStatusSuccess,
  113. CreatedAt: 100,
  114. UpdatedAt: 200,
  115. Data: []byte(`{
  116. "code":0,
  117. "aiping_id":"internal",
  118. "data":{
  119. "task_id":"899333358055493641",
  120. "task_status":"succeed",
  121. "task_result":{"videos":[{"id":"v1","url":"https://example.com/video.mp4","duration":"5.041"}]}
  122. }
  123. }`),
  124. }
  125. data := taskDataObject(task)
  126. require.Equal(t, "task_public", data["task_id"])
  127. taskResult := data["task_result"].(map[string]any)
  128. videos := taskResult["videos"].([]any)
  129. require.Equal(t, "", videos[0].(map[string]any)["watermark_url"])
  130. }
  131. func TestDoKlingAipingProxyRequestUsesSelectedContextKey(t *testing.T) {
  132. service.InitHttpClient()
  133. var gotAuth string
  134. server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  135. gotAuth = r.Header.Get("Authorization")
  136. w.Header().Set("Content-Type", "application/json")
  137. _, _ = w.Write([]byte(`{"code":0,"message":"success","data":[]}`))
  138. }))
  139. defer server.Close()
  140. c := newControllerJSONContext(t, "/v1/general/advanced-presets-elements", ``)
  141. common.SetContextKey(c, constant.ContextKeyChannelKey, "selected-key")
  142. route, ok := klingaiping.FindRoute(http.MethodGet, "/v1/general/advanced-presets-elements", klingaiping.RouteKindProxy)
  143. require.True(t, ok)
  144. channel := &model.Channel{
  145. Key: "raw-channel-key",
  146. BaseURL: common.GetPointer(server.URL),
  147. }
  148. resp, err := doKlingAipingProxyRequest(c, route, channel)
  149. require.NoError(t, err)
  150. defer resp.Body.Close()
  151. require.Equal(t, "Bearer selected-key", gotAuth)
  152. }
  153. func TestCopyProxyResponseNormalizesMsgError(t *testing.T) {
  154. w := httptest.NewRecorder()
  155. c, _ := gin.CreateTestContext(w)
  156. c.Set(common.RequestIdKey, "req-test")
  157. resp := &http.Response{
  158. StatusCode: http.StatusUnauthorized,
  159. Header: http.Header{"Content-Type": []string{"application/json"}},
  160. Body: io.NopCloser(strings.NewReader(`{"code":401,"msg":"unauthorized","data":null}`)),
  161. }
  162. copyProxyResponse(c, resp)
  163. require.Equal(t, http.StatusUnauthorized, w.Code)
  164. require.Contains(t, w.Body.String(), `"message":"unauthorized"`)
  165. require.NotContains(t, w.Body.String(), `"msg"`)
  166. require.Contains(t, w.Body.String(), `"request_id":"req-test"`)
  167. }
  168. func TestCopyProxyResponseNormalizesPlainTextError(t *testing.T) {
  169. w := httptest.NewRecorder()
  170. c, _ := gin.CreateTestContext(w)
  171. c.Set(common.RequestIdKey, "req-test")
  172. resp := &http.Response{
  173. StatusCode: http.StatusMethodNotAllowed,
  174. Header: http.Header{"Content-Type": []string{"text/plain"}},
  175. Body: io.NopCloser(strings.NewReader("Method Not Allowed")),
  176. }
  177. copyProxyResponse(c, resp)
  178. require.Equal(t, http.StatusMethodNotAllowed, w.Code)
  179. require.Contains(t, w.Body.String(), `"message":"Method Not Allowed"`)
  180. require.Contains(t, w.Body.String(), `"request_id":"req-test"`)
  181. }
  182. func TestCopyProxyResponseNormalizesDetailMessageError(t *testing.T) {
  183. w := httptest.NewRecorder()
  184. c, _ := gin.CreateTestContext(w)
  185. c.Set(common.RequestIdKey, "req-test")
  186. resp := &http.Response{
  187. StatusCode: http.StatusServiceUnavailable,
  188. Header: http.Header{"Content-Type": []string{"application/json"}},
  189. Body: io.NopCloser(strings.NewReader(`{"detail":{"message":"not found","error_type":"not_found"},"aiping_id":"internal"}`)),
  190. }
  191. copyProxyResponse(c, resp)
  192. require.Equal(t, http.StatusServiceUnavailable, w.Code)
  193. require.Contains(t, w.Body.String(), `"message":"not found"`)
  194. require.NotContains(t, w.Body.String(), `map[`)
  195. require.Contains(t, w.Body.String(), `"request_id":"req-test"`)
  196. }
  197. func TestNormalizeKlingAipingTaskErrorMessageExtractsUpstreamJSONMessage(t *testing.T) {
  198. taskErr := &dto.TaskError{
  199. Code: "fail_to_fetch_task",
  200. Message: `{"code":400,"message":"ERROR: image download failed","request_id":"upstream"}`,
  201. StatusCode: http.StatusBadRequest,
  202. }
  203. normalizeKlingAipingTaskError(taskErr)
  204. require.Equal(t, "ERROR: image download failed", taskErr.Message)
  205. }
  206. func TestParseKlingAipingPageBoundaries(t *testing.T) {
  207. c := newControllerJSONContext(t, "/v1/videos/text2video?pageNum=1001&pageSize=30", `{}`)
  208. c.Request.URL.RawQuery = "pageNum=1001&pageSize=30"
  209. _, _, err := parseKlingAipingPage(c)
  210. require.ErrorContains(t, err, "pageNum")
  211. c = newControllerJSONContext(t, "/v1/videos/text2video?pageNum=1&pageSize=501", `{}`)
  212. c.Request.URL.RawQuery = "pageNum=1&pageSize=501"
  213. _, _, err = parseKlingAipingPage(c)
  214. require.ErrorContains(t, err, "pageSize")
  215. }