package com.gxwebsoft.ai.controller; import com.gxwebsoft.common.core.web.ApiResult; import org.junit.jupiter.api.Test; import java.util.LinkedHashMap; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; /** * SSE 末帧格式的回归测试。 * *

出图这类「业务方法自己不推帧、只返回一个结果」的链路,结果靠末帧下发; * 端上按 {@code type === 'final'} 识别。字段名一旦改了而端上没改, * 表现为「流正常结束但页面一直转圈」,不容易在联调时发现,所以钉死格式。 */ public class AiControllerSseFrameTest { @Test public void finalFrameMarksTypeAndKeepsResult() { Map data = new LinkedHashMap<>(); data.put("photo_files", "[\"https://example.com/a.jpeg\"]"); String json = AiController.finalFrameJson(new ApiResult<>(0, "ok", data)); assertTrue(json.contains("\"type\":\"final\""), "末帧必须带 type=final,端上靠它区分业务帧"); assertTrue(json.contains("\"result\":{"), "业务返回值要原样放在 result 里"); assertTrue(json.contains("photo_files"), "返回体里的字段不能丢"); assertEquals(1, countOccurrences(json, "\"type\":"), "末帧只能有一个 type 字段"); } @Test public void finalFrameKeepsStringResult() { String json = AiController.finalFrameJson("plain-text"); assertTrue(json.contains("\"result\":\"plain-text\"")); } private static int countOccurrences(String text, String needle) { int count = 0; int index = text.indexOf(needle); while (index != -1) { count++; index = text.indexOf(needle, index + needle.length()); } return count; } }