项目文件夹

文件
2026-07-14 10:24:10 +08:00

78 行
2.4 KiB
Go

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
package sse_test
import (
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/EthanCodeCraft/xlgo-core/sse"
"github.com/gin-gonic/gin"
)
// ===== C3a:断连即停(核心) =====
// 回归 C3a:断连即停由 internal testsse_stream_internal_test.go,TestStreamStopsOnCtxCancelInternal
// 权威覆盖——直接构造 SSEWriter + 可控 ctx,验证 Stream 在 ctx.Done 时返回 ctx.Err。
// StreamText/StreamChunks/StreamWithID 用相同 select 模式(代码审查保证),外部网络断连测试
// 因 httptest loopback 下 c.Request.Context() 取消时序不可靠而省略,internal test 为权威。
// ===== C3a:正常完成路径仍工作 =====
// 回归:ch 正常关闭时 StreamText 写 done 并返回 nil。
func TestStreamTextNormalCompletion(t *testing.T) {
ch := make(chan string, 3)
ch <- "a"
ch <- "b"
close(ch)
r := gin.New()
r.GET("/sse", func(c *gin.Context) {
err := sse.StreamText(c, ch)
if err != nil {
t.Errorf("StreamText normal completion err: %v", err)
}
})
srv := httptest.NewServer(r)
defer srv.Close()
resp, err := http.Get(srv.URL + "/sse")
if err != nil {
t.Fatalf("connect: %v", err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if !strings.Contains(string(body), `"text":"a"`) || !strings.Contains(string(body), `"text":"b"`) {
t.Errorf("body missing chunks: %s", string(body))
}
if !strings.Contains(string(body), "event: done") {
t.Errorf("body missing done event: %s", string(body))
}
}
// ===== C3c:不手设 Transfer-Encoding: chunked =====
// 回归 C3c:响应头不应含 Transfer-Encoding: chunkedHTTP/2 下非法,HTTP/1.1 冗余)。
func TestNewSSEWriterNoChunkedHeader(t *testing.T) {
r := gin.New()
r.GET("/sse", func(c *gin.Context) {
_, _ = sse.NewSSEWriter(c)
})
w := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/sse", nil)
r.ServeHTTP(w, req)
if got := w.Header().Get("Transfer-Encoding"); got != "" {
t.Errorf("Transfer-Encoding = %q, want empty (C3c: should not hand-set chunked)", got)
}
}
// ===== C3b:上游生产者契约文档化 =====
// StreamText 在 ctx.Done 后返回 ctx.Err;生产者(往 ch 发送者)应监听同一 ctx,
// 在取消时停止上游 LLM 流。本框架无法单方面停止生产者,调用方契约见 StreamText 注释。
// 该契约由 TestStreamTextStopsOnContextCancel 间接验证(StreamText 确实因 ctx.Done 退出)。