Compare commits
1 Commits
developmen
...
feature/re
Author | SHA1 | Date |
---|---|---|
Dora Korpar | 9e2252d26a |
|
@ -27,9 +27,9 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
|||
async.waterfall([
|
||||
function checkDestBucketVal(next) {
|
||||
metadataValidateBucketAndObj(metadataValParams, log,
|
||||
(err, destinationBucket) => {
|
||||
(err, destinationBucket, objMD) => {
|
||||
if (err) {
|
||||
return next(err, destinationBucket);
|
||||
return next(err, destinationBucket, 0, objMD);
|
||||
}
|
||||
if (destinationBucket.policies) {
|
||||
// TODO: Check bucket policies to see if user is granted
|
||||
|
@ -41,21 +41,22 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
|||
metadataValMPUparams.requestType =
|
||||
'bucketPolicyGoAhead';
|
||||
}
|
||||
return next(null, destinationBucket);
|
||||
return next(null, destinationBucket, objMD);
|
||||
});
|
||||
},
|
||||
function checkMPUval(destBucket, next) {
|
||||
function checkMPUval(destBucket, objMD, next) {
|
||||
metadataValParams.log = log;
|
||||
services.metadataValidateMultipart(metadataValParams,
|
||||
(err, mpuBucket, mpuOverviewObj) => {
|
||||
if (err) {
|
||||
return next(err, destBucket);
|
||||
return next(err, destBucket, 0, objMD);
|
||||
}
|
||||
return next(err, mpuBucket, mpuOverviewObj, destBucket);
|
||||
return next(err, mpuBucket, mpuOverviewObj, destBucket,
|
||||
objMD);
|
||||
});
|
||||
},
|
||||
function ifMultipleBackend(mpuBucket, mpuOverviewObj, destBucket,
|
||||
next) {
|
||||
objMD, next) {
|
||||
if (config.backends.data === 'multiple') {
|
||||
let location;
|
||||
// if controlling location constraint is not stored in object
|
||||
|
@ -66,7 +67,7 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
|||
null, destBucket, log);
|
||||
if (backendInfoObj.err) {
|
||||
return process.nextTick(() => {
|
||||
next(backendInfoObj.err, destBucket);
|
||||
next(backendInfoObj.err, destBucket, 0, objMD);
|
||||
});
|
||||
}
|
||||
location = backendInfoObj.controllingLC;
|
||||
|
@ -76,37 +77,37 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
|||
return multipleBackendGateway.abortMPU(objectKey, uploadId,
|
||||
location, bucketName, log, (err, skipDataDelete) => {
|
||||
if (err) {
|
||||
return next(err, destBucket);
|
||||
return next(err, destBucket, 0, objMD);
|
||||
}
|
||||
return next(null, mpuBucket, destBucket,
|
||||
skipDataDelete);
|
||||
skipDataDelete, objMD);
|
||||
});
|
||||
}
|
||||
return next(null, mpuBucket, destBucket, false);
|
||||
return next(null, mpuBucket, destBucket, false, objMD);
|
||||
},
|
||||
function getPartLocations(mpuBucket, destBucket, skipDataDelete,
|
||||
next) {
|
||||
objMD, next) {
|
||||
services.getMPUparts(mpuBucket.getName(), uploadId, log,
|
||||
(err, result) => {
|
||||
if (err) {
|
||||
return next(err, destBucket);
|
||||
return next(err, destBucket, 0, objMD);
|
||||
}
|
||||
const storedParts = result.Contents;
|
||||
return next(null, mpuBucket, storedParts, destBucket,
|
||||
skipDataDelete);
|
||||
skipDataDelete, objMD);
|
||||
});
|
||||
},
|
||||
function deleteData(mpuBucket, storedParts, destBucket,
|
||||
skipDataDelete, next) {
|
||||
skipDataDelete, objMD, next) {
|
||||
// for Azure we do not need to delete data
|
||||
if (skipDataDelete) {
|
||||
return next(null, mpuBucket, storedParts, destBucket);
|
||||
return next(null, mpuBucket, storedParts, destBucket, objMD);
|
||||
}
|
||||
// The locations were sent to metadata as an array
|
||||
// under partLocations. Pull the partLocations.
|
||||
let locations = storedParts.map(item => item.value.partLocations);
|
||||
if (locations.length === 0) {
|
||||
return next(null, mpuBucket, storedParts, destBucket);
|
||||
return next(null, mpuBucket, storedParts, destBucket, objMD);
|
||||
}
|
||||
// flatten the array
|
||||
locations = [].concat(...locations);
|
||||
|
@ -117,9 +118,10 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
|||
}
|
||||
cb();
|
||||
});
|
||||
}, () => next(null, mpuBucket, storedParts, destBucket));
|
||||
}, () => next(null, mpuBucket, storedParts, destBucket, objMD));
|
||||
},
|
||||
function deleteMetadata(mpuBucket, storedParts, destBucket, next) {
|
||||
function deleteMetadata(mpuBucket, storedParts, destBucket, objMD,
|
||||
next) {
|
||||
let splitter = constants.splitter;
|
||||
// BACKWARD: Remove to remove the old splitter
|
||||
if (mpuBucket.getMdBucketModelVersion() < 2) {
|
||||
|
@ -135,7 +137,8 @@ function abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
|||
const keysToDelete = storedParts.map(item => item.key);
|
||||
keysToDelete.push(mpuOverviewKey);
|
||||
services.batchDeleteObjectMetadata(mpuBucket.getName(),
|
||||
keysToDelete, log, err => next(err, destBucket, partSizeSum));
|
||||
keysToDelete, log, err => next(err, destBucket, partSizeSum,
|
||||
objMD));
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
|
|
|
@ -180,9 +180,17 @@ function _parseXml(xmlToParse, next) {
|
|||
*/
|
||||
function getObjMetadataAndDelete(authInfo, canonicalID, request,
|
||||
bucketName, bucket, quietSetting, errorResults, inPlay, log, next) {
|
||||
const deletedObjStats = {
|
||||
requesterIsObjOwner: {
|
||||
totalContentLengthDeleted: 0,
|
||||
numOfObjectsRemoved: 0,
|
||||
},
|
||||
requesterNotObjOwner: {
|
||||
totalContentLengthDeleted: 0,
|
||||
numOfObjectsRemoved: 0,
|
||||
},
|
||||
};
|
||||
const successfullyDeleted = [];
|
||||
let totalContentLengthDeleted = 0;
|
||||
let numOfObjectsRemoved = 0;
|
||||
const skipError = new Error('skip');
|
||||
|
||||
// doing 5 requests at a time. note that the data wrapper
|
||||
|
@ -253,9 +261,19 @@ function getObjMetadataAndDelete(authInfo, canonicalID, request,
|
|||
errorResults.push({ entry, error: err });
|
||||
return moveOn();
|
||||
}
|
||||
const reqObjDiffOwners = objMD && canonicalID !== objMD['owner-id'];
|
||||
if (deleteInfo.deleted && objMD['content-length']) {
|
||||
numOfObjectsRemoved++;
|
||||
totalContentLengthDeleted += objMD['content-length'];
|
||||
if (reqObjDiffOwners) {
|
||||
deletedObjStats.requesterNotObjOwner.numOfObjectsRemoved++;
|
||||
deletedObjStats.requesterNotObjOwner.
|
||||
totalContentLengthDeleted += objMD['content-length'];
|
||||
deletedObjStats.requesterNotObjOwner.objOwnerCanonicalID =
|
||||
objMD['owner-id'];
|
||||
} else {
|
||||
deletedObjStats.requesterIsObjOwner.numOfObjectsRemoved++;
|
||||
deletedObjStats.requesterIsObjOwner.
|
||||
totalContentLengthDeleted += objMD['content-length'];
|
||||
}
|
||||
}
|
||||
let isDeleteMarker;
|
||||
let deleteMarkerVersionId;
|
||||
|
@ -269,7 +287,11 @@ function getObjMetadataAndDelete(authInfo, canonicalID, request,
|
|||
deleteMarkerVersionId = versionIdUtils.encode(versionId);
|
||||
// In this case we are putting a new object (i.e., the delete
|
||||
// marker), so we decrement the numOfObjectsRemoved value.
|
||||
numOfObjectsRemoved--;
|
||||
if (reqObjDiffOwners) {
|
||||
deletedObjStats.requesterNotObjOwner.numOfObjectsRemoved--;
|
||||
} else {
|
||||
deletedObjStats.requesterIsObjOwner.numOfObjectsRemoved--;
|
||||
}
|
||||
// If trying to delete a delete marker, DeleteMarkerVersionId equals
|
||||
// deleteMarker's versionID and DeleteMarker equals true
|
||||
} else if (objMD && objMD.isDeleteMarker) {
|
||||
|
@ -283,9 +305,13 @@ function getObjMetadataAndDelete(authInfo, canonicalID, request,
|
|||
},
|
||||
// end of forEach func
|
||||
err => {
|
||||
log.trace('finished deleting objects', { numOfObjectsRemoved });
|
||||
return next(err, quietSetting, errorResults, numOfObjectsRemoved,
|
||||
successfullyDeleted, totalContentLengthDeleted, bucket);
|
||||
const totalObjectsRemoved = deletedObjStats.requesterIsObjOwner.
|
||||
numOfObjectsRemoved + deletedObjStats.requesterNotObjOwner.
|
||||
numberOfObjectsRemoved;
|
||||
log.trace('finished deleting objects',
|
||||
{ numOfObjectsRemoved: totalObjectsRemoved });
|
||||
return next(err, quietSetting, errorResults, deletedObjStats,
|
||||
successfullyDeleted, bucket);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -473,8 +499,8 @@ function multiObjectDelete(authInfo, request, log, callback) {
|
|||
bucketName, bucket, quietSetting, errorResults, inPlay,
|
||||
log, next);
|
||||
},
|
||||
], (err, quietSetting, errorResults, numOfObjectsRemoved,
|
||||
successfullyDeleted, totalContentLengthDeleted, bucket) => {
|
||||
], (err, quietSetting, errorResults, deletedObjStats,
|
||||
successfullyDeleted, bucket) => {
|
||||
const corsHeaders = collectCorsHeaders(request.headers.origin,
|
||||
request.method, bucket);
|
||||
if (err) {
|
||||
|
@ -483,13 +509,30 @@ function multiObjectDelete(authInfo, request, log, callback) {
|
|||
const xml = _formatXML(quietSetting, errorResults,
|
||||
successfullyDeleted);
|
||||
const deletedKeys = successfullyDeleted.map(item => item.key);
|
||||
pushMetric('multiObjectDelete', log, {
|
||||
authInfo,
|
||||
bucket: bucketName,
|
||||
keys: deletedKeys,
|
||||
byteLength: Number.parseInt(totalContentLengthDeleted, 10),
|
||||
numberOfObjects: numOfObjectsRemoved,
|
||||
});
|
||||
if (deletedObjStats.requesterIsObjOwner.numOfObjectsRemoved > 0) {
|
||||
pushMetric('multiObjectDelete', log, {
|
||||
authInfo,
|
||||
bucket: bucketName,
|
||||
keys: deletedKeys,
|
||||
byteLength: Number.parseInt(deletedObjStats.requesterIsObjOwner.
|
||||
totalContentLengthDeleted, 10),
|
||||
numberOfObjects: deletedObjStats.requesterIsObjOwner.
|
||||
numOfObjectsRemoved,
|
||||
});
|
||||
}
|
||||
if (deletedObjStats.requesterNotObjOwner.numOfObjectsRemoved > 0) {
|
||||
pushMetric('multiObjectDelete', log, {
|
||||
authInfo,
|
||||
bucket: bucketName,
|
||||
keys: deletedKeys,
|
||||
byteLength: Number.parseInt(deletedObjStats.
|
||||
requesterNotObjOwner.totalContentLengthDeleted, 10),
|
||||
numberOfObjects: deletedObjStats.requesterNotObjOwner.
|
||||
numOfObjectsRemoved,
|
||||
objOwnerCanonicalID: deletedObjStats.requesterNotObjOwner.
|
||||
objOwnerCanonicalID,
|
||||
});
|
||||
}
|
||||
return callback(null, xml, corsHeaders);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ function multipartDelete(authInfo, request, log, callback) {
|
|||
const uploadId = request.query.uploadId;
|
||||
|
||||
abortMultipartUpload(authInfo, bucketName, objectKey, uploadId, log,
|
||||
(err, destinationBucket, partSizeSum) => {
|
||||
(err, destinationBucket, partSizeSum, objMD) => {
|
||||
const corsHeaders = collectCorsHeaders(request.headers.origin,
|
||||
request.method, destinationBucket);
|
||||
const location = destinationBucket ?
|
||||
|
@ -49,6 +49,7 @@ function multipartDelete(authInfo, request, log, callback) {
|
|||
bucket: bucketName,
|
||||
keys: [objectKey],
|
||||
byteLength: partSizeSum,
|
||||
objOwnerCanonicalID: objMD ? objMD['owner-id'] : '',
|
||||
});
|
||||
}
|
||||
return callback(null, corsHeaders);
|
||||
|
|
|
@ -146,8 +146,12 @@ function objectDelete(authInfo, request, log, cb) {
|
|||
resHeaders['x-amz-version-id'] = result.versionId === 'null' ?
|
||||
result.versionId : versionIdUtils.encode(result.versionId);
|
||||
}
|
||||
pushMetric('putDeleteMarkerObject', log, { authInfo,
|
||||
bucket: bucketName, keys: [objectKey] });
|
||||
pushMetric('putDeleteMarkerObject', log, {
|
||||
authInfo,
|
||||
bucket: bucketName,
|
||||
keys: [objectKey],
|
||||
objOwnerCanonicalID: objectMD ? objectMD['owner-id'] : '',
|
||||
});
|
||||
} else {
|
||||
log.end().addDefaultFields({
|
||||
contentLength: objectMD['content-length'],
|
||||
|
@ -157,7 +161,9 @@ function objectDelete(authInfo, request, log, cb) {
|
|||
bucket: bucketName,
|
||||
keys: [objectKey],
|
||||
byteLength: Number.parseInt(objectMD['content-length'], 10),
|
||||
numberOfObjects: 1 });
|
||||
numberOfObjects: 1,
|
||||
objOwnerCanonicalID: objectMD ? objectMD['owner-id'] : '',
|
||||
});
|
||||
}
|
||||
return cb(err, resHeaders);
|
||||
});
|
||||
|
|
|
@ -196,7 +196,8 @@ function listMetrics(metricType) {
|
|||
*/
|
||||
function pushMetric(action, log, metricObj) {
|
||||
const { bucket, keys, byteLength, newByteLength,
|
||||
oldByteLength, numberOfObjects, authInfo, canonicalID } = metricObj;
|
||||
oldByteLength, numberOfObjects, authInfo, canonicalID,
|
||||
objOwnerCanonicalID } = metricObj;
|
||||
const utapiObj = {
|
||||
bucket,
|
||||
keys,
|
||||
|
@ -205,10 +206,14 @@ function pushMetric(action, log, metricObj) {
|
|||
oldByteLength,
|
||||
numberOfObjects,
|
||||
};
|
||||
// If objOwnerCanonicalID is included, there is possible discrepancy between
|
||||
// object owner and requester, so use objOwnerCanonicalID for metrics
|
||||
// If `authInfo` is included by the API, get the account's canonical ID for
|
||||
// account-level metrics and the shortId for user-level metrics. Otherwise
|
||||
// check if the canonical ID is already provided for account-level metrics.
|
||||
if (authInfo) {
|
||||
if (objOwnerCanonicalID) {
|
||||
utapiObj.accountId = objOwnerCanonicalID;
|
||||
} else if (authInfo) {
|
||||
utapiObj.accountId = authInfo.getCanonicalID();
|
||||
utapiObj.userId = authInfo.isRequesterAnIAMUser() ?
|
||||
authInfo.getShortid() : undefined;
|
||||
|
|
|
@ -9,76 +9,92 @@ const { ds } = require('../../../lib/data/in_memory/backend');
|
|||
const DummyRequest = require('../DummyRequest');
|
||||
const { bucketPut } = require('../../../lib/api/bucketPut');
|
||||
const objectPut = require('../../../lib/api/objectPut');
|
||||
const bucketPutACL = require('../../../lib/api/bucketPutACL');
|
||||
|
||||
const log = new DummyRequestLogger();
|
||||
const canonicalID = 'accessKey1';
|
||||
const altCanonicalID = 'accessKey2';
|
||||
const authInfo = makeAuthInfo(canonicalID);
|
||||
const altAuthInfo = makeAuthInfo(altCanonicalID);
|
||||
const namespace = 'default';
|
||||
const bucketName = 'bucketname';
|
||||
const postBody = Buffer.from('I am a body', 'utf8');
|
||||
const contentLength = 2 * postBody.length;
|
||||
const objectKey1 = 'objectName1';
|
||||
const objectKey2 = 'objectName2';
|
||||
const objectKey3 = 'objectName3';
|
||||
const testBucketPutRequest = new DummyRequest({
|
||||
bucketName,
|
||||
namespace,
|
||||
headers: {},
|
||||
url: `/${bucketName}`,
|
||||
});
|
||||
const testPutObjectRequest1 = new DummyRequest({
|
||||
bucketName,
|
||||
namespace,
|
||||
objectKey: objectKey1,
|
||||
headers: {},
|
||||
url: `/${bucketName}/${objectKey1}`,
|
||||
}, postBody);
|
||||
const testPutObjectRequest2 = new DummyRequest({
|
||||
bucketName,
|
||||
namespace,
|
||||
objectKey: objectKey2,
|
||||
headers: {},
|
||||
url: `/${bucketName}/${objectKey2}`,
|
||||
}, postBody);
|
||||
const testPutObjectRequest3 = new DummyRequest({
|
||||
bucketName,
|
||||
namespace,
|
||||
objectKey: objectKey3,
|
||||
headers: {},
|
||||
url: `/${bucketName}/${objectKey3}`,
|
||||
}, postBody);
|
||||
|
||||
describe('getObjMetadataAndDelete function for multiObjectDelete', () => {
|
||||
let testPutObjectRequest1;
|
||||
let testPutObjectRequest2;
|
||||
const request = new DummyRequest({
|
||||
headers: {},
|
||||
parsedContentLength: contentLength,
|
||||
}, postBody);
|
||||
const bucket = { getVersioningConfiguration: () => null };
|
||||
|
||||
beforeEach(done => {
|
||||
cleanup();
|
||||
testPutObjectRequest1 = new DummyRequest({
|
||||
bucketName,
|
||||
namespace,
|
||||
objectKey: objectKey1,
|
||||
headers: {},
|
||||
url: `/${bucketName}/${objectKey1}`,
|
||||
}, postBody);
|
||||
testPutObjectRequest2 = new DummyRequest({
|
||||
bucketName,
|
||||
namespace,
|
||||
objectKey: objectKey2,
|
||||
headers: {},
|
||||
url: `/${bucketName}/${objectKey2}`,
|
||||
}, postBody);
|
||||
bucketPut(authInfo, testBucketPutRequest, log, () => {
|
||||
objectPut(authInfo, testPutObjectRequest1,
|
||||
undefined, log, () => {
|
||||
objectPut(authInfo, testPutObjectRequest2,
|
||||
undefined, log, () => {
|
||||
assert.strictEqual(metadata.keyMaps
|
||||
.get(bucketName)
|
||||
.has(objectKey1), true);
|
||||
assert.strictEqual(metadata.keyMaps
|
||||
.get(bucketName)
|
||||
.has(objectKey2), true);
|
||||
done();
|
||||
});
|
||||
describe('bucket and objects belong to same account', () => {
|
||||
beforeEach(done => {
|
||||
cleanup();
|
||||
bucketPut(authInfo, testBucketPutRequest, log, () => {
|
||||
objectPut(authInfo, testPutObjectRequest1, undefined,
|
||||
log, () => {
|
||||
objectPut(authInfo, testPutObjectRequest2, undefined,
|
||||
log, () => {
|
||||
assert.strictEqual(metadata.keyMaps
|
||||
.get(bucketName)
|
||||
.has(objectKey1), true);
|
||||
assert.strictEqual(metadata.keyMaps
|
||||
.get(bucketName)
|
||||
.has(objectKey2), true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully get object metadata and then ' +
|
||||
'delete metadata and data', done => {
|
||||
getObjMetadataAndDelete(authInfo, 'foo', request, bucketName, bucket,
|
||||
true, [], [{ key: objectKey1 }, { key: objectKey2 }], log,
|
||||
(err, quietSetting, errorResults, numOfObjects,
|
||||
successfullyDeleted, totalContentLengthDeleted) => {
|
||||
it('should successfully get object metadata and then ' +
|
||||
'delete metadata and data', done => {
|
||||
getObjMetadataAndDelete(authInfo, authInfo.getCanonicalID(),
|
||||
request, bucketName, bucket, true, [],
|
||||
[{ key: objectKey1 }, { key: objectKey2 }], log,
|
||||
(err, quietSetting, errorResults, deletedObjStats) => {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(quietSetting, true);
|
||||
assert.deepStrictEqual(errorResults, []);
|
||||
assert.strictEqual(numOfObjects, 2);
|
||||
assert.strictEqual(totalContentLengthDeleted, contentLength);
|
||||
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||
numOfObjectsRemoved, 2);
|
||||
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||
numOfObjectsRemoved, 0);
|
||||
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||
totalContentLengthDeleted, contentLength);
|
||||
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||
totalContentLengthDeleted, 0);
|
||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||
.has(objectKey1), false);
|
||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||
|
@ -91,37 +107,42 @@ describe('getObjMetadataAndDelete function for multiObjectDelete', () => {
|
|||
done();
|
||||
}, 20);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should return success results if no such key', done => {
|
||||
getObjMetadataAndDelete(authInfo, 'foo', request, bucketName, bucket,
|
||||
true, [], [{ key: 'madeup1' }, { key: 'madeup2' }], log,
|
||||
(err, quietSetting, errorResults, numOfObjects,
|
||||
successfullyDeleted, totalContentLengthDeleted) => {
|
||||
it('should return success results if no such key', done => {
|
||||
getObjMetadataAndDelete(authInfo, authInfo.getCanonicalID(),
|
||||
request, bucketName, bucket, true, [],
|
||||
[{ key: 'madeup1' }, { key: 'madeup2' }], log,
|
||||
(err, quietSetting, errorResults, deletedObjStats) => {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(quietSetting, true);
|
||||
assert.deepStrictEqual(errorResults, []);
|
||||
assert.strictEqual(numOfObjects, 0);
|
||||
assert.strictEqual(totalContentLengthDeleted,
|
||||
0);
|
||||
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||
numOfObjectsRemoved, 0);
|
||||
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||
numOfObjectsRemoved, 0);
|
||||
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||
totalContentLengthDeleted, 0);
|
||||
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||
totalContentLengthDeleted, 0);
|
||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||
.has(objectKey1), true);
|
||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||
.has(objectKey2), true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should return error results if err from metadata getting object' +
|
||||
it('should return error results if err from metadata getting object' +
|
||||
'is error other than NoSuchKey', done => {
|
||||
// we fake an error by calling on an imaginary bucket
|
||||
// even though the getObjMetadataAndDelete function would
|
||||
// never be called if there was no bucket (would error out earlier
|
||||
// in API)
|
||||
getObjMetadataAndDelete(authInfo, 'foo', request, 'madeupbucket',
|
||||
bucket, true, [], [{ key: objectKey1 }, { key: objectKey2 }], log,
|
||||
(err, quietSetting, errorResults, numOfObjects,
|
||||
successfullyDeleted, totalContentLengthDeleted) => {
|
||||
// we fake an error by calling on an imaginary bucket
|
||||
// even though the getObjMetadataAndDelete function would
|
||||
// never be called if there was no bucket (would error out earlier
|
||||
// in API)
|
||||
getObjMetadataAndDelete(authInfo, authInfo.getCanonicalID(),
|
||||
request, 'madeupbucket', bucket, true, [],
|
||||
[{ key: objectKey1 }, { key: objectKey2 }], log,
|
||||
(err, quietSetting, errorResults, deletedObjStats) => {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(quietSetting, true);
|
||||
assert.deepStrictEqual(errorResults, [
|
||||
|
@ -134,54 +155,151 @@ describe('getObjMetadataAndDelete function for multiObjectDelete', () => {
|
|||
error: errors.NoSuchBucket,
|
||||
},
|
||||
]);
|
||||
assert.strictEqual(totalContentLengthDeleted,
|
||||
0);
|
||||
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||
totalContentLengthDeleted, 0);
|
||||
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||
totalContentLengthDeleted, 0);
|
||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||
.has(objectKey1), true);
|
||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||
.has(objectKey2), true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should return no error or success results if no objects in play',
|
||||
done => {
|
||||
getObjMetadataAndDelete(authInfo, 'foo', request, bucketName,
|
||||
bucket, true, [], [], log,
|
||||
(err, quietSetting, errorResults, numOfObjects,
|
||||
successfullyDeleted, totalContentLengthDeleted) => {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(quietSetting, true);
|
||||
assert.deepStrictEqual(errorResults, []);
|
||||
assert.strictEqual(numOfObjects, 0);
|
||||
assert.strictEqual(totalContentLengthDeleted,
|
||||
0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass along error results', done => {
|
||||
const errorResultsSample = [
|
||||
{
|
||||
key: 'somekey1',
|
||||
error: errors.AccessDenied,
|
||||
},
|
||||
{
|
||||
key: 'somekey2',
|
||||
error: errors.AccessDenied,
|
||||
},
|
||||
];
|
||||
getObjMetadataAndDelete(authInfo, 'foo', request, bucketName, bucket,
|
||||
true, errorResultsSample,
|
||||
it('should return no error or success results if no objects in play',
|
||||
done => {
|
||||
getObjMetadataAndDelete(authInfo, authInfo.getCanonicalID(),
|
||||
request, bucketName, bucket, true, [], [], log,
|
||||
(err, quietSetting, errorResults, deletedObjStats) => {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(quietSetting, true);
|
||||
assert.deepStrictEqual(errorResults, []);
|
||||
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||
numOfObjectsRemoved, 0);
|
||||
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||
numOfObjectsRemoved, 0);
|
||||
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||
totalContentLengthDeleted, 0);
|
||||
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||
totalContentLengthDeleted, 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass along error results', done => {
|
||||
const errorResultsSample = [
|
||||
{
|
||||
key: 'somekey1',
|
||||
error: errors.AccessDenied,
|
||||
},
|
||||
{
|
||||
key: 'somekey2',
|
||||
error: errors.AccessDenied,
|
||||
},
|
||||
];
|
||||
getObjMetadataAndDelete(authInfo, authInfo.getCanonicalID(),
|
||||
request, bucketName, bucket, true, errorResultsSample,
|
||||
[{ key: objectKey1 }, { key: objectKey2 }], log,
|
||||
(err, quietSetting, errorResults, numOfObjects,
|
||||
successfullyDeleted, totalContentLengthDeleted) => {
|
||||
(err, quietSetting, errorResults, deletedObjStats) => {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(quietSetting, true);
|
||||
assert.deepStrictEqual(errorResults, errorResultsSample);
|
||||
assert.strictEqual(numOfObjects, 2);
|
||||
assert.strictEqual(totalContentLengthDeleted, contentLength);
|
||||
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||
numOfObjectsRemoved, 2);
|
||||
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||
numOfObjectsRemoved, 0);
|
||||
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||
totalContentLengthDeleted, contentLength);
|
||||
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||
totalContentLengthDeleted, 0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('bucket and objects belong to different accounts', () => {
|
||||
beforeEach(done => {
|
||||
cleanup();
|
||||
bucketPut(authInfo, testBucketPutRequest, log, () => {
|
||||
const testACLRequest = {
|
||||
bucketName,
|
||||
namespace,
|
||||
headers: { host: `${bucketName}.s3.amazonaws.com` },
|
||||
post: '<AccessControlPolicy xmlns=' +
|
||||
'"http://s3.amazonaws.com/doc/2006-03-01/">' +
|
||||
'<Owner>' +
|
||||
`<ID>${authInfo.getCanonicalID()}</ID>` +
|
||||
'<DisplayName>OwnerDisplayName</DisplayName>' +
|
||||
'</Owner>' +
|
||||
'<AccessControlList>' +
|
||||
'<Grant>' +
|
||||
'<Grantee xsi:type="CanonicalUser">' +
|
||||
`<ID>${altAuthInfo.getCanonicalID()}</ID>` +
|
||||
'<DisplayName>OwnerDisplayName</DisplayName>' +
|
||||
'</Grantee>' +
|
||||
'<Permission>WRITE</Permission>' +
|
||||
'</Grant>' +
|
||||
'</AccessControlList>' +
|
||||
'</AccessControlPolicy>',
|
||||
url: '/?acl',
|
||||
query: { acl: '' },
|
||||
};
|
||||
bucketPutACL(authInfo, testACLRequest, log, () => {
|
||||
objectPut(authInfo, testPutObjectRequest1, undefined,
|
||||
log, () => {
|
||||
objectPut(altAuthInfo, testPutObjectRequest2, undefined,
|
||||
log, () => {
|
||||
objectPut(altAuthInfo, testPutObjectRequest3,
|
||||
undefined, log, () => {
|
||||
assert.strictEqual(metadata.keyMaps
|
||||
.get(bucketName)
|
||||
.has(objectKey1), true);
|
||||
assert.strictEqual(metadata.keyMaps
|
||||
.get(bucketName)
|
||||
.has(objectKey2), true);
|
||||
assert.strictEqual(metadata.keyMaps
|
||||
.get(bucketName)
|
||||
.has(objectKey3), true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully get object metadata and then ' +
|
||||
'delete metadata and data', done => {
|
||||
getObjMetadataAndDelete(authInfo, authInfo.getCanonicalID(),
|
||||
request, bucketName, bucket, true, [],
|
||||
[{ key: objectKey1 }, { key: objectKey2 }, { key: objectKey3 }],
|
||||
log, (err, quietSetting, errorResults, deletedObjStats) => {
|
||||
assert.ifError(err);
|
||||
assert.strictEqual(quietSetting, true);
|
||||
assert.deepStrictEqual(errorResults, []);
|
||||
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||
numOfObjectsRemoved, 1);
|
||||
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||
numOfObjectsRemoved, 2);
|
||||
assert.strictEqual(deletedObjStats.requesterIsObjOwner.
|
||||
totalContentLengthDeleted, postBody.length);
|
||||
assert.strictEqual(deletedObjStats.requesterNotObjOwner.
|
||||
totalContentLengthDeleted, contentLength);
|
||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||
.has(objectKey1), false);
|
||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||
.has(objectKey2), false);
|
||||
assert.strictEqual(metadata.keyMaps.get(bucketName)
|
||||
.has(objectKey3), false);
|
||||
// call to delete data is async so wait 20 ms to check
|
||||
// that data deleted
|
||||
setTimeout(() => {
|
||||
// eslint-disable-next-line
|
||||
assert.deepStrictEqual(ds, [ , , , , ]);
|
||||
done();
|
||||
}, 20);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue