From fedaf66907f15b2ed2016dc4bfbaa37c51286986 Mon Sep 17 00:00:00 2001 From: Claude Bot Date: Thu, 16 Oct 2025 17:14:11 +0000 Subject: [PATCH] Fix remaining flaky tests by waiting for complete HTTP responses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed two more potentially flaky tests that were resolving on first data chunk instead of waiting for complete HTTP responses: 1. Basic HTTP request test: - Now parses Content-Length header - Waits until full response body is received before resolving - Adds close handler as fallback for Connection: close 2. Keep-Alive multiple requests test: - Implements proper HTTP response parser that handles pipelined responses - Maintains buffer and extracts complete responses one at a time - Supports multiple responses in single data chunk - Each response is pushed to array only when complete (headers + body) - Properly handles Connection: close by pushing remaining buffer Both tests now robustly handle: - Multi-chunk responses - Pipelined responses - Content-Length parsing - Connection close scenarios All 7 tests pass with 281 expect() calls. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../issue/14567-server-accept.test.ts | 98 +++++++++++++++---- 1 file changed, 81 insertions(+), 17 deletions(-) diff --git a/test/regression/issue/14567-server-accept.test.ts b/test/regression/issue/14567-server-accept.test.ts index c1ae77ae96..c577e45a0a 100644 --- a/test/regression/issue/14567-server-accept.test.ts +++ b/test/regression/issue/14567-server-accept.test.ts @@ -22,7 +22,7 @@ test.todoIf(isWindows)("server.accept() accepts file descriptor and handles HTTP server.accept(serverFd); // Connect client socket and track responses - const responses: Buffer[] = []; + let fullResponse = ""; let resolveData: ((value: void) => void) | null = null; let dataPromise = new Promise(resolve => { resolveData = resolve; @@ -31,16 +31,38 @@ test.todoIf(isWindows)("server.accept() accepts file descriptor and handles HTTP const client = await Bun.connect({ socket: { data(socket, data) { - responses.push(Buffer.from(data)); - if (resolveData) { - resolveData(); - resolveData = null; + fullResponse += Buffer.from(data).toString(); + + // Parse headers to find Content-Length + const headerEnd = fullResponse.indexOf("\r\n\r\n"); + if (headerEnd !== -1) { + const headers = fullResponse.substring(0, headerEnd); + const contentLengthMatch = headers.match(/Content-Length:\s*(\d+)/i); + + if (contentLengthMatch) { + const contentLength = parseInt(contentLengthMatch[1], 10); + const bodyStart = headerEnd + 4; + const currentBodyLength = fullResponse.length - bodyStart; + + // Only resolve when we have the complete body + if (currentBodyLength >= contentLength && resolveData) { + resolveData(); + resolveData = null; + } + } } }, open(socket) { // Send HTTP request socket.write("GET / HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: close\r\n" + "\r\n"); }, + close(socket) { + // Connection closed - resolve if not already resolved + if (resolveData) { + resolveData(); + resolveData = null; + } + }, }, fd: clientFd, }); @@ -49,9 +71,8 @@ test.todoIf(isWindows)("server.accept() accepts file descriptor and handles HTTP await dataPromise; // Verify we got an HTTP response - const response = Buffer.concat(responses).toString(); - expect(response).toContain("HTTP/1.1 200"); - expect(response).toContain("Hello from request 1!"); + expect(fullResponse).toContain("HTTP/1.1 200"); + expect(fullResponse).toContain("Hello from request 1!"); client.end(); } finally { @@ -81,6 +102,7 @@ test.todoIf(isWindows)("server.accept() handles multiple requests with Keep-Aliv server.accept(serverFd); const responses: string[] = []; + let buffer = ""; let resolveData: ((value: void) => void) | null = null; let currentPromise = new Promise(resolve => { resolveData = resolve; @@ -89,11 +111,41 @@ test.todoIf(isWindows)("server.accept() handles multiple requests with Keep-Aliv const client = await Bun.connect({ socket: { data(socket, data) { - const text = Buffer.from(data).toString(); - responses.push(text); - if (resolveData) { - resolveData(); - resolveData = null; + buffer += Buffer.from(data).toString(); + + // Parse and extract complete HTTP responses from buffer + while (true) { + const headerEnd = buffer.indexOf("\r\n\r\n"); + if (headerEnd === -1) break; + + const headers = buffer.substring(0, headerEnd); + const contentLengthMatch = headers.match(/Content-Length:\s*(\d+)/i); + + if (contentLengthMatch) { + const contentLength = parseInt(contentLengthMatch[1], 10); + const bodyStart = headerEnd + 4; + const totalLength = bodyStart + contentLength; + + // Check if we have the complete response + if (buffer.length >= totalLength) { + // Extract complete response + const completeResponse = buffer.substring(0, totalLength); + buffer = buffer.substring(totalLength); + + // Push to responses and resolve current promise + responses.push(completeResponse); + if (resolveData) { + resolveData(); + resolveData = null; + } + } else { + // Need more data + break; + } + } else { + // No Content-Length - can't parse further without more info + break; + } } }, open(socket) { @@ -109,12 +161,24 @@ test.todoIf(isWindows)("server.accept() handles multiple requests with Keep-Aliv body1, ); }, + close(socket) { + // Connection closed - push any remaining buffer as final response + if (buffer.length > 0) { + responses.push(buffer); + buffer = ""; + } + if (resolveData) { + resolveData(); + resolveData = null; + } + }, }, fd: clientFd, }); // Wait for first response await currentPromise; + expect(responses.length).toBeGreaterThanOrEqual(1); expect(responses[0]).toContain("HTTP/1.1 200"); expect(responses[0]).toContain("Request 1: Hello World"); @@ -135,8 +199,7 @@ test.todoIf(isWindows)("server.accept() handles multiple requests with Keep-Aliv await currentPromise; expect(responses.length).toBeGreaterThanOrEqual(2); - const fullResponse = responses.join(""); - expect(fullResponse).toContain("Request 2: Second request"); + expect(responses[1]).toContain("Request 2: Second request"); // Send third request currentPromise = new Promise(resolve => { @@ -145,8 +208,9 @@ test.todoIf(isWindows)("server.accept() handles multiple requests with Keep-Aliv client.write("GET /final HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: close\r\n" + "\r\n"); await currentPromise; - const finalResponse = responses.join(""); - expect(finalResponse).toContain("Request 3: no body"); + expect(responses.length).toBeGreaterThanOrEqual(3); + const allResponses = responses.join(""); + expect(allResponses).toContain("Request 3: no body"); expect(requestCount).toBe(3);