From a23b28c27d2735094c015946715bb936b971bda1 Mon Sep 17 00:00:00 2001 From: easyai Date: Wed, 22 Jul 2026 08:56:30 +0800 Subject: [PATCH] =?UTF-8?q?test(api):=20=E7=AD=89=E5=BE=85=E5=BC=82?= =?UTF-8?q?=E6=AD=A5=E4=BB=BB=E5=8A=A1=E5=AE=8C=E6=88=90=E5=90=8E=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E7=BB=93=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 真实队列环境中 X-Async 请求会先返回 queued。集成测试改为轮询任务完成并重新读取详情,避免把正确的异步受理状态误判为失败。 --- apps/api/internal/httpapi/core_flow_integration_test.go | 9 +++++++++ .../httpapi/keling_simulation_integration_test.go | 5 +++++ .../internal/httpapi/kling_compat_integration_test.go | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/apps/api/internal/httpapi/core_flow_integration_test.go b/apps/api/internal/httpapi/core_flow_integration_test.go index 59dc203..d9f4b0c 100644 --- a/apps/api/internal/httpapi/core_flow_integration_test.go +++ b/apps/api/internal/httpapi/core_flow_integration_test.go @@ -513,6 +513,8 @@ VALUES ($1, 5, '{"purpose":"core-flow"}'::jsonb)`, inviteCode); err != nil { "simulation": true, "simulationDurationMs": 5, }, map[string]string{"X-Async": "true"}, http.StatusAccepted, &imageResponse) + waitForTaskStatus(t, server.URL, apiKeyResponse.Secret, imageResponse.Task.ID, []string{"succeeded"}, 10*time.Second) + doJSON(t, server.URL, http.MethodGet, "/api/v1/tasks/"+imageResponse.Task.ID, apiKeyResponse.Secret, nil, http.StatusOK, &imageResponse.Task) if imageResponse.Task.Status != "succeeded" || imageResponse.Task.Result["id"] == "" { t.Fatalf("unexpected image generation task: %+v", imageResponse.Task) } @@ -533,6 +535,8 @@ VALUES ($1, 5, '{"purpose":"core-flow"}'::jsonb)`, inviteCode); err != nil { "simulation": true, "simulationDurationMs": 5, }, map[string]string{"X-Async": "true"}, http.StatusAccepted, &imageEditResponse) + waitForTaskStatus(t, server.URL, apiKeyResponse.Secret, imageEditResponse.Task.ID, []string{"succeeded"}, 10*time.Second) + doJSON(t, server.URL, http.MethodGet, "/api/v1/tasks/"+imageEditResponse.Task.ID, apiKeyResponse.Secret, nil, http.StatusOK, &imageEditResponse.Task) if imageEditResponse.Task.Status != "succeeded" || imageEditResponse.Task.Result["id"] == "" { t.Fatalf("unexpected image edit task: %+v", imageEditResponse.Task) } @@ -1196,6 +1200,7 @@ WHERE reference_type = 'gateway_task' }, http.StatusCreated, &videoRoutePlatformModel) var textToVideoTask struct { Task struct { + ID string `json:"id"` Status string `json:"status"` ModelType string `json:"modelType"` } `json:"task"` @@ -1207,6 +1212,8 @@ WHERE reference_type = 'gateway_task' "simulationDurationMs": 5, "prompt": "text to video route", }, map[string]string{"X-Async": "true"}, http.StatusAccepted, &textToVideoTask) + waitForTaskStatus(t, server.URL, apiKeyResponse.Secret, textToVideoTask.Task.ID, []string{"succeeded"}, 10*time.Second) + doJSON(t, server.URL, http.MethodGet, "/api/v1/tasks/"+textToVideoTask.Task.ID, apiKeyResponse.Secret, nil, http.StatusOK, &textToVideoTask.Task) if textToVideoTask.Task.Status != "succeeded" || textToVideoTask.Task.ModelType != "video_generate" { t.Fatalf("text-to-video request should use video_generate model_type: %+v", textToVideoTask.Task) } @@ -1226,6 +1233,8 @@ WHERE reference_type = 'gateway_task' "prompt": "image to video route", "image": "https://example.com/source.png", }, map[string]string{"X-Async": "true"}, http.StatusAccepted, &imageToVideoTask) + waitForTaskStatus(t, server.URL, apiKeyResponse.Secret, imageToVideoTask.Task.ID, []string{"succeeded"}, 10*time.Second) + doJSON(t, server.URL, http.MethodGet, "/api/v1/tasks/"+imageToVideoTask.Task.ID, apiKeyResponse.Secret, nil, http.StatusOK, &imageToVideoTask.Task) if imageToVideoTask.Task.Status != "succeeded" || imageToVideoTask.Task.ModelType != "image_to_video" { t.Fatalf("image-to-video request should use image_to_video model_type: %+v", imageToVideoTask.Task) } diff --git a/apps/api/internal/httpapi/keling_simulation_integration_test.go b/apps/api/internal/httpapi/keling_simulation_integration_test.go index ecdca2d..66eb657 100644 --- a/apps/api/internal/httpapi/keling_simulation_integration_test.go +++ b/apps/api/internal/httpapi/keling_simulation_integration_test.go @@ -145,6 +145,11 @@ WHERE username = $1`, username); err != nil { http.StatusAccepted, &response, ) + if response.Task.ID == "" { + t.Fatal("async Kling simulation response did not return a task id") + } + waitForTaskStatus(t, server.URL, apiKeyResponse.Secret, response.Task.ID, []string{"succeeded"}, 10*time.Second) + doJSON(t, server.URL, http.MethodGet, "/api/v1/tasks/"+response.Task.ID, apiKeyResponse.Secret, nil, http.StatusOK, &response.Task) task := response.Task if task.ID == "" || diff --git a/apps/api/internal/httpapi/kling_compat_integration_test.go b/apps/api/internal/httpapi/kling_compat_integration_test.go index 15cc410..9b9afb5 100644 --- a/apps/api/internal/httpapi/kling_compat_integration_test.go +++ b/apps/api/internal/httpapi/kling_compat_integration_test.go @@ -138,12 +138,18 @@ WHERE platform_id = $1::uuid } var response struct { Task struct { + ID string `json:"id"` Status string `json:"status"` ModelType string `json:"modelType"` ResolvedModel string `json:"resolvedModel"` } `json:"task"` } doJSONWithHeaders(t, server.URL, http.MethodPost, "/api/v1/videos/generations", apiKeyResponse.Secret, request, map[string]string{"X-Async": "true"}, http.StatusAccepted, &response) + if response.Task.ID == "" { + t.Fatal("async generic video response did not return a task id") + } + waitForTaskStatus(t, server.URL, apiKeyResponse.Secret, response.Task.ID, []string{"succeeded"}, 10*time.Second) + doJSON(t, server.URL, http.MethodGet, "/api/v1/tasks/"+response.Task.ID, apiKeyResponse.Secret, nil, http.StatusOK, &response.Task) resolvedModel, resolved := klingV2ProviderModel(response.Task.ResolvedModel) if response.Task.Status != "succeeded" || response.Task.ModelType != expectedModelType || !resolved || resolvedModel != model { t.Fatalf("generic video request without modelType should use inferred capability: %+v", response.Task)