Skip to content

Commit 2e495e0

Browse files
committed
fixup! Add stall detection to recover from frozen uploads
1 parent f419e84 commit 2e495e0

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed

test/spec/test-stall-detection.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,5 +328,85 @@ describe('tus-stall-detection', () => {
328328
// Stall detection should not have triggered during the onBeforeRequest delay
329329
expect(options.onError.calls.count()).toBe(0)
330330
})
331+
332+
it('should detect stalls when progress events stop mid-upload', async () => {
333+
const testStack = new TestHttpStack()
334+
const file = getBlob('hello world'.repeat(100)) // Larger file for multiple progress events
335+
336+
let progressCallCount = 0
337+
let progressHandler = null
338+
339+
// Override createRequest to capture and control progress events
340+
const originalCreateRequest = testStack.createRequest.bind(testStack)
341+
testStack.createRequest = function(method, url) {
342+
const req = originalCreateRequest(method, url)
343+
344+
if (method === 'PATCH') {
345+
const originalSetProgressHandler = req.setProgressHandler.bind(req)
346+
req.setProgressHandler = function(handler) {
347+
progressHandler = handler
348+
originalSetProgressHandler(handler)
349+
}
350+
351+
// Override send to simulate progress events that stop
352+
const originalSend = req.send.bind(req)
353+
req.send = async function(body) {
354+
const result = originalSend(body)
355+
356+
// Simulate some progress events then stop
357+
if (progressHandler && body) {
358+
const totalSize = await getBodySize(body)
359+
// Send progress events for first 30% of upload
360+
for (let i = 0; i <= 3; i++) {
361+
progressCallCount++
362+
progressHandler(Math.floor(totalSize * 0.1 * i))
363+
await new Promise(resolve => setTimeout(resolve, 50))
364+
}
365+
// Then stop sending progress events to simulate a stall
366+
}
367+
368+
return result
369+
}
370+
}
371+
372+
return req
373+
}
374+
375+
const options = {
376+
httpStack: testStack,
377+
endpoint: 'https://tus.io/uploads',
378+
stallDetection: {
379+
enabled: true,
380+
checkInterval: 100,
381+
stallTimeout: 200,
382+
},
383+
retryDelays: null, // No retries to get immediate error
384+
onError: waitableFunction('onError'),
385+
onProgress: waitableFunction('onProgress'),
386+
}
387+
388+
const upload = new Upload(file, options)
389+
upload.start()
390+
391+
// Handle the POST request
392+
const req = await testStack.nextRequest()
393+
expect(req.method).toBe('POST')
394+
req.respondWith({
395+
status: 201,
396+
responseHeaders: {
397+
Location: '/uploads/12345',
398+
},
399+
})
400+
401+
// The PATCH request will start sending progress events then stall
402+
403+
// Wait for stall detection to trigger
404+
const error = await options.onError.toBeCalled()
405+
expect(error.message).toContain('Upload stalled')
406+
407+
// Verify that we received some progress events before the stall
408+
expect(progressCallCount).toBeGreaterThan(0)
409+
expect(options.onProgress.calls.count()).toBeGreaterThan(0)
410+
})
331411
})
332412
})

0 commit comments

Comments
 (0)