Skip to content

Commit 92ab736

Browse files
committed
Handle cases where CDP's file upload service has expired the upload ID
1 parent a6cab10 commit 92ab736

2 files changed

Lines changed: 100 additions & 1 deletion

File tree

src/server/plugins/engine/pageControllers/FileUploadPageController.test.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable @typescript-eslint/dot-notation */
22
import { ComponentType, type ComponentDef } from '@defra/forms-model'
3+
import Boom from '@hapi/boom'
34
import { type ValidationErrorItem, type ValidationResult } from 'joi'
45

56
import {
@@ -195,6 +196,89 @@ describe('FileUploadPageController', () => {
195196
)
196197
})
197198

199+
it('initiates new upload when getUploadStatus throws a 404 error', async () => {
200+
const state = {
201+
upload: {
202+
[controller.path]: {
203+
upload: {
204+
uploadId: 'some-id',
205+
uploadUrl: 'some-url',
206+
statusUrl: 'some-status-url'
207+
},
208+
files: []
209+
}
210+
}
211+
} as unknown as FormSubmissionState
212+
213+
const notFoundError = Boom.notFound('Upload not found')
214+
215+
jest
216+
.spyOn(uploadService, 'getUploadStatus')
217+
.mockRejectedValue(notFoundError)
218+
219+
const testController = controller as TestableFileUploadPageController
220+
const initiateSpy = jest.spyOn(
221+
testController,
222+
'initiateAndStoreNewUpload'
223+
)
224+
initiateSpy.mockResolvedValue(state as never)
225+
226+
const result = await controller['checkUploadStatus'](request, state, 1)
227+
228+
expect(initiateSpy).toHaveBeenCalledWith(request, state)
229+
expect(result).toBe(state)
230+
})
231+
232+
it('re-throws non-404 Boom errors from getUploadStatus', async () => {
233+
const state = {
234+
upload: {
235+
[controller.path]: {
236+
upload: {
237+
uploadId: 'some-id',
238+
uploadUrl: 'some-url',
239+
statusUrl: 'some-status-url'
240+
},
241+
files: []
242+
}
243+
}
244+
} as unknown as FormSubmissionState
245+
246+
const serverError = Boom.internal('Server error')
247+
248+
jest
249+
.spyOn(uploadService, 'getUploadStatus')
250+
.mockRejectedValue(serverError)
251+
252+
await expect(
253+
controller['checkUploadStatus'](request, state, 1)
254+
).rejects.toThrow('Server error')
255+
})
256+
257+
it('re-throws non-Boom errors from getUploadStatus', async () => {
258+
const state = {
259+
upload: {
260+
[controller.path]: {
261+
upload: {
262+
uploadId: 'some-id',
263+
uploadUrl: 'some-url',
264+
statusUrl: 'some-status-url'
265+
},
266+
files: []
267+
}
268+
}
269+
} as unknown as FormSubmissionState
270+
271+
const networkError = new Error('Network failure')
272+
273+
jest
274+
.spyOn(uploadService, 'getUploadStatus')
275+
.mockRejectedValue(networkError)
276+
277+
await expect(
278+
controller['checkUploadStatus'](request, state, 1)
279+
).rejects.toThrow('Network failure')
280+
})
281+
198282
it('handles pending upload with backoff and retries', async () => {
199283
const state = {
200284
upload: {

src/server/plugins/engine/pageControllers/FileUploadPageController.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,22 @@ export class FileUploadPageController extends QuestionPageController {
327327
}
328328

329329
const uploadId = upload.uploadId
330-
const statusResponse = await getUploadStatus(uploadId)
330+
331+
let statusResponse
332+
333+
try {
334+
statusResponse = await getUploadStatus(uploadId)
335+
} catch (err) {
336+
// if the user loads a file upload page and queries the cached upload, after the upload has
337+
// expired in CDP, we will get a 404 from the getUploadStatus endpoint.
338+
// In this case we want to initiate a new upload and return that state, so the form
339+
// doesn't blow up for the end user.
340+
if (Boom.isBoom(err) && err.output.statusCode === 404) {
341+
return this.initiateAndStoreNewUpload(request, state)
342+
}
343+
throw err
344+
}
345+
331346
if (!statusResponse) {
332347
throw Boom.badRequest(
333348
`Unexpected empty response from getUploadStatus for ${uploadId}`

0 commit comments

Comments
 (0)