Defer locked-period supplements to a pending ledger, route duty-holder notifications, persist stage-scoped comments, and prefer Approver for reopen.
59 lines
2.0 KiB
Go
59 lines
2.0 KiB
Go
package server_test
|
||
|
||
import (
|
||
"net/http"
|
||
"net/http/httptest"
|
||
"strings"
|
||
"testing"
|
||
"time"
|
||
|
||
"chat-agent-system/internal/bizdev"
|
||
"chat-agent-system/internal/config"
|
||
"chat-agent-system/internal/server"
|
||
)
|
||
|
||
// TestChatStream_GetMessageQueryRejected 验证 T20-B11:
|
||
// GET /api/v1/chat/stream 带 message query 必须被 4xx 拒绝(用户正文不得进 URL),
|
||
// 指引改走 POST JSON body。无需鉴权即可到达该分支(在 principal 解析前拒绝)。
|
||
func TestChatStream_GetMessageQueryRejected(t *testing.T) {
|
||
cfg := &config.Config{DataDir: t.TempDir(), AgentBackend: "stub"}
|
||
svc := bizdev.MustNewService(t, cfg)
|
||
srv := server.NewServer(cfg, svc)
|
||
handler := srv.Routes()
|
||
|
||
req := httptest.NewRequest(http.MethodGet, "/api/v1/chat/stream?session_id=s1&message="+time.Now().Format("150405"), nil)
|
||
rec := httptest.NewRecorder()
|
||
handler.ServeHTTP(rec, req)
|
||
|
||
if rec.Code != http.StatusBadRequest {
|
||
t.Fatalf("GET with message query expected 400, got %d: %s", rec.Code, rec.Body.String())
|
||
}
|
||
if !contains(rec.Body.String(), "POST") {
|
||
t.Fatalf("error should point to POST body, got: %s", rec.Body.String())
|
||
}
|
||
}
|
||
|
||
// TestChatStream_GetWithoutMessageNotLeak 无 message 的 GET 不触发 B11 分支
|
||
// (进入后续 message cannot be empty 的统一拒绝,同样不产生 SSE 头)。
|
||
func TestChatStream_GetWithoutMessageNotLeak(t *testing.T) {
|
||
cfg := &config.Config{DataDir: t.TempDir(), AgentBackend: "stub"}
|
||
svc := bizdev.MustNewService(t, cfg)
|
||
srv := server.NewServer(cfg, svc)
|
||
handler := srv.Routes()
|
||
|
||
req := httptest.NewRequest(http.MethodGet, "/api/v1/chat/stream?session_id=s1", nil)
|
||
rec := httptest.NewRecorder()
|
||
handler.ServeHTTP(rec, req)
|
||
|
||
if rec.Code != http.StatusBadRequest {
|
||
t.Fatalf("GET without message expected 400 (empty message), got %d", rec.Code)
|
||
}
|
||
if contains(rec.Header().Get("Content-Type"), "text/event-stream") {
|
||
t.Fatal("must not start SSE stream for message-less GET")
|
||
}
|
||
}
|
||
|
||
func contains(s, sub string) bool {
|
||
return strings.Contains(s, sub)
|
||
}
|