Skip to content

Commit

Permalink
@tus/s3-store: finalize incomplete parts
Browse files Browse the repository at this point in the history
  • Loading branch information
atticoos committed Oct 26, 2023
1 parent 9149b84 commit 6383aa7
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 0 deletions.
6 changes: 6 additions & 0 deletions packages/s3-store/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,13 @@ export class S3Store extends DataStore {

if (metadata.file.size === newOffset) {
try {
// If no parts exist yet, then the incomplete part needs to be completed
const incompletePart = await this.getIncompletePart(id)
if (incompletePart) {
await this.uploadPart(metadata, incompletePart, nextPartNumber)
}
const parts = await this.retrieveParts(id)

await this.finishMultipartUpload(metadata, parts as Array<AWS.Part>)
this.clearCache(id)
} catch (error) {
Expand Down
35 changes: 35 additions & 0 deletions packages/s3-store/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,41 @@ describe('S3DataStore', function () {
}
})

it('completes an incomplete part when deferred length becomes resolved', async function () {
const store = this.datastore
const incompleteSize = 2 * 1024 * 1024 // 2MB
const uploadIncompletePart = sinon.spy(store, 'uploadIncompletePart')
const uploadPart = sinon.spy(store, 'uploadPart')
const finishMultipartUpload = sinon.spy(store, 'finishMultipartUpload')
const upload = new Upload({
id: 'deferred-incomplete-part-test-' + Uid.rand(),
// Deferred length
size: undefined,
offset: 0,
})
let offset = upload.offset
await store.create(upload)

// Upload a single chunk small enough to create an incomplete part
offset = await store.write(
Readable.from(Buffer.alloc(incompleteSize)),
upload.id,
offset
)
assert.equal(uploadIncompletePart.called, true)
assert.equal(uploadPart.called, false)

// Simulate the completion PATCH of a deferred length multipart upload
// Resolve the deferred length
await store.declareUploadLength(upload.id, incompleteSize)
// Notify the store to complete the multipart upload (empty payload)
await store.write(Readable.from(Buffer.alloc(0)), upload.id, offset)
// The incomplete part will now be completed
assert.equal(uploadPart.called, true)
// The multipart upload will now be completed
assert.equal(finishMultipartUpload.called, true)
})

it('upload as multipart upload when incomplete part grows beyond minimal part size', async function () {
const store = this.datastore
const size = 10 * 1024 * 1024 // 10MiB
Expand Down

0 comments on commit 6383aa7

Please sign in to comment.