CLDSRV-925: UploadPartCopy handle checksums#6188
Conversation
Hello leif-scality,My role is to assist you with the merge of this Available options
Available commands
Status report is not available. |
Incorrect fix versionThe
Considering where you are trying to merge, I ignored possible hotfix versions and I expected to find:
Please check the |
❌ 3 Tests Failed:
View the full list of 3 ❄️ flaky test(s)
To view more test analytics, go to the Test Analytics Dashboard |
213b6f9 to
c216f9e
Compare
|
LGTM |
dc11eca to
bb17208
Compare
| (part, cb) => { | ||
| const done = jsutil.once(cb); | ||
| if (part.dataStoreType === 'azure') { | ||
| // Azure's data.get writes part bytes into the provided writable | ||
| // instead of returning a Readable. Pipe a per-part PassThrough | ||
| // into the master passthrough and use its 'end' as the completion | ||
| // signal — same pattern arsenal's data.copyObject uses. | ||
| const perPart = new PassThrough(); | ||
| perPart.once('error', err => done(wrapErr(err, part))); | ||
| perPart.once('end', () => done()); | ||
| perPart.pipe(passthrough, { end: false }); | ||
| return data.get(part, perPart, log, err => { | ||
| if (err) { | ||
| perPart.destroy(err); | ||
| done(wrapErr(err, part)); | ||
| } | ||
| }); | ||
| } | ||
| return data.get(part, null, log, (err, partStream) => { | ||
| if (err) { | ||
| return done(wrapErr(err, part)); | ||
| } | ||
| partStream.once('error', err => done(wrapErr(err, part))); | ||
| partStream.once('end', () => done()); | ||
| partStream.pipe(passthrough, { end: false }); | ||
| return undefined; | ||
| }); | ||
| }, |
| function computeChecksumFromDataLocator(dataLocator, algorithm, log, cb) { | ||
| const onceCb = jsutil.once(cb); | ||
| const sourceStream = buildSourcePartsStream(dataLocator || [], log); | ||
| const checksumSink = new ChecksumWritable(algorithm, log); | ||
| sourceStream.once('error', err => { | ||
| checksumSink.destroy(err); | ||
| onceCb(err); | ||
| }); | ||
| checksumSink.once('error', onceCb); | ||
| checksumSink.once('finish', () => onceCb(null, { algorithm, value: checksumSink.digest })); | ||
| sourceStream.pipe(checksumSink); | ||
| } |
| function _copyPartStreamingWithChecksum(dataLocator, size, sse, destLocationConstraint, | ||
| dataStoreContext, algo, log, cb) { | ||
| log.debug('recomputing checksum on UploadPartCopy', { algorithm: algo, size }); | ||
| const wrapChecksumErr = err => Object.assign(err, { checksumStream: { algorithm: algo } }); | ||
| const backendInfo = new BackendInfo(config, destLocationConstraint); | ||
| const sourceStream = buildSourcePartsStream(dataLocator, log); | ||
| const checksumStream = new ChecksumTransform(algo, undefined, false, log); | ||
| const done = jsutil.once((err, result) => { | ||
| if (err) { | ||
| sourceStream.destroy(err); | ||
| checksumStream.destroy(err); | ||
| return cb(err); | ||
| } | ||
| return cb(null, result); | ||
| }); | ||
| sourceStream.once('error', done); | ||
| checksumStream.once('error', err => done(wrapChecksumErr(err))); | ||
| sourceStream.pipe(checksumStream); | ||
| const doPut = cipherBundle => | ||
| data.put(cipherBundle, checksumStream, size, dataStoreContext, backendInfo, log, | ||
| (err, dataRetrievalInfo, hashedStream) => { | ||
| if (err) { | ||
| return done(err); | ||
| } | ||
| const location = { | ||
| key: dataRetrievalInfo.key, | ||
| dataStoreName: dataRetrievalInfo.dataStoreName, | ||
| dataStoreETag: hashedStream.completedHash, | ||
| size, | ||
| }; | ||
| if (cipherBundle) { | ||
| location.sseCryptoScheme = cipherBundle.cryptoScheme; | ||
| location.sseCipheredDataKey = cipherBundle.cipheredDataKey; | ||
| location.sseAlgorithm = cipherBundle.algorithm; | ||
| location.sseMasterKeyId = cipherBundle.masterKeyId; | ||
| } | ||
| return done(null, { | ||
| locations: [location], | ||
| totalHash: hashedStream.completedHash, | ||
| checksum: { algorithm: algo, value: checksumStream.digest }, | ||
| }); | ||
| }); | ||
| if (sse && sse.algorithm) { | ||
| return kms.createCipherBundle(sse, log, (err, cipherBundle) => { | ||
| if (err) { | ||
| return done(err); | ||
| } | ||
| return doPut(cipherBundle); | ||
| }); | ||
| } | ||
| return doPut(null); | ||
| } |
| const noRange = { headers: {} }; | ||
| const withRange = { headers: { 'x-amz-copy-source-range': 'bytes=0-1' } }; | ||
|
|
||
| it('returns true when a copy-source-range is requested', () => { |
There was a problem hiding this comment.
Test names using it() should start with "should" (e.g. it('should return true when a copy-source-range is requested', ...)). This applies to multiple tests in this file.
— Claude Code
| assert.strictEqual(err.name, 'InvalidRequest', | ||
| `expected InvalidRequest, got ${err.name}: ${err.message}`); | ||
| // AWS names the expected (MPU) and actual (sent) algorithms. | ||
| assert(err.message.includes( |
There was a problem hiding this comment.
Prefer assert.match over assert(err.message.includes(...)) for substring assertions — it gives a clearer diff on failure. Same applies to the identical pattern at line 247.
— Claude Code
|
No description provided.