|
221 | 221 | connection_without_retries = described_class.send(:connection_without_retries) |
222 | 222 | expect(connection_without_retries).to be_a(HTTPX::Session) |
223 | 223 | end |
224 | | - |
225 | | - it "prevents body duplication when streaming request is retried after mid-transmission error" do |
226 | | - # This integration test verifies the complete fix for https://github.com/shakacode/react_on_rails/issues/1895 |
227 | | - # It ensures that when a streaming request fails mid-transmission and is retried, |
228 | | - # the client doesn't receive duplicate chunks. |
229 | | - |
230 | | - described_class.reset_connection |
231 | | - |
232 | | - # Track how many times the request is made to verify retry behavior |
233 | | - request_attempt = 0 |
234 | | - original_chunks = ["Chunk 1", "Chunk 2", "Chunk 3"] |
235 | | - |
236 | | - # Mock a streaming response that fails on first attempt, succeeds on second |
237 | | - connection = described_class.send(:connection_without_retries) |
238 | | - allow(connection).to receive(:post).and_wrap_original do |original_method, *args, **kwargs| |
239 | | - if kwargs[:stream] |
240 | | - request_attempt += 1 |
241 | | - |
242 | | - # Set up mock based on attempt number |
243 | | - if request_attempt == 1 |
244 | | - # First attempt: simulate mid-transmission failure (HTTPError during streaming) |
245 | | - # This simulates a connection error after partial data is sent |
246 | | - mock_streaming_response(render_full_url, 200) do |yielder| |
247 | | - yielder.call("#{original_chunks[0]}\n") |
248 | | - # Simulate connection error mid-stream |
249 | | - # StreamRequest catches any error and retries, so we can use a simple error |
250 | | - raise IOError, "Connection closed" |
251 | | - end |
252 | | - else |
253 | | - # Second attempt: complete all chunks successfully |
254 | | - mock_streaming_response(render_full_url, 200) do |yielder| |
255 | | - original_chunks.each { |chunk| yielder.call("#{chunk}\n") } |
256 | | - end |
257 | | - end |
258 | | - end |
259 | | - |
260 | | - original_method.call(*args, **kwargs) |
261 | | - end |
262 | | - |
263 | | - stream = described_class.render_code_as_stream("/render", "console.log('test');", is_rsc_payload: false) |
264 | | - received_chunks = [] |
265 | | - |
266 | | - # StreamRequest should handle the retry and yield all chunks exactly once |
267 | | - stream.each_chunk { |chunk| received_chunks << chunk } |
268 | | - |
269 | | - # Verify no duplication: should have exactly 3 chunks, not 4 (1 from failed + 3 from retry) |
270 | | - expect(received_chunks).to eq(original_chunks) |
271 | | - expect(received_chunks.size).to eq(3) |
272 | | - |
273 | | - # Verify retry actually happened |
274 | | - expect(request_attempt).to eq(2) |
275 | | - end |
276 | 224 | end |
277 | 225 | end |
0 commit comments