first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 21:52:23 +03:00
commit 880f412e2c
2662 changed files with 866266 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
package handlers
import (
"bufio"
"fmt"
"net"
"strings"
"testing"
"github.com/maximhq/bifrost/transports/bifrost-http/lib"
"github.com/valyala/fasthttp"
)
// TestSSEStreamReaderNoEventBatching verifies that SSE events are delivered
// individually through fasthttp's chunked transfer encoding, not batched
// into larger TCP segments. This is the core regression test for the
// fasthttputil.PipeConns batching fix.
func TestSSEStreamReaderNoEventBatching(t *testing.T) {
const numEvents = 20
// Build expected events
events := make([]string, numEvents)
for i := range events {
events[i] = fmt.Sprintf("data: {\"index\":%d,\"content\":\"chunk-%d\"}\n\n", i, i)
}
handler := func(ctx *fasthttp.RequestCtx) {
ctx.SetContentType("text/event-stream")
ctx.Response.Header.Set("Cache-Control", "no-cache")
reader := lib.NewSSEStreamReader()
go func() {
defer reader.Done()
for _, event := range events {
if !reader.Send([]byte(event)) {
return
}
}
}()
ctx.Response.SetBodyStream(reader, -1)
}
// Use net.Pipe for deterministic in-process testing
serverConn, clientConn := net.Pipe()
defer clientConn.Close()
// Run fasthttp server on one end of the pipe
go func() {
_ = fasthttp.ServeConn(serverConn, handler)
}()
// Send HTTP request through the pipe
_, err := clientConn.Write([]byte("GET /stream HTTP/1.1\r\nHost: test\r\n\r\n"))
if err != nil {
t.Fatalf("failed to write request: %v", err)
}
// Read response using bufio to parse chunked encoding
br := bufio.NewReader(clientConn)
// Read and skip HTTP response headers
for {
line, err := br.ReadString('\n')
if err != nil {
t.Fatalf("failed to read response header: %v", err)
}
if strings.TrimSpace(line) == "" {
break // End of headers
}
}
// Read chunked transfer-encoded body.
// Each HTTP chunk should contain exactly one SSE event.
var receivedEvents []string
for {
// Read chunk size line (hex size + CRLF)
sizeLine, err := br.ReadString('\n')
if err != nil {
t.Fatalf("failed to read chunk size: %v", err)
}
sizeLine = strings.TrimSpace(sizeLine)
var chunkSize int
_, err = fmt.Sscanf(sizeLine, "%x", &chunkSize)
if err != nil {
t.Fatalf("failed to parse chunk size %q: %v", sizeLine, err)
}
if chunkSize == 0 {
break // Terminal chunk
}
// Read exactly chunkSize bytes + trailing CRLF
chunkData := make([]byte, chunkSize+2) // +2 for CRLF
n := 0
for n < len(chunkData) {
nn, err := br.Read(chunkData[n:])
if err != nil {
t.Fatalf("failed to read chunk data: %v", err)
}
n += nn
}
chunk := string(chunkData[:chunkSize])
receivedEvents = append(receivedEvents, chunk)
}
// Verify each chunk contains exactly one SSE event
if len(receivedEvents) != numEvents {
t.Errorf("expected %d individual chunks, got %d (events were batched)", numEvents, len(receivedEvents))
for i, chunk := range receivedEvents {
eventCount := strings.Count(chunk, "\n\n")
t.Logf(" chunk %d: %d SSE events, %d bytes", i, eventCount, len(chunk))
}
}
for i, chunk := range receivedEvents {
if i >= len(events) {
break
}
if chunk != events[i] {
t.Errorf("chunk %d: got %q, want %q", i, chunk, events[i])
}
}
}