preread_body_test.go 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package httputil
  2. import (
  3. "bytes"
  4. "io"
  5. "net/http"
  6. "strings"
  7. "testing"
  8. )
  9. func TestPrereadBodyRoundtrip(t *testing.T) {
  10. body := []byte(`{"model":"gpt-5.4"}`)
  11. preread := NewPrereadBody(body)
  12. got, err := io.ReadAll(preread)
  13. if err != nil {
  14. t.Fatalf("read preread body: %v", err)
  15. }
  16. if !bytes.Equal(got, body) {
  17. t.Fatalf("body mismatch: got %q want %q", got, body)
  18. }
  19. if err := preread.Close(); err != nil {
  20. t.Fatalf("close: %v", err)
  21. }
  22. if !bytes.Equal(preread.Bytes(), body) {
  23. t.Fatalf("Bytes() mismatch after close: %q", preread.Bytes())
  24. }
  25. }
  26. func TestPrereadBodyReadableTwiceFromFreshWrapper(t *testing.T) {
  27. // ResetRequestBody 每次都回填新的 PrereadBody;同一实例只被顺序消费一次。
  28. body := []byte("payload")
  29. first := NewPrereadBody(body)
  30. got1, _ := io.ReadAll(first)
  31. if !bytes.Equal(got1, body) {
  32. t.Fatalf("first read mismatch: %q", got1)
  33. }
  34. second := NewPrereadBody(first.Bytes())
  35. got2, _ := io.ReadAll(second)
  36. if !bytes.Equal(got2, body) {
  37. t.Fatalf("second read mismatch: %q", got2)
  38. }
  39. }
  40. func TestReadRequestBodyWithPreallocReturnsPrereadBodySliceWithoutCopy(t *testing.T) {
  41. body := []byte(`{"model":"claude-sonnet-4.5"}`)
  42. req, err := http.NewRequest(http.MethodPost, "/v1/messages", NewPrereadBody(body))
  43. if err != nil {
  44. t.Fatalf("new request: %v", err)
  45. }
  46. req.Header.Set("Content-Length", "0") // 故意与实际不符,验证不依赖 ContentLength
  47. got, err := ReadRequestBodyWithPrealloc(req)
  48. if err != nil {
  49. t.Fatalf("ReadRequestBodyWithPrealloc: %v", err)
  50. }
  51. if &got[0] != &body[0] {
  52. t.Fatalf("expected zero-copy return of the same slice")
  53. }
  54. if !bytes.Equal(got, body) {
  55. t.Fatalf("body mismatch: got %q want %q", got, body)
  56. }
  57. }
  58. func TestReadRequestBodyWithPreallocHandlesNilPrereadBody(t *testing.T) {
  59. req, err := http.NewRequest(http.MethodPost, "/v1/messages", nil)
  60. if err != nil {
  61. t.Fatalf("new request: %v", err)
  62. }
  63. got, err := ReadRequestBodyWithPrealloc(req)
  64. if err != nil || got != nil {
  65. t.Fatalf("expected nil body, got (%#v, %v)", got, err)
  66. }
  67. }
  68. func TestPrereadBodyPartialConsumeThenPreallocReturnsFullBody(t *testing.T) {
  69. body := []byte(strings.Repeat("x", 64))
  70. preread := NewPrereadBody(body)
  71. head := make([]byte, 16)
  72. if _, err := io.ReadFull(preread, head); err != nil {
  73. t.Fatalf("partial read: %v", err)
  74. }
  75. req, err := http.NewRequest(http.MethodPost, "/v1/responses", preread)
  76. if err != nil {
  77. t.Fatalf("new request: %v", err)
  78. }
  79. got, err := ReadRequestBodyWithPrealloc(req)
  80. if err != nil {
  81. t.Fatalf("ReadRequestBodyWithPrealloc: %v", err)
  82. }
  83. if !bytes.Equal(got, body) {
  84. t.Fatalf("expected full body after partial consume, got %d bytes", len(got))
  85. }
  86. }