openai_compact_stream_failure_created_at_test.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. //go:build unit
  2. package service
  3. import (
  4. "encoding/json"
  5. "net/http"
  6. "net/http/httptest"
  7. "strings"
  8. "testing"
  9. "github.com/gin-gonic/gin"
  10. "github.com/stretchr/testify/require"
  11. )
  12. // issue #5601:严格的 Responses 客户端把 created_at 当必填字段,缺失即
  13. // `missing field 'created_at'`。writeOpenAICompactSSEFailureMessage 存在的理由就是
  14. // 让 Codex 能把这帧识别成合法终止事件;解析不了就退化回它想避免的盲重连。
  15. func TestWriteOpenAICompactSSEFailureMessage_CarriesCreatedAt(t *testing.T) {
  16. gin.SetMode(gin.TestMode)
  17. rec := httptest.NewRecorder()
  18. c, _ := gin.CreateTestContext(rec)
  19. c.Request = httptest.NewRequest(http.MethodPost, "/v1/responses", nil)
  20. writeOpenAICompactSSEFailureMessage(c, http.StatusBadGateway, "upstream_error", "boom")
  21. body := rec.Body.String()
  22. require.Contains(t, body, "event: response.failed")
  23. _, payload, found := strings.Cut(body, "data: ")
  24. require.True(t, found, "SSE 帧必须带 data 行: %q", body)
  25. var event struct {
  26. Type string `json:"type"`
  27. Response struct {
  28. ID string `json:"id"`
  29. Object string `json:"object"`
  30. CreatedAt int64 `json:"created_at"`
  31. Status string `json:"status"`
  32. } `json:"response"`
  33. }
  34. require.NoError(t, json.Unmarshal([]byte(strings.TrimSpace(payload)), &event))
  35. require.Equal(t, "response.failed", event.Type)
  36. require.Equal(t, "response", event.Response.Object)
  37. require.Equal(t, "failed", event.Response.Status)
  38. require.Greater(t, event.Response.CreatedAt, int64(0),
  39. "response.failed 必须带有效的 created_at,否则严格客户端读不出这帧")
  40. }