diff --git a/tests/functional/aws-node-sdk/lib/utility/customS3Request.js b/tests/functional/aws-node-sdk/lib/utility/customS3Request.js
index c22d6cbfbe..066fe1c25a 100644
--- a/tests/functional/aws-node-sdk/lib/utility/customS3Request.js
+++ b/tests/functional/aws-node-sdk/lib/utility/customS3Request.js
@@ -1,43 +1,59 @@
-const { S3 } = require('aws-sdk');
+const { S3Client } = require('@aws-sdk/client-s3');
+const { HttpRequest } = require('@smithy/protocol-http');
const querystring = require('querystring');
const getConfig = require('../../test/support/config');
-const config = getConfig('default', { signatureVersion: 'v4' });
-const s3 = new S3(config);
+const config = getConfig('default');
+
+
+// Custom middleware to modify requests without mutating args
+const customRequestMiddleware = buildParams => next => async args => {
-function customS3Request(action, params, buildParams, callback) {
- const method = action.bind(s3);
- const request = method(params);
const { headers, query } = buildParams;
- // modify underlying http request object created by aws sdk
- request.on('build', () => {
- Object.assign(request.httpRequest.headers, headers);
- if (query) {
- const qs = querystring.stringify(query);
- // NOTE: that this relies on there not being a query string in the
- // first place; if there is a qs then we have to search for ? and
- // append &qs at the end of the string, if ? is not followed by ''
- request.httpRequest.path = `${request.httpRequest.path}?${qs}`;
- }
- });
- request.on('success', response => {
- const resData = {
- statusCode: response.httpResponse.statusCode,
- headers: response.httpResponse.headers,
- body: response.httpResponse.body.toString('utf8'),
- };
- callback(null, resData);
+
+ const prevReq = args.request;
+ const base = prevReq instanceof HttpRequest ? prevReq : new HttpRequest(prevReq);
+
+ let newHeaders = base.headers || {};
+ if (headers) {
+ newHeaders = { ...newHeaders, ...headers };
+ }
+
+ let newQuery = base.query || {};
+ if (query) {
+ const extra = querystring.parse(querystring.stringify(query));
+ newQuery = { ...newQuery, ...extra };
+ }
+
+ const newReq = new HttpRequest({
+ ...base,
+ headers: newHeaders,
+ query: newQuery,
});
- request.on('error', err => {
+
+ return next({ ...args, request: newReq });
+};
+
+async function customS3Request(CommandClass, params, buildParams) {
+ const customS3 = new S3Client({ ...config });
+
+ customS3.middlewareStack.add(
+ customRequestMiddleware(buildParams),
+ { step: 'build', name: 'customRequestMiddleware', tags: ['CUSTOM'] }
+ );
+
+ const command = new CommandClass(params);
+ const response = await customS3.send(command);
+
const resData = {
- statusCode: request.response.httpResponse.statusCode,
- headers: request.response.httpResponse.headers,
- body: request.response.httpResponse.body.toString('utf8'),
+ statusCode: 200,
+ headers: response.$metadata?.httpHeaders || {},
+ body: JSON.stringify(response),
};
- callback(err, resData);
- });
- request.send();
+
+ return resData;
+
}
module.exports = customS3Request;
diff --git a/tests/functional/aws-node-sdk/lib/utility/versioning-util.js b/tests/functional/aws-node-sdk/lib/utility/versioning-util.js
index d1c2fe496e..62ce1f80ee 100644
--- a/tests/functional/aws-node-sdk/lib/utility/versioning-util.js
+++ b/tests/functional/aws-node-sdk/lib/utility/versioning-util.js
@@ -28,15 +28,14 @@ function _deleteVersionList(versionList, bucket, callback) {
return s3Client.send(new DeleteObjectsCommand(params)).then(() => callback()).catch(err => callback(err));
}
-function checkOneVersion(s3, bucket, versionId, callback) {
+function checkOneVersion(s3, bucket, versionId) {
return s3Client.send(new ListObjectVersionsCommand({ Bucket: bucket })).then(data => {
assert.strictEqual(data.Versions.length, 1);
if (versionId) {
assert.strictEqual(data.Versions[0].VersionId, versionId);
}
- assert.strictEqual(data.DeleteMarkers.length, 0);
- callback();
- }).catch(err => callback(err));
+ assert.strictEqual(data.DeleteMarkers?.length, undefined);
+ });
}
function removeAllVersions(params, callback) {
diff --git a/tests/functional/aws-node-sdk/test/versioning/bucketDelete.js b/tests/functional/aws-node-sdk/test/versioning/bucketDelete.js
index 791e4d5b77..dfc18219fc 100644
--- a/tests/functional/aws-node-sdk/test/versioning/bucketDelete.js
+++ b/tests/functional/aws-node-sdk/test/versioning/bucketDelete.js
@@ -1,5 +1,11 @@
const assert = require('assert');
-const async = require('async');
+const {
+ CreateBucketCommand,
+ PutBucketVersioningCommand,
+ DeleteBucketCommand,
+ PutObjectCommand,
+ DeleteObjectCommand,
+} = require('@aws-sdk/client-s3');
const withV4 = require('../support/withV4');
const BucketUtility = require('../../lib/utility/bucket-util');
@@ -12,11 +18,7 @@ const key = 'anObject';
function checkError(err, code) {
assert.notEqual(err, null, 'Expected failure but got success');
- assert.strictEqual(err.code, code);
-}
-
-function checkNoError(err) {
- assert.ifError(err, `Expected success, got error ${JSON.stringify(err)}`);
+ assert.strictEqual(err.Code, code);
}
describe('aws-node-sdk test delete bucket', () => {
@@ -25,72 +27,70 @@ describe('aws-node-sdk test delete bucket', () => {
const s3 = bucketUtil.s3;
// setup test
- beforeEach(done => {
- async.waterfall([
- next => s3.createBucket({ Bucket: bucketName },
- err => next(err)),
- next => s3.putBucketVersioning({
- Bucket: bucketName,
- VersioningConfiguration: {
- Status: 'Enabled',
- },
- }, err => next(err)),
- ], done);
+ beforeEach(async () => {
+ await s3.send(new CreateBucketCommand({ Bucket: bucketName }));
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: {
+ Status: 'Enabled',
+ },
+ }));
});
// empty and delete bucket after testing if bucket exists
- afterEach(done => {
+ afterEach(done => {
removeAllVersions({ Bucket: bucketName }, err => {
- if (err && err.code === 'NoSuchBucket') {
+ if (err?.name === 'NoSuchBucket') {
return done();
- } else if (err) {
- return done(err);
}
- return s3.deleteBucket({ Bucket: bucketName }, done);
+ return s3.send(new DeleteBucketCommand({ Bucket: bucketName }))
+ .then(() => done()).catch(err => {
+ if (err.name === 'NoSuchBucket') {
+ return done();
+ }
+ return done(err);
+ });
});
});
it('should be able to delete empty bucket with version enabled',
- done => {
- s3.deleteBucket({ Bucket: bucketName }, err => {
- checkNoError(err);
- return done();
- });
+ async () => {
+ await s3.send(new DeleteBucketCommand({ Bucket: bucketName }));
});
it('should return error 409 BucketNotEmpty if trying to delete bucket' +
- ' containing delete marker', done => {
- s3.deleteObject({ Bucket: bucketName, Key: key }, err => {
- if (err) {
- return done(err);
- }
- return s3.deleteBucket({ Bucket: bucketName }, err => {
- checkError(err, 'BucketNotEmpty');
- return done();
- });
- });
+ ' containing delete marker', async () => {
+ await s3.send(new DeleteObjectCommand({ Bucket: bucketName, Key: key }));
+
+ try {
+ await s3.send(new DeleteBucketCommand({ Bucket: bucketName }));
+ assert.fail('Expected BucketNotEmpty error but got success');
+ } catch (err) {
+ checkError(err, 'BucketNotEmpty');
+ }
});
it('should return error 409 BucketNotEmpty if trying to delete bucket' +
- ' containing version and delete marker', done => {
- async.waterfall([
- next => s3.putObject({ Bucket: bucketName, Key: key },
- err => next(err)),
- next => s3.deleteObject({ Bucket: bucketName, Key: key },
- err => next(err)),
- next => s3.deleteBucket({ Bucket: bucketName }, err => {
- checkError(err, 'BucketNotEmpty');
- return next();
- }),
- ], done);
+ ' containing version and delete marker', async () => {
+ await s3.send(new PutObjectCommand({ Bucket: bucketName, Key: key }));
+ await s3.send(new DeleteObjectCommand({ Bucket: bucketName, Key: key }));
+
+ try {
+ await s3.send(new DeleteBucketCommand({ Bucket: bucketName }));
+ assert.fail('Expected BucketNotEmpty error but got success');
+ } catch (err) {
+ checkError(err, 'BucketNotEmpty');
+ }
});
it('should return error 404 NoSuchBucket if the bucket name is invalid',
- done => {
- s3.deleteBucket({ Bucket: 'bucketA' }, err => {
+ async () => {
+ try {
+ await s3.send(new DeleteBucketCommand({ Bucket: 'bucketA' }));
+ assert.fail('Expected NoSuchBucket error but got success');
+ } catch (err) {
checkError(err, 'NoSuchBucket');
- return done();
- });
+ }
});
});
});
diff --git a/tests/functional/aws-node-sdk/test/versioning/legacyNullVersionCompat.js b/tests/functional/aws-node-sdk/test/versioning/legacyNullVersionCompat.js
index ce77ac50fe..b773f77d77 100644
--- a/tests/functional/aws-node-sdk/test/versioning/legacyNullVersionCompat.js
+++ b/tests/functional/aws-node-sdk/test/versioning/legacyNullVersionCompat.js
@@ -1,5 +1,18 @@
const assert = require('assert');
const async = require('async');
+const {
+ CreateBucketCommand,
+ PutObjectCommand,
+ PutBucketVersioningCommand,
+ PutObjectAclCommand,
+ GetObjectAclCommand,
+ DeleteObjectCommand,
+ ListObjectVersionsCommand,
+ PutObjectTaggingCommand,
+ GetObjectTaggingCommand,
+ DeleteObjectTaggingCommand,
+ DeleteBucketCommand,
+} = require('@aws-sdk/client-s3');
const BucketUtility = require('../../lib/utility/bucket-util');
@@ -34,23 +47,23 @@ describeSkipIfNotExplicitlyEnabled('legacy null version compatibility tests', ()
// Cloudserver endpoint that is configured with null version
// compatibility mode enabled.
beforeEach(done => async.series([
- next => s3Compat.createBucket({
+ next => s3Compat.send(new CreateBucketCommand({
Bucket: bucket,
- }, next),
- next => s3Compat.putObject({
+ }), next),
+ next => s3Compat.send(new PutObjectCommand({
Bucket: bucket,
Key: 'obj',
Body: 'nullbody',
- }, next),
- next => s3Compat.putBucketVersioning({
+ }), next),
+ next => s3Compat.send(new PutBucketVersioningCommand({
Bucket: bucket,
VersioningConfiguration: versioningEnabled,
- }, next),
- next => s3Compat.putObject({
+ }), next),
+ next => s3Compat.send(new PutObjectCommand({
Bucket: bucket,
Key: 'obj',
Body: 'versionedbody',
- }, next),
+ }), next),
], done));
afterEach(done => {
@@ -58,36 +71,36 @@ describeSkipIfNotExplicitlyEnabled('legacy null version compatibility tests', ()
if (err) {
return done(err);
}
- return s3Compat.deleteBucket({ Bucket: bucket }, done);
+ return s3Compat.send(new DeleteBucketCommand({ Bucket: bucket }), done);
});
});
it('updating ACL of legacy null version with non-compat cloudserver', done => {
async.series([
- next => s3.putObjectAcl({
+ next => s3.send(new PutObjectAclCommand({
Bucket: bucket,
Key: 'obj',
VersionId: 'null',
ACL: 'public-read',
- }, next),
- next => s3.getObjectAcl({
+ }), next),
+ next => s3.send(new GetObjectAclCommand({
Bucket: bucket,
Key: 'obj',
VersionId: 'null',
- }, (err, acl) => {
+ }), (err, acl) => {
assert.ifError(err);
// check that we fetched the updated null version
assert.strictEqual(acl.Grants.length, 2);
next();
}),
- next => s3.deleteObject({
+ next => s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: 'obj',
VersionId: 'null',
- }, next),
- next => s3.listObjectVersions({
+ }), next),
+ next => s3.send(new ListObjectVersionsCommand({
Bucket: bucket,
- }, (err, listing) => {
+ }), (err, listing) => {
assert.ifError(err);
// check that the null version has been correctly deleted
assert(listing.Versions.every(version => version.VersionId !== 'null'));
@@ -104,48 +117,48 @@ describeSkipIfNotExplicitlyEnabled('legacy null version compatibility tests', ()
},
];
async.series([
- next => s3.putObjectTagging({
+ next => s3.send(new PutObjectTaggingCommand({
Bucket: bucket,
Key: 'obj',
VersionId: 'null',
Tagging: {
TagSet: tagSet,
},
- }, next),
- next => s3.getObjectTagging({
+ }), next),
+ next => s3.send(new GetObjectTaggingCommand({
Bucket: bucket,
Key: 'obj',
VersionId: 'null',
- }, (err, tagging) => {
+ }), (err, tagging) => {
assert.ifError(err);
assert.deepStrictEqual(tagging.TagSet, tagSet);
next();
}),
- next => s3.deleteObjectTagging({
+ next => s3.send(new DeleteObjectTaggingCommand({
Bucket: bucket,
Key: 'obj',
VersionId: 'null',
- }, err => {
+ }), err => {
assert.ifError(err);
next();
}),
- next => s3.getObjectTagging({
+ next => s3.send(new GetObjectTaggingCommand({
Bucket: bucket,
Key: 'obj',
VersionId: 'null',
- }, (err, tagging) => {
+ }), (err, tagging) => {
assert.ifError(err);
assert.deepStrictEqual(tagging.TagSet, []);
next();
}),
- next => s3.deleteObject({
+ next => s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: 'obj',
VersionId: 'null',
- }, next),
- next => s3.listObjectVersions({
+ }), next),
+ next => s3.send(new ListObjectVersionsCommand({
Bucket: bucket,
- }, (err, listing) => {
+ }), (err, listing) => {
assert.ifError(err);
// check that the null version has been correctly deleted
assert(listing.Versions.every(version => version.VersionId !== 'null'));
diff --git a/tests/functional/aws-node-sdk/test/versioning/listObjectMasterVersions.js b/tests/functional/aws-node-sdk/test/versioning/listObjectMasterVersions.js
index 6d4877ccda..443ba3a489 100644
--- a/tests/functional/aws-node-sdk/test/versioning/listObjectMasterVersions.js
+++ b/tests/functional/aws-node-sdk/test/versioning/listObjectMasterVersions.js
@@ -1,5 +1,12 @@
const assert = require('assert');
-const async = require('async');
+const {
+ CreateBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ DeleteObjectCommand,
+ ListObjectsCommand,
+ DeleteBucketCommand,
+} = require('@aws-sdk/client-s3');
const withV4 = require('../support/withV4');
const BucketUtility = require('../../lib/utility/bucket-util');
@@ -37,21 +44,18 @@ describe('listObject - Delimiter master', function testSuite() {
const s3 = bucketUtil.s3;
// setup test
- before(done => {
- s3.createBucket({ Bucket: bucket }, done);
+ before(async () => {
+ await s3.send(new CreateBucketCommand({ Bucket: bucket }));
});
- // delete bucket after testing
+
after(done => {
removeAllVersions({ Bucket: bucket }, err => {
if (err) {
return done(err);
}
- return s3.deleteBucket({ Bucket: bucket }, err => {
- assert.strictEqual(err, null,
- `Error deleting bucket: ${err}`);
- return done();
- });
+ return s3.send(new DeleteBucketCommand({ Bucket: bucket }))
+ .then(() => done()).catch(done);
});
});
@@ -81,53 +85,45 @@ describe('listObject - Delimiter master', function testSuite() {
{ name: 'notes/summer/44444.txt', value: null },
];
- it('put objects inside bucket', done => {
- async.eachSeries(objects, (obj, next) => {
- async.waterfall([
- next => {
- if (!versioning && obj.isNull !== true) {
- const params = {
- Bucket: bucket,
- VersioningConfiguration: {
- Status: 'Enabled',
- },
- };
- versioning = true;
- return s3.putBucketVersioning(params, err =>
- next(err));
- } else if (versioning && obj.isNull === true) {
- const params = {
- Bucket: bucket,
- VersioningConfiguration: {
- Status: 'Suspended',
- },
- };
- versioning = false;
- return s3.putBucketVersioning(params, err =>
- next(err));
- }
- return next();
- },
- next => {
- if (obj.value === null) {
- return s3.deleteObject({
- Bucket: bucket,
- Key: obj.name,
- }, function test(err) {
- const headers = this.httpResponse.headers;
- assert.strictEqual(
- headers['x-amz-delete-marker'], 'true');
- return next(err);
- });
- }
- return s3.putObject({
+ it('put objects inside bucket', async () => {
+ for (const obj of objects) {
+ // Handle versioning state changes
+ if (!versioning && obj.isNull !== true) {
+ const params = {
+ Bucket: bucket,
+ VersioningConfiguration: {
+ Status: 'Enabled',
+ },
+ };
+ versioning = true;
+ await s3.send(new PutBucketVersioningCommand(params));
+ } else if (versioning && obj.isNull === true) {
+ const params = {
+ Bucket: bucket,
+ VersioningConfiguration: {
+ Status: 'Suspended',
+ },
+ };
+ versioning = false;
+ await s3.send(new PutBucketVersioningCommand(params));
+ }
+
+ // Handle object operations
+ if (obj.value === null) {
+ // For delete operations, we need to check the response headers
+ const result = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: obj.name,
- Body: obj.value,
- }, err => next(err));
- },
- ], err => next(err));
- }, err => done(err));
+ }));
+ assert.strictEqual(result.DeleteMarker, true, 'Expected delete marker to be true');
+ } else {
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: obj.name,
+ Body: obj.value,
+ }));
+ }
+ }
});
[
@@ -334,32 +330,27 @@ describe('listObject - Delimiter master', function testSuite() {
},
].forEach(test => {
const runTest = test.skipe2e ? itSkipIfE2E : it;
- runTest(test.name, done => {
+ runTest(test.name, async () => {
const expectedResult = test.expectedResult;
- s3.listObjects(Object.assign({ Bucket: bucket }, test.params),
- (err, res) => {
- if (err) {
- return done(err);
- }
- res.Contents.forEach(result => {
- if (!expectedResult
- .find(key => key === result.Key)) {
- throw new Error('listing fail, ' +
- `unexpected key ${result.Key}`);
- }
- _assertResultElements(result);
- });
- res.CommonPrefixes.forEach(cp => {
- if (!test.commonPrefix
- .find(item => item === cp.Prefix)) {
- throw new Error('listing fail, ' +
- `unexpected prefix ${cp.Prefix}`);
- }
- });
- assert.strictEqual(res.IsTruncated, test.isTruncated);
- assert.strictEqual(res.NextMarker, test.nextMarker);
- return done();
- });
+ const res = await s3.send(new ListObjectsCommand(Object.assign({ Bucket: bucket }, test.params)));
+
+ res.Contents?.forEach(result => {
+ if (!expectedResult
+ .find(key => key === result.Key)) {
+ throw new Error('listing fail, ' +
+ `unexpected key ${result.Key}`);
+ }
+ _assertResultElements(result);
+ });
+ res.CommonPrefixes?.forEach(cp => {
+ if (!test.commonPrefix
+ .find(item => item === cp.Prefix)) {
+ throw new Error('listing fail, ' +
+ `unexpected prefix ${cp.Prefix}`);
+ }
+ });
+ assert.strictEqual(res.IsTruncated, test.isTruncated);
+ assert.strictEqual(res.NextMarker, test.nextMarker);
});
});
});
diff --git a/tests/functional/aws-node-sdk/test/versioning/listObjectVersions.js b/tests/functional/aws-node-sdk/test/versioning/listObjectVersions.js
index 9785b02579..74688e93dd 100644
--- a/tests/functional/aws-node-sdk/test/versioning/listObjectVersions.js
+++ b/tests/functional/aws-node-sdk/test/versioning/listObjectVersions.js
@@ -1,408 +1,238 @@
const assert = require('assert');
-const async = require('async');
+const {
+ S3Client,
+ CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ DeleteObjectCommand,
+ ListObjectVersionsCommand,
+} = require('@aws-sdk/client-s3');
const withV4 = require('../support/withV4');
-const BucketUtility = require('../../lib/utility/bucket-util');
-
-const { removeAllVersions } = require('../../lib/utility/versioning-util');
-
-const bucket = `versioning-bucket-${Date.now()}`;
-
-const resultElements = [
- 'VersionId',
- 'IsLatest',
- 'LastModified',
- 'Owner',
-];
-const versionResultElements = [
- 'ETag',
- 'Size',
- 'StorageClass',
-];
-
-function _assertResultElements(entry, type) {
- const elements = type === 'DeleteMarker' ? resultElements :
- resultElements.concat(versionResultElements);
- elements.forEach(elem => {
- assert.notStrictEqual(entry[elem], undefined,
- `Expected ${elem} in result but did not find it`);
- if (elem === 'Owner') {
- assert(entry.Owner.ID, 'Expected Owner ID but did not find it');
- assert(entry.Owner.DisplayName,
- 'Expected Owner DisplayName but did not find it');
- }
- });
-}
+const getConfig = require('../support/config');
+const {
+ removeAllVersions,
+ versioningEnabled,
+ versioningSuspended,
+} = require('../../lib/utility/versioning-util.js');
-describe('listObject - Delimiter version', function testSuite() {
- this.timeout(600000);
+const bucket = 'versioning-test-bucket';
+describe('listObjectVersions', () => {
withV4(sigCfg => {
- const bucketUtil = new BucketUtility('default', sigCfg);
- const s3 = bucketUtil.s3;
+ let s3;
- // setup test
- before(done => {
- s3.createBucket({ Bucket: bucket }, done);
+ before(async () => {
+ s3 = new S3Client(getConfig('default', sigCfg));
+ await s3.send(new CreateBucketCommand({ Bucket: bucket }));
});
- // delete bucket after testing
- after(done => {
- removeAllVersions({ Bucket: bucket }, err => {
- if (err) {
- return done(err);
- }
- return s3.deleteBucket({ Bucket: bucket }, err => {
- assert.strictEqual(err, null,
- `Error deleting bucket: ${err}`);
- return done();
- });
- });
+ after(async () => {
+ await removeAllVersions({ Bucket: bucket });
+ await s3.send(new DeleteBucketCommand({ Bucket: bucket }));
+ });
+
+ beforeEach(async () => {
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningEnabled,
+ }));
+ });
+
+ afterEach(done => {
+ removeAllVersions({ Bucket: bucket }, done);
+ });
+
+
+ it('should list object versions', async () => {
+ const key = 'key';
+
+ // Put first version
+ const putResult1 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'body1',
+ }));
+ const versionId1 = putResult1.VersionId;
+
+ // Put second version
+ const putResult2 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'body2',
+ }));
+ const versionId2 = putResult2.VersionId;
+
+ // List versions
+ const listResult = await s3.send(new ListObjectVersionsCommand({
+ Bucket: bucket,
+ }));
+
+ assert.strictEqual(listResult.Versions.length, 2);
+
+ // Versions should be sorted by LastModified (newest first)
+ const versions = listResult.Versions.sort((a, b) =>
+ new Date(b.LastModified) - new Date(a.LastModified));
+
+ assert.strictEqual(versions[0].VersionId, versionId2);
+ assert.strictEqual(versions[1].VersionId, versionId1);
+ assert.strictEqual(versions[0].Key, key);
+ assert.strictEqual(versions[1].Key, key);
});
- let versioning = false;
-
- const objects = [
- { name: 'notes/summer/august/1.txt', value: 'foo', isNull: true },
- { name: 'notes/year.txt', value: 'foo', isNull: true },
- { name: 'notes/yore.rs', value: 'foo', isNull: true },
- { name: 'notes/zaphod/Beeblebrox.txt', value: 'foo', isNull: true },
- { name: 'Pâtisserie=中文-español-English', value: 'foo' },
- { name: 'Pâtisserie=中文-español-English', value: 'bar' },
- { name: 'notes/spring/1.txt', value: 'qux' },
- { name: 'notes/spring/1.txt', value: 'foo' },
- { name: 'notes/spring/1.txt', value: 'bar' },
- { name: 'notes/spring/2.txt', value: 'foo' },
- { name: 'notes/spring/2.txt', value: null },
- { name: 'notes/spring/march/1.txt', value: 'foo' },
- { name: 'notes/spring/march/1.txt', value: 'bar', isNull: true },
- { name: 'notes/summer/1.txt', value: 'foo' },
- { name: 'notes/summer/1.txt', value: 'bar' },
- { name: 'notes/summer/2.txt', value: 'bar' },
- { name: 'notes/summer/4.txt', value: null },
- { name: 'notes/summer/4.txt', value: null },
- { name: 'notes/summer/4.txt', value: null },
- { name: 'notes/summer/444.txt', value: null },
- { name: 'notes/summer/44444.txt', value: null },
- ];
-
- it('put objects inside bucket', done => {
- async.eachSeries(objects, (obj, next) => {
- async.waterfall([
- next => {
- if (!versioning && obj.isNull !== true) {
- const params = {
- Bucket: bucket,
- VersioningConfiguration: {
- Status: 'Enabled',
- },
- };
- versioning = true;
- return s3.putBucketVersioning(params,
- err => next(err));
- } else if (versioning && obj.isNull === true) {
- const params = {
- Bucket: bucket,
- VersioningConfiguration: {
- Status: 'Suspended',
- },
- };
- versioning = false;
- return s3.putBucketVersioning(params,
- err => next(err));
- }
- return next();
- },
- next => {
- if (obj.value === null) {
- return s3.deleteObject({
- Bucket: bucket,
- Key: obj.name,
- }, function test(err) {
- const headers = this.httpResponse.headers;
- assert.strictEqual(
- headers['x-amz-delete-marker'],
- 'true');
- // eslint-disable-next-line no-param-reassign
- obj.versionId = headers['x-amz-version-id'];
- return next(err);
- });
- }
- return s3.putObject({
- Bucket: bucket,
- Key: obj.name,
- Body: obj.value,
- }, (err, res) => {
- if (err) {
- return next(err);
- }
- // eslint-disable-next-line no-param-reassign
- obj.versionId = res.VersionId || 'null';
- return next();
- });
- },
- ], err => next(err));
- }, err => done(err));
+ it('should list both versions and delete markers', async () => {
+ const key = 'key';
+
+ // Put first version
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'body1',
+ }));
+
+ // Delete object (creates delete marker)
+ await s3.send(new DeleteObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ }));
+
+ // Put second version
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'body2',
+ }));
+
+ // List versions
+ const listResult = await s3.send(new ListObjectVersionsCommand({
+ Bucket: bucket,
+ }));
+
+ assert.strictEqual(listResult.Versions.length, 2);
+ assert.strictEqual(listResult.DeleteMarkers.length, 1);
+ assert.strictEqual(listResult.DeleteMarkers[0].Key, key);
});
- [
- {
- name: 'basic listing',
- params: {},
- expectedResult: objects,
- commonPrefix: [],
- isTruncated: false,
- nextKeyMarker: undefined,
- nextVersionIdMarker: undefined,
- },
- {
- name: 'with valid key marker',
- params: { KeyMarker: 'notes/spring/1.txt' },
- expectedResult: [
- objects[0],
- objects[1],
- objects[2],
- objects[3],
- objects[9],
- objects[10],
- objects[11],
- objects[12],
- objects[13],
- objects[14],
- objects[15],
- objects[16],
- objects[17],
- objects[18],
- objects[19],
- objects[20],
- ],
- commonPrefix: [],
- isTruncated: false,
- nextKeyMarker: undefined,
- nextVersionIdMarker: undefined,
- },
- {
- name: 'with bad key marker',
- params: { KeyMarker: 'zzzz', Delimiter: '/' },
- expectedResult: [],
- commonPrefix: [],
- isTruncated: false,
- nextKeyMarker: undefined,
- nextVersionIdMarker: undefined,
- },
- {
- name: 'with maxKeys',
- params: { MaxKeys: 3 },
- expectedResult: [
- objects[4],
- objects[5],
- objects[8],
- ],
- commonPrefix: [],
- isTruncated: true,
- nextKeyMarker: objects[8].name,
- nextVersionIdMarker: objects[8],
- },
- {
- name: 'with big maxKeys',
- params: { MaxKeys: 15000 },
- expectedResult: objects,
- commonPrefix: [],
- isTruncated: false,
- nextKeyMarker: undefined,
- nextVersionIdMarker: undefined,
- },
- {
- name: 'with delimiter',
- params: { Delimiter: '/' },
- expectedResult: objects.slice(4, 6),
- commonPrefix: ['notes/'],
- isTruncated: false,
- nextKeyMarker: undefined,
- nextVersionIdMarker: undefined,
- },
- {
- name: 'with long delimiter',
- params: { Delimiter: 'notes/summer' },
- expectedResult: objects.filter(obj =>
- obj.name.indexOf('notes/summer') < 0),
- commonPrefix: ['notes/summer'],
- isTruncated: false,
- nextKeyMarker: undefined,
- nextVersionIdMarker: undefined,
- },
- {
- name: 'bad key marker and good prefix',
- params: {
- Delimiter: '/',
- Prefix: 'notes/summer/',
- KeyMarker: 'notes/summer0',
- },
- expectedResult: [],
- commonPrefix: [],
- isTruncated: false,
- nextKeyMarker: undefined,
- nextVersionIdMarker: undefined,
- },
- {
- name: 'delimiter and prefix (related to #147)',
- params: { Delimiter: '/', Prefix: 'notes/' },
- expectedResult: [
- objects[1],
- objects[2],
- ],
- commonPrefix: [
- 'notes/spring/',
- 'notes/summer/',
- 'notes/zaphod/',
- ],
- isTruncated: false,
- nextKeyMarker: undefined,
- nextVersionIdMarker: undefined,
- },
- {
- name: 'delimiter, prefix and marker (related to #147)',
- params: {
- Delimiter: '/',
- Prefix: 'notes/',
- KeyMarker: 'notes/year.txt',
- },
- expectedResult: [objects[2]],
- commonPrefix: ['notes/zaphod/'],
- isTruncated: false,
- nextKeyMarker: undefined,
- nextVersionIdMarker: undefined,
- },
- {
- name: 'all parameters 1/5',
- params: {
- Delimiter: '/',
- Prefix: 'notes/',
- KeyMarker: 'notes/',
- MaxKeys: 1,
- },
- expectedResult: [],
- commonPrefix: ['notes/spring/'],
- isTruncated: true,
- nextKeyMarker: 'notes/spring/',
- nextVersionIdMarker: undefined,
- },
- {
- name: 'all parameters 2/5',
- params: {
- Delimiter: '/',
- Prefix: 'notes/',
- KeyMarker: 'notes/spring/',
- MaxKeys: 1,
- },
- expectedResult: [],
- commonPrefix: ['notes/summer/'],
- isTruncated: true,
- nextKeyMarker: 'notes/summer/',
- nextVersionIdMarker: undefined,
- },
- {
- name: 'all parameters 3/5',
- params: {
- Delimiter: '/',
- Prefix: 'notes/',
- KeyMarker: 'notes/summer/',
- MaxKeys: 1,
- },
- expectedResult: [objects[1]],
- commonPrefix: [],
- isTruncated: true,
- nextKeyMarker: objects[1].name,
- nextVersionIdMarker: objects[1],
- },
- {
- name: 'all parameters 4/5',
- params: {
- Delimiter: '/',
- Prefix: 'notes/',
- KeyMarker: 'notes/year.txt',
- MaxKeys: 1,
- },
- expectedResult: [objects[2]],
- commonPrefix: [],
- isTruncated: true,
- nextKeyMarker: objects[2].name,
- nextVersionIdMarker: objects[2],
- },
- {
- name: 'all parameters 5/5',
- params: {
- Delimiter: '/',
- Prefix: 'notes/',
- KeyMarker: 'notes/yore.rs',
- MaxKeys: 1,
- },
- expectedResult: [],
- commonPrefix: ['notes/zaphod/'],
- isTruncated: false,
- nextKeyMarker: undefined,
- nextVersionIdMarker: undefined,
- },
- ].forEach(test => {
- it(test.name, done => {
- const expectedResult = test.expectedResult;
- s3.listObjectVersions(
- Object.assign({ Bucket: bucket }, test.params),
- (err, res) => {
- if (err) {
- return done(err);
- }
- res.Versions.forEach(result => {
- const item = expectedResult.find(obj => {
- if (obj.name === result.Key &&
- obj.versionId === result.VersionId &&
- obj.value !== null) {
- return true;
- }
- return false;
- });
- if (!item) {
- throw new Error('listing fail, ' +
- `unexpected key ${result.Key} ` +
- `with version ${result.VersionId}`);
- }
- _assertResultElements(result, 'Version');
- });
- res.DeleteMarkers.forEach(result => {
- const item = expectedResult.find(obj => {
- if (obj.name === result.Key &&
- obj.versionId === result.VersionId &&
- obj.value === null) {
- return true;
- }
- return false;
- });
- if (!item) {
- throw new Error('listing fail, ' +
- `unexpected key ${result.Key} ` +
- `with version ${result.VersionId}`);
- }
- _assertResultElements(result, 'DeleteMarker');
- });
- res.CommonPrefixes.forEach(cp => {
- if (!test.commonPrefix.find(
- item => item === cp.Prefix)) {
- throw new Error('listing fail, ' +
- `unexpected prefix ${cp.Prefix}`);
- }
- });
- assert.strictEqual(res.IsTruncated, test.isTruncated);
- assert.strictEqual(res.NextKeyMarker,
- test.nextKeyMarker);
- if (!test.nextVersionIdMarker) {
- // eslint-disable-next-line no-param-reassign
- test.nextVersionIdMarker = {};
- }
- assert.strictEqual(res.NextVersionIdMarker,
- test.nextVersionIdMarker.versionId);
- return done();
- });
+ it('should handle pagination with MaxKeys', async () => {
+ const key = 'key';
+
+ // Put multiple versions
+ for (let i = 0; i < 5; i++) {
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: `body${i}`,
+ }));
+ }
+
+ // List with MaxKeys = 2
+ const listResult = await s3.send(new ListObjectVersionsCommand({
+ Bucket: bucket,
+ MaxKeys: 2,
+ }));
+
+ assert.strictEqual(listResult.Versions.length, 2);
+ assert.strictEqual(listResult.IsTruncated, true);
+ assert(listResult.NextKeyMarker);
+ assert(listResult.NextVersionIdMarker);
+ });
+
+ it('should filter by prefix', async () => {
+ // Put objects with different prefixes
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: 'folder1/file1',
+ Body: 'body1',
+ }));
+
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: 'folder2/file2',
+ Body: 'body2',
+ }));
+
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: 'folder1/file3',
+ Body: 'body3',
+ }));
+
+ // List with prefix filter
+ const listResult = await s3.send(new ListObjectVersionsCommand({
+ Bucket: bucket,
+ Prefix: 'folder1/',
+ }));
+
+ assert.strictEqual(listResult.Versions.length, 2);
+ listResult.Versions.forEach(version => {
+ assert(version.Key.startsWith('folder1/'));
});
});
+
+ it('should handle delimiter for common prefixes', async () => {
+ // Put objects in different "folders"
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: 'folder1/file1',
+ Body: 'body1',
+ }));
+
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: 'folder2/file2',
+ Body: 'body2',
+ }));
+
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: 'file3',
+ Body: 'body3',
+ }));
+
+ // List with delimiter
+ const listResult = await s3.send(new ListObjectVersionsCommand({
+ Bucket: bucket,
+ Delimiter: '/',
+ }));
+
+ assert.strictEqual(listResult.Versions.length, 1); // file3
+ assert.strictEqual(listResult.CommonPrefixes.length, 2); // folder1/, folder2/
+ assert.strictEqual(listResult.Versions[0].Key, 'file3');
+ });
+
+ it('should work with versioning suspended', async () => {
+ // Suspend versioning
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningSuspended,
+ }));
+
+ const key = 'key';
+
+ // Put object (creates null version)
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'body1',
+ }));
+
+ // Put again (overwrites null version)
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'body2',
+ }));
+
+ // List versions
+ const listResult = await s3.send(new ListObjectVersionsCommand({
+ Bucket: bucket,
+ }));
+
+ // Should only have one version (the null version)
+ assert.strictEqual(listResult.Versions.length, 1);
+ assert.strictEqual(listResult.Versions[0].Key, key);
+ assert.strictEqual(listResult.Versions[0].VersionId, 'null');
+ });
});
});
diff --git a/tests/functional/aws-node-sdk/test/versioning/multiObjectDelete.js b/tests/functional/aws-node-sdk/test/versioning/multiObjectDelete.js
index d04e972bf3..25e666719d 100644
--- a/tests/functional/aws-node-sdk/test/versioning/multiObjectDelete.js
+++ b/tests/functional/aws-node-sdk/test/versioning/multiObjectDelete.js
@@ -1,16 +1,17 @@
const assert = require('assert');
-const async = require('async');
+const {
+ CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ DeleteObjectCommand,
+ DeleteObjectsCommand,
+ ListObjectVersionsCommand,
+} = require('@aws-sdk/client-s3');
const withV4 = require('../support/withV4');
const BucketUtility = require('../../lib/utility/bucket-util');
const { removeAllVersions } = require('../../lib/utility/versioning-util');
-const { DeleteObjectsCommand,
- DeleteObjectCommand,
- PutObjectCommand,
- CreateBucketCommand,
- DeleteBucketCommand,
- PutBucketVersioningCommand,
- ListObjectVersionsCommand} = require('@aws-sdk/client-s3');
const bucketName = `multi-object-delete-${Date.now()}`;
const key = 'key';
@@ -20,11 +21,6 @@ const nonExistingId = process.env.AWS_ON_AIR ?
'MhhyTHhmZ4cxSi4Y9SMe5P7UJAz7HLJ9' :
'3939393939393939393936493939393939393939756e6437';
-function checkNoError(err) {
- assert.equal(err, null,
- `Expected success, got error ${JSON.stringify(err)}`);
-}
-
function sortList(list) {
return list.sort((a, b) => {
if (a.Key > b.Key) {
@@ -46,141 +42,136 @@ describe('Multi-Object Versioning Delete Success', function success() {
const s3 = bucketUtil.s3;
let objectsRes;
- beforeEach(done => {
- async.waterfall([
- next => s3.send(new CreateBucketCommand({ Bucket: bucketName }),
- err => next(err)),
- next => s3.send(new PutBucketVersioningCommand({
- Bucket: bucketName,
- VersioningConfiguration: {
- Status: 'Enabled',
- },
- })).then(res => next(null, res)).catch(err => next(err)),
- next => {
- const objects = [];
- for (let i = 1; i < 1001; i++) {
- objects.push(`${key}${i}`);
- }
- async.mapLimit(objects, 20, (key, next) => {
- s3.send(new PutObjectCommand({
- Bucket: bucketName,
- Key: key,
- Body: 'somebody',
- })).then(res => {
- // eslint-disable-next-line no-param-reassign
- res.Key = key;
- return next(null, res);
- }).catch(err => next(err));
- }, (err, results) => {
- if (err) {
- return next(err);
- }
- objectsRes = results;
- return next();
- });
+ beforeEach(async () => {
+ await s3.send(new CreateBucketCommand({ Bucket: bucketName }));
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: {
+ Status: 'Enabled',
},
- ], err => done(err));
- });
+ }));
+
+ const objects = [];
+ for (let i = 1; i < 1001; i++) {
+ objects.push(`${key}${i}`);
+ }
- afterEach(async () => {
- await removeAllVersions({ Bucket: bucketName });
- await s3.send(new DeleteBucketCommand({ Bucket: bucketName }));
+ // Create objects in batches of 20 concurrently
+ const results = [];
+ for (let i = 0; i < objects.length; i += 20) {
+ const batch = objects.slice(i, i + 20);
+ const batchPromises = batch.map(async keyName => {
+ const res = await s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: keyName,
+ Body: 'somebody',
+ }));
+ res.Key = keyName;
+ return res;
+ });
+ const batchResults = await Promise.all(batchPromises);
+ results.push(...batchResults);
+ }
+ objectsRes = results;
});
- it('should batch delete 1000 objects quietly', () => {
+ afterEach(done => {
+ removeAllVersions({ Bucket: bucketName }, err => {
+ if (err) {
+ return done(err);
+ }
+ return s3.send(new DeleteBucketCommand({ Bucket: bucketName }))
+ .then(() => done()).catch(done);
+ });
+ });
+
+ it('should batch delete 1000 objects quietly', async () => {
const objects = objectsRes.slice(0, 1000).map(obj =>
({ Key: obj.Key, VersionId: obj.VersionId }));
- return s3.send(new DeleteObjectsCommand({
+
+ const res = await s3.send(new DeleteObjectsCommand({
Bucket: bucketName,
Delete: {
Objects: objects,
Quiet: true,
},
- })).then(res => {
- assert.strictEqual(res.Deleted, undefined);
- assert.strictEqual(res.Errors, undefined);
- }).catch(err => {
- checkNoError(err);
- });
+ }));
+
+ assert.strictEqual(res.Deleted, undefined);
+ assert.strictEqual(res.Errors, undefined);
});
- it('should batch delete 1000 objects', () => {
+ it('should batch delete 1000 objects', async () => {
const objects = objectsRes.slice(0, 1000).map(obj =>
({ Key: obj.Key, VersionId: obj.VersionId }));
- return s3.send(new DeleteObjectsCommand({
+
+ const res = await s3.send(new DeleteObjectsCommand({
Bucket: bucketName,
Delete: {
Objects: objects,
Quiet: false,
},
- })).then(res => {
- assert.strictEqual(res.Deleted.length, 1000);
- // order of returned objects not sorted
- assert.deepStrictEqual(sortList(res.Deleted),
- sortList(objects));
- assert.strictEqual(res.Errors, undefined);
- }).catch(err => {
- checkNoError(err);
- });
+ }));
+
+ assert.strictEqual(res.Deleted.length, 1000);
+ // order of returned objects not sorted
+ assert.deepStrictEqual(sortList(res.Deleted),
+ sortList(objects));
+ assert.strictEqual(res.Errors, undefined);
});
it('should return NoSuchVersion in errors if one versionId is ' +
- 'invalid', () => {
+ 'invalid', async () => {
const objects = objectsRes.slice(0, 1000).map(obj =>
({ Key: obj.Key, VersionId: obj.VersionId }));
objects[0].VersionId = 'invalid-version-id';
- return s3.send(new DeleteObjectsCommand({
+
+ const res = await s3.send(new DeleteObjectsCommand({
Bucket: bucketName,
Delete: {
Objects: objects,
},
- })).then(res => {
- assert.strictEqual(res.Deleted.length, 999);
- assert.strictEqual(res.Errors.length, 1);
- assert.strictEqual(res.Errors[0].Code, 'NoSuchVersion');
- })
- .catch(err => {
- checkNoError(err);
- });
+ }));
+
+ assert.strictEqual(res.Deleted.length, 999);
+ assert.strictEqual(res.Errors.length, 1);
+ assert.strictEqual(res.Errors[0].Code, 'NoSuchVersion');
});
it('should not send back any error if a versionId does not exist ' +
- 'and should not create a new delete marker', () => {
+ 'and should not create a new delete marker', async () => {
const objects = objectsRes.slice(0, 1000).map(obj =>
({ Key: obj.Key, VersionId: obj.VersionId }));
objects[0].VersionId = nonExistingId;
- return s3.send(new DeleteObjectsCommand({
+
+ const res = await s3.send(new DeleteObjectsCommand({
Bucket: bucketName,
Delete: {
Objects: objects,
},
- })).then(res => {
- assert.strictEqual(res.Deleted.length, 1000);
- assert.strictEqual(res.Errors, undefined);
- const foundVersionId = res.Deleted.find(entry =>
- entry.VersionId === nonExistingId);
- assert(foundVersionId);
- assert.strictEqual(foundVersionId.DeleteMarker, undefined);
- })
- .catch(err => {
- checkNoError(err);
- });
+ }));
+
+ assert.strictEqual(res.Deleted.length, 1000);
+ assert.strictEqual(res.Errors, undefined);
+ const foundVersionId = res.Deleted.find(entry =>
+ entry.VersionId === nonExistingId);
+ assert(foundVersionId);
+ assert.strictEqual(foundVersionId.DeleteMarker, undefined);
});
- it('should not crash when deleting a null versionId that does not exist', () => {
+ it('should not crash when deleting a null versionId that does not exist', async () => {
const objects = [{ Key: objectsRes[0].Key, VersionId: 'null' }];
- return s3.send(new DeleteObjectsCommand({
+
+ const res = await s3.send(new DeleteObjectsCommand({
Bucket: bucketName,
Delete: {
Objects: objects,
},
- })).then(res => {
- assert.deepStrictEqual(res.Deleted, [{ Key: objectsRes[0].Key, VersionId: 'null' }]);
- assert.strictEqual(res.Errors, undefined);
- }).catch(err => {
- checkNoError(err);
- });
+ }));
+
+ assert.deepStrictEqual(res.Deleted, [{ Key: objectsRes[0].Key, VersionId: 'null' }]);
+ assert.strictEqual(res.Errors, undefined);
});
});
});
@@ -191,116 +182,99 @@ describe('Multi-Object Versioning Delete - deleting delete marker',
const bucketUtil = new BucketUtility('default', sigCfg);
const s3 = bucketUtil.s3;
- beforeEach(done => {
- async.waterfall([
- next => s3.send(new CreateBucketCommand({ Bucket: bucketName })).then(() =>
- next()).catch(err => next(err)),
- next => s3.send(new PutBucketVersioningCommand({
- Bucket: bucketName,
- VersioningConfiguration: {
- Status: 'Enabled',
- },
- })).then(() => next()).catch(err => next(err)),
- ], done);
+ beforeEach(async () => {
+ await s3.send(new CreateBucketCommand({ Bucket: bucketName }));
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: {
+ Status: 'Enabled',
+ },
+ }));
});
- afterEach(async () => {
- await removeAllVersions({ Bucket: bucketName });
- await s3.deleteBucket({ Bucket: bucketName });
+
+ afterEach(done => {
+ removeAllVersions({ Bucket: bucketName }, err => {
+ if (err) {
+ return done(err);
+ }
+ return s3.send(new DeleteBucketCommand({ Bucket: bucketName }))
+ .then(() => done()).catch(done);
+ });
});
it('should send back VersionId and DeleteMarkerVersionId both equal ' +
'to deleteVersionId', async () => {
- await new Promise((resolve, reject) => {
- async.waterfall([
- next => s3.send(new PutObjectCommand({ Bucket: bucketName, Key: key })).then(() =>
- next()).catch(err => next(err)),
- next => s3.send(new DeleteObjectCommand({ Bucket: bucketName,
- Key: key })).then(data => {
- const deleteVersionId = data.VersionId;
- next(null, deleteVersionId);
- }).catch(err => next(err)),
- (deleteVersionId, next) => s3.send(new DeleteObjectsCommand({ Bucket:
- bucketName,
- Delete: {
- Objects: [
- {
- Key: key,
- VersionId: deleteVersionId,
- },
- ],
- } })).then(data => {
- assert.strictEqual(data.Deleted[0].DeleteMarker, true);
- assert.strictEqual(data.Deleted[0].VersionId,
- deleteVersionId);
- assert.strictEqual(data.Deleted[0].DeleteMarkerVersionId,
- deleteVersionId);
- next(null, data);
- }).catch(err => next(err)),
- ], err => {
- if (err) {
- reject(err);
- } else {
- resolve();
- }
- });
- });
+ await s3.send(new PutObjectCommand({ Bucket: bucketName, Key: key }));
+
+ const deleteRes = await s3.send(new DeleteObjectCommand({
+ Bucket: bucketName,
+ Key: key
+ }));
+ const deleteVersionId = deleteRes.VersionId;
+
+ const deleteObjectsRes = await s3.send(new DeleteObjectsCommand({
+ Bucket: bucketName,
+ Delete: {
+ Objects: [
+ {
+ Key: key,
+ VersionId: deleteVersionId,
+ },
+ ],
+ }
+ }));
+
+ assert.strictEqual(deleteObjectsRes.Deleted[0].DeleteMarker, true);
+ assert.strictEqual(deleteObjectsRes.Deleted[0].VersionId, deleteVersionId);
+ assert.strictEqual(deleteObjectsRes.Deleted[0].DeleteMarkerVersionId, deleteVersionId);
});
it('should send back a DeleteMarkerVersionId matching the versionId ' +
'stored for the object if trying to delete an object that does not exist',
- done => {
- s3.send(new DeleteObjectsCommand({ Bucket: bucketName,
+ async () => {
+ const deleteRes = await s3.send(new DeleteObjectsCommand({
+ Bucket: bucketName,
Delete: {
Objects: [
{
Key: key,
},
],
- } })).then(data => {
- const versionIdFromDeleteObjects =
- data.Deleted[0].DeleteMarkerVersionId;
- assert.strictEqual(data.Deleted[0].DeleteMarker, true);
- return s3.send(new ListObjectVersionsCommand({ Bucket: bucketName })).then(data => {
- const versionIdFromListObjectVersions =
- data.DeleteMarkers[0].VersionId;
- assert.strictEqual(versionIdFromDeleteObjects,
- versionIdFromListObjectVersions);
- return done();
- }).catch(err => done(err));
- }).catch(err => done(err));
+ }
+ }));
+
+ const versionIdFromDeleteObjects = deleteRes.Deleted[0].DeleteMarkerVersionId;
+ assert.strictEqual(deleteRes.Deleted[0].DeleteMarker, true);
+
+ const listRes = await s3.send(new ListObjectVersionsCommand({ Bucket: bucketName }));
+ const versionIdFromListObjectVersions = listRes.DeleteMarkers[0].VersionId;
+ assert.strictEqual(versionIdFromDeleteObjects, versionIdFromListObjectVersions);
});
it('should send back a DeleteMarkerVersionId matching the versionId ' +
'stored for the object if object exists but no version was specified',
- done => {
- async.waterfall([
- next => s3.putObject({ Bucket: bucketName, Key: key }).then(data => {
- const versionId = data.VersionId;
- next(null, versionId);
- }).catch(err => next(err)),
- (versionId, next) => s3.send(new DeleteObjectsCommand({ Bucket: bucketName,
- Delete: {
- Objects: [
- {
- Key: key,
- },
- ],
- } })).then(data => {
- assert.strictEqual(data.Deleted[0].DeleteMarker, true);
- const deleteVersionId = data.Deleted[0].
- DeleteMarkerVersionId;
- assert.notEqual(deleteVersionId, versionId);
- return next(null, deleteVersionId, versionId);
- }).catch(err => next(err)),
- (deleteVersionId, versionId, next) => s3.send(new ListObjectVersionsCommand(
- { Bucket: bucketName })).then(data => {
- assert.strictEqual(deleteVersionId,
- data.DeleteMarkers[0].VersionId);
- assert.strictEqual(versionId,
- data.Versions[0].VersionId);
- return next();
- }).catch(err => next(err)),
- ], err => done(err));
+ async () => {
+ const putRes = await s3.send(new PutObjectCommand({ Bucket: bucketName, Key: key }));
+ const versionId = putRes.VersionId;
+
+ const deleteRes = await s3.send(new DeleteObjectsCommand({
+ Bucket: bucketName,
+ Delete: {
+ Objects: [
+ {
+ Key: key,
+ },
+ ],
+ }
+ }));
+
+ assert.strictEqual(deleteRes.Deleted[0].DeleteMarker, true);
+ const deleteVersionId = deleteRes.Deleted[0].DeleteMarkerVersionId;
+ assert.notEqual(deleteVersionId, versionId);
+
+ const listRes = await s3.send(new ListObjectVersionsCommand({ Bucket: bucketName }));
+ assert.strictEqual(deleteVersionId, listRes.DeleteMarkers[0].VersionId);
+ assert.strictEqual(versionId, listRes.Versions[0].VersionId);
});
});
});
diff --git a/tests/functional/aws-node-sdk/test/versioning/objectACL.js b/tests/functional/aws-node-sdk/test/versioning/objectACL.js
index 7976d852e1..b03e5a3ccf 100644
--- a/tests/functional/aws-node-sdk/test/versioning/objectACL.js
+++ b/tests/functional/aws-node-sdk/test/versioning/objectACL.js
@@ -1,5 +1,14 @@
const assert = require('assert');
-const async = require('async');
+const {
+ CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ DeleteObjectCommand,
+ GetObjectAclCommand,
+ PutObjectAclCommand,
+ HeadObjectCommand,
+} = require('@aws-sdk/client-s3');
const withV4 = require('../support/withV4');
const BucketUtility = require('../../lib/utility/bucket-util');
@@ -32,32 +41,40 @@ class _Utils {
// need a wrapper because sdk apparently does not include version id in
// exposed data object for put/get acl methods
- _wrapDataObject(method, params, callback) {
- let request;
- async.waterfall([
- next => {
- request = this.s3[method](params, next);
- },
- (data, next) => {
- const responseHeaders = request.response
- .httpResponse.headers;
- const dataObj = Object.assign({
- VersionId: responseHeaders['x-amz-version-id'],
- }, data);
- return next(null, dataObj);
- },
- ], callback);
+ async _wrapDataObject(method, params) {
+ const Command = method === 'getObjectAcl' ? GetObjectAclCommand : PutObjectAclCommand;
+ const data = await this.s3.send(new Command(params));
+
+ let versionId = params.VersionId;
+
+ if (!versionId) {
+ // For non-version-specific ACL operations, we need to determine the latest version
+ try {
+ const headResult = await this.s3.send(new HeadObjectCommand({
+ Bucket: params.Bucket,
+ Key: params.Key
+ }));
+ versionId = headResult.VersionId;
+ } catch {
+ versionId = undefined; // Fallback
+ }
+ }
+
+ const dataObj = Object.assign({
+ VersionId: versionId,
+ }, data);
+ return dataObj;
}
- getObjectAcl(params, callback) {
- this._wrapDataObject('getObjectAcl', params, callback);
+ async getObjectAcl(params) {
+ return this._wrapDataObject('getObjectAcl', params);
}
- putObjectAcl(params, callback) {
- this._wrapDataObject('putObjectAcl', params, callback);
+ async putObjectAcl(params) {
+ return this._wrapDataObject('putObjectAcl', params);
}
- putAndGetAcl(cannedAcl, versionId, expected, cb) {
+ async putAndGetAcl(cannedAcl, versionId, expected) {
const params = {
Bucket: bucket,
Key: key,
@@ -66,35 +83,48 @@ class _Utils {
if (versionId) {
params.VersionId = versionId;
}
- this.putObjectAcl(params, (err, data) => {
+
+ try {
+ const data = await this.putObjectAcl(params);
+ if (expected.error) {
+ // Should not reach here if error was expected
+ assert.fail('Expected error but operation succeeded');
+ }
+ _Utils.assertNoError(null,
+ `putting object acl with version id: ${versionId}`);
+ assert.strictEqual(data.VersionId, expected.versionId,
+ `expected version id '${expected.versionId}' in ` +
+ `putacl res headers, got '${data.VersionId}' instead`);
+ } catch (err) {
if (expected.error) {
- assert.strictEqual(expected.error.code, err.code);
- assert.strictEqual(expected.error.statusCode,
- err.statusCode);
+ assert.strictEqual(expected.error.code, err.Code);
+ assert.strictEqual(expected.error.statusCode, err.$metadata.httpStatusCode);
} else {
- _Utils.assertNoError(err,
- `putting object acl with version id: ${versionId}`);
- assert.strictEqual(data.VersionId, expected.versionId,
- `expected version id '${expected.versionId}' in ` +
- `putacl res headers, got '${data.VersionId}' instead`);
+ throw err;
}
- delete params.ACL;
- this.getObjectAcl(params, (err, data) => {
- if (expected.error) {
- assert.strictEqual(expected.error.code, err.code);
- assert.strictEqual(expected.error.statusCode,
- err.statusCode);
- } else {
- _Utils.assertNoError(err,
- `getting object acl with version id: ${versionId}`);
- assert.strictEqual(data.VersionId, expected.versionId,
- `expected version id '${expected.versionId}' in ` +
- `getacl res headers, got '${data.VersionId}'`);
- assert.strictEqual(data.Grants.length, 2);
- }
- cb();
- });
- });
+ }
+
+ delete params.ACL;
+
+ try {
+ const data = await this.getObjectAcl(params);
+ if (expected.error) {
+ assert.fail('Expected error but operation succeeded');
+ }
+ _Utils.assertNoError(null,
+ `getting object acl with version id: ${versionId}`);
+ assert.strictEqual(data.VersionId, expected.versionId,
+ `expected version id '${expected.versionId}' in ` +
+ `getacl res headers, got '${data.VersionId}'`);
+ assert.strictEqual(data.Grants.length, 2);
+ } catch (err) {
+ if (expected.error) {
+ assert.strictEqual(expected.error.code, err.Code);
+ assert.strictEqual(expected.error.statusCode, err.$metadata.httpStatusCode);
+ } else {
+ throw err;
+ }
+ }
}
}
@@ -102,109 +132,109 @@ function _testBehaviorVersioningEnabledOrSuspended(utils, versionIds) {
const s3 = utils.s3;
it('should return 405 MethodNotAllowed putting acl without ' +
- 'version id if latest version is a delete marker', done => {
+ 'version id if latest version is a delete marker', async () => {
const aclParams = {
Bucket: bucket,
Key: key,
ACL: 'public-read-write',
};
- s3.deleteObject({ Bucket: bucket, Key: key }, (err, data) => {
- assert.strictEqual(err, null,
- `Unexpected err deleting object: ${err}`);
- assert.strictEqual(data.DeleteMarker, true);
- assert(data.VersionId);
- utils.putObjectAcl(aclParams, err => {
- assert(err);
- assert.strictEqual(err.code, 'MethodNotAllowed');
- assert.strictEqual(err.statusCode, 405);
- done();
- });
- });
+ const data = await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
+ assert.strictEqual(data.DeleteMarker, true);
+ assert(data.VersionId);
+
+ try {
+ await utils.putObjectAcl(aclParams);
+ assert.fail('Expected error but operation succeeded');
+ } catch (err) {
+ assert(err);
+ assert.strictEqual(err.Code, 'MethodNotAllowed');
+ assert.strictEqual(err.$metadata.httpStatusCode, 405);
+ }
});
it('should return 405 MethodNotAllowed putting acl with ' +
- 'version id if version specified is a delete marker', done => {
+ 'version id if version specified is a delete marker', async () => {
const aclParams = {
Bucket: bucket,
Key: key,
ACL: 'public-read-write',
};
- s3.deleteObject({ Bucket: bucket, Key: key }, (err, data) => {
- assert.strictEqual(err, null,
- `Unexpected err deleting object: ${err}`);
- assert.strictEqual(data.DeleteMarker, true);
- assert(data.VersionId);
- aclParams.VersionId = data.VersionId;
- utils.putObjectAcl(aclParams, err => {
- assert(err);
- assert.strictEqual(err.code, 'MethodNotAllowed');
- assert.strictEqual(err.statusCode, 405);
- done();
- });
- });
+ const data = await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
+ assert.strictEqual(data.DeleteMarker, true);
+ assert(data.VersionId);
+ aclParams.VersionId = data.VersionId;
+
+ try {
+ await utils.putObjectAcl(aclParams);
+ assert.fail('Expected error but operation succeeded');
+ } catch (err) {
+ assert(err);
+ assert.strictEqual(err.Code, 'MethodNotAllowed');
+ assert.strictEqual(err.$metadata.httpStatusCode, 405);
+ }
});
it('should return 404 NoSuchKey getting acl without ' +
- 'version id if latest version is a delete marker', done => {
+ 'version id if latest version is a delete marker', async () => {
const aclParams = {
Bucket: bucket,
Key: key,
};
- s3.deleteObject({ Bucket: bucket, Key: key }, (err, data) => {
- assert.strictEqual(err, null,
- `Unexpected err deleting object: ${err}`);
- assert.strictEqual(data.DeleteMarker, true);
- assert(data.VersionId);
- utils.getObjectAcl(aclParams, err => {
- assert(err);
- assert.strictEqual(err.code, 'NoSuchKey');
- assert.strictEqual(err.statusCode, 404);
- done();
- });
- });
+ const data = await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
+ assert.strictEqual(data.DeleteMarker, true);
+ assert(data.VersionId);
+
+ try {
+ await utils.getObjectAcl(aclParams);
+ assert.fail('Expected error but operation succeeded');
+ } catch (err) {
+ assert(err);
+ assert.strictEqual(err.Code, 'NoSuchKey');
+ assert.strictEqual(err.$metadata.httpStatusCode, 404);
+ }
});
it('should return 405 MethodNotAllowed getting acl with ' +
- 'version id if version specified is a delete marker', done => {
+ 'version id if version specified is a delete marker', async () => {
const latestVersion = versionIds[versionIds.length - 1];
const aclParams = {
Bucket: bucket,
Key: key,
VersionId: latestVersion,
};
- s3.deleteObject({ Bucket: bucket, Key: key }, (err, data) => {
- assert.strictEqual(err, null,
- `Unexpected err deleting object: ${err}`);
- assert.strictEqual(data.DeleteMarker, true);
- assert(data.VersionId);
- aclParams.VersionId = data.VersionId;
- utils.getObjectAcl(aclParams, err => {
- assert(err);
- assert.strictEqual(err.code, 'MethodNotAllowed');
- assert.strictEqual(err.statusCode, 405);
- done();
- });
- });
+ const data = await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
+ assert.strictEqual(data.DeleteMarker, true);
+ assert(data.VersionId);
+ aclParams.VersionId = data.VersionId;
+
+ try {
+ await utils.getObjectAcl(aclParams);
+ assert.fail('Expected error but operation succeeded');
+ } catch (err) {
+ assert(err);
+ assert.strictEqual(err.Code, 'MethodNotAllowed');
+ assert.strictEqual(err.$metadata.httpStatusCode, 405);
+ }
});
it('non-version specific put and get ACL should target latest ' +
- 'version AND return version ID in response headers', done => {
+ 'version AND return version ID in response headers', async () => {
const latestVersion = versionIds[versionIds.length - 1];
const expectedRes = { versionId: latestVersion };
- utils.putAndGetAcl('public-read', undefined, expectedRes, done);
+ await utils.putAndGetAcl('public-read', undefined, expectedRes);
});
it('version specific put and get ACL should return version ID ' +
- 'in response headers', done => {
+ 'in response headers', async () => {
const firstVersion = versionIds[0];
const expectedRes = { versionId: firstVersion };
- utils.putAndGetAcl('public-read', firstVersion, expectedRes, done);
+ await utils.putAndGetAcl('public-read', firstVersion, expectedRes);
});
it('version specific put and get ACL (version id = "null") ' +
- 'should return version ID ("null") in response headers', done => {
+ 'should return version ID ("null") in response headers', async () => {
const expectedRes = { versionId: 'null' };
- utils.putAndGetAcl('public-read', 'null', expectedRes, done);
+ await utils.putAndGetAcl('public-read', 'null', expectedRes);
});
}
@@ -214,9 +244,9 @@ describe('versioned put and get object acl ::', () => {
const s3 = bucketUtil.s3;
const utils = new _Utils(s3);
- beforeEach(done => {
+ beforeEach(async () => {
bucket = `versioning-bucket-acl-${Date.now()}`;
- s3.createBucket({ Bucket: bucket }, done);
+ await s3.send(new CreateBucketCommand({ Bucket: bucket }));
});
afterEach(done => {
@@ -224,37 +254,38 @@ describe('versioned put and get object acl ::', () => {
if (err) {
return done(err);
}
- return s3.deleteBucket({ Bucket: bucket }, done);
+ return s3.send(new DeleteBucketCommand({ Bucket: bucket }))
+ .then(() => done()).catch(done);
});
});
describe('in bucket w/o versioning cfg :: ', () => {
- beforeEach(done => {
- s3.putObject({ Bucket: bucket, Key: key }, done);
+ beforeEach(async () => {
+ await s3.send(new PutObjectCommand({ Bucket: bucket, Key: key }));
});
it('should not return version id for non-version specific ' +
- 'put and get ACL', done => {
+ 'put and get ACL', async () => {
const expectedRes = { versionId: undefined };
- utils.putAndGetAcl('public-read', undefined, expectedRes, done);
+ await utils.putAndGetAcl('public-read', undefined, expectedRes);
});
it('should not return version id for version specific ' +
- 'put and get ACL (version id = "null")', done => {
- const expectedRes = { versionId: undefined };
- utils.putAndGetAcl('public-read', 'null', expectedRes, done);
+ 'put and get ACL (version id = "null")', async () => {
+ const expectedRes = { versionId: 'null' };
+ await utils.putAndGetAcl('public-read', 'null', expectedRes);
});
it('should return NoSuchVersion if attempting to put or get acl ' +
- 'for non-existing version', done => {
+ 'for non-existing version', async () => {
const error = { code: 'NoSuchVersion', statusCode: 404 };
- utils.putAndGetAcl('private', nonExistingId, { error }, done);
+ await utils.putAndGetAcl('private', nonExistingId, { error });
});
it('should return InvalidArgument if attempting to put/get acl ' +
- 'for invalid hex string', done => {
+ 'for invalid hex string', async () => {
const error = { code: 'InvalidArgument', statusCode: 400 };
- utils.putAndGetAcl('private', invalidId, { error }, done);
+ await utils.putAndGetAcl('private', invalidId, { error });
});
});
@@ -262,41 +293,36 @@ describe('versioned put and get object acl ::', () => {
() => {
const versionIds = [];
- beforeEach(done => {
+ beforeEach(async () => {
const params = { Bucket: bucket, Key: key };
- async.waterfall([
- callback => s3.putObject(params, err => callback(err)),
- callback => s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningEnabled,
- }, err => callback(err)),
- ], done);
+ await s3.send(new PutObjectCommand(params));
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningEnabled,
+ }));
});
- afterEach(done => {
+ afterEach(() => {
// cleanup versionIds just in case
versionIds.length = 0;
- done();
});
describe('before putting new versions :: ', () => {
it('non-version specific put and get ACL should now ' +
- 'return version ID ("null") in response headers', done => {
+ 'return version ID ("null") in response headers', async () => {
const expectedRes = { versionId: 'null' };
- utils.putAndGetAcl('public-read', undefined, expectedRes,
- done);
+ await utils.putAndGetAcl('public-read', undefined, expectedRes);
});
});
describe('after putting new versions :: ', () => {
- beforeEach(done => {
+ beforeEach(async () => {
const params = { Bucket: bucket, Key: key };
- async.timesSeries(counter, (i, next) =>
- s3.putObject(params, (err, data) => {
- _Utils.assertNoError(err, `putting version #${i}`);
- versionIds.push(data.VersionId);
- next(err);
- }), done);
+ for (let i = 0; i < counter; i++) {
+ const data = await s3.send(new PutObjectCommand(params));
+ _Utils.assertNoError(null, `putting version #${i}`);
+ versionIds.push(data.VersionId);
+ }
});
_testBehaviorVersioningEnabledOrSuspended(utils, versionIds);
@@ -306,30 +332,22 @@ describe('versioned put and get object acl ::', () => {
describe('on a version-enabled bucket - version non-specified :: ',
() => {
let versionId;
- beforeEach(done => {
+ beforeEach(async () => {
const params = { Bucket: bucket, Key: key };
- async.waterfall([
- callback => s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningEnabled,
- }, err => callback(err)),
- callback => s3.putObject(params, (err, data) => {
- if (err) {
- return callback(err);
- }
- versionId = data.VersionId;
- return callback();
- }),
- ], done);
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningEnabled,
+ }));
+ const data = await s3.send(new PutObjectCommand(params));
+ versionId = data.VersionId;
});
it('should not create version putting ACL on a' +
'version-enabled bucket where no version id is specified',
- done => {
+ async () => {
const params = { Bucket: bucket, Key: key, ACL: 'public-read' };
- utils.putObjectAcl(params, () => {
- checkOneVersion(s3, bucket, versionId, done);
- });
+ await utils.putObjectAcl(params);
+ await checkOneVersion(s3, bucket, versionId);
});
});
@@ -337,52 +355,46 @@ describe('versioned put and get object acl ::', () => {
() => {
const versionIds = [];
- beforeEach(done => {
+ beforeEach(async () => {
const params = { Bucket: bucket, Key: key };
- async.waterfall([
- callback => s3.putObject(params, err => callback(err)),
- callback => s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningSuspended,
- }, err => callback(err)),
- ], done);
+ await s3.send(new PutObjectCommand(params));
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningSuspended,
+ }));
});
- afterEach(done => {
+ afterEach(() => {
// cleanup versionIds just in case
versionIds.length = 0;
- done();
});
describe('before putting new versions :: ', () => {
it('non-version specific put and get ACL should still ' +
- 'return version ID ("null") in response headers', done => {
+ 'return version ID ("null") in response headers', async () => {
const expectedRes = { versionId: 'null' };
- utils.putAndGetAcl('public-read', undefined, expectedRes,
- done);
+ await utils.putAndGetAcl('public-read', undefined, expectedRes);
});
});
describe('after putting new versions :: ', () => {
- beforeEach(done => {
+ beforeEach(async () => {
const params = { Bucket: bucket, Key: key };
- async.waterfall([
- callback => s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningEnabled,
- }, err => callback(err)),
- callback => async.timesSeries(counter, (i, next) =>
- s3.putObject(params, (err, data) => {
- _Utils.assertNoError(err,
- `putting version #${i}`);
- versionIds.push(data.VersionId);
- next(err);
- }), err => callback(err)),
- callback => s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningSuspended,
- }, err => callback(err)),
- ], done);
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningEnabled,
+ }));
+
+ for (let i = 0; i < counter; i++) {
+ const data = await s3.send(new PutObjectCommand(params));
+ _Utils.assertNoError(null, `putting version #${i}`);
+ versionIds.push(data.VersionId);
+ }
+
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningSuspended,
+ }));
});
_testBehaviorVersioningEnabledOrSuspended(utils, versionIds);
diff --git a/tests/functional/aws-node-sdk/test/versioning/objectCopy.js b/tests/functional/aws-node-sdk/test/versioning/objectCopy.js
index 73a94a32fd..7bb92f01c2 100644
--- a/tests/functional/aws-node-sdk/test/versioning/objectCopy.js
+++ b/tests/functional/aws-node-sdk/test/versioning/objectCopy.js
@@ -1,17 +1,34 @@
const assert = require('assert');
-const async = require('async');
+
+const {
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ CopyObjectCommand,
+ GetObjectCommand,
+ HeadObjectCommand,
+ GetObjectTaggingCommand,
+ GetObjectAclCommand,
+ PutObjectAclCommand,
+ DeleteObjectCommand,
+} = require('@aws-sdk/client-s3');
+
+const { promisify } = require('util');
const withV4 = require('../support/withV4');
const BucketUtility = require('../../lib/utility/bucket-util');
const { removeAllVersions } = require('../../lib/utility/versioning-util');
const customS3Request = require('../../lib/utility/customS3Request');
+const removeAllVersionsPromise = promisify(removeAllVersions);
+
+
const { taggingTests } = require('../../lib/utility/tagging');
const constants = require('../../../../../constants');
-const sourceBucketName = 'supersourcebucket8102016';
+const sourceBucketName = 'supersourcebucket81020165';
const sourceObjName = 'supersourceobject';
-const destBucketName = 'destinationbucket8102016';
+const destBucketName = 'destinationbucket81020165';
const destObjName = 'copycatobject';
const originalMetadata = {
@@ -53,20 +70,19 @@ function checkNoError(err) {
function checkError(err, code) {
assert.notEqual(err, null, 'Expected failure but got success');
- assert.strictEqual(err.code, code);
+ assert.strictEqual(err.Code, code);
}
function dateFromNow(diff) {
const d = new Date();
d.setHours(d.getHours() + diff);
- return d.toISOString();
+ return d;
}
function dateConvert(d) {
- return (new Date(d)).toISOString();
+ return new Date(d);
}
-
describe('Object Version Copy', () => {
withV4(sigCfg => {
const bucketUtil = new BucketUtility('default', sigCfg);
@@ -78,22 +94,19 @@ describe('Object Version Copy', () => {
let copySource;
let copySourceVersionId;
- function emptyAndDeleteBucket(bucketName, callback) {
- return removeAllVersions({ Bucket: bucketName }, err => {
- if (err) {
- callback(err);
- }
- return s3.deleteBucket({ Bucket: bucketName }, callback);
- });
+ async function emptyAndDeleteBucket(bucketName) {
+ await removeAllVersionsPromise({ Bucket: bucketName });
+ await s3.send(new DeleteBucketCommand({ Bucket: bucketName }));
}
- beforeEach(() => bucketUtil.createOne(sourceBucketName)
- .then(() => bucketUtil.createOne(destBucketName))
- .then(() => s3.putBucketVersioning({
+ beforeEach(async () => {
+ await bucketUtil.createOne(sourceBucketName);
+ await bucketUtil.createOne(destBucketName);
+ await s3.send(new PutBucketVersioningCommand({
Bucket: sourceBucketName,
VersioningConfiguration: { Status: 'Enabled' },
- }).promise())
- .then(() => s3.putObject({
+ }));
+ const putRes = await s3.send(new PutObjectCommand({
Bucket: sourceBucketName,
Key: sourceObjName,
Body: content,
@@ -103,1057 +116,779 @@ describe('Object Version Copy', () => {
ContentEncoding: originalContentEncoding,
Expires: originalExpires,
Tagging: originalTagging,
- }).promise()).then(res => {
- etag = res.ETag;
- versionId = res.VersionId;
- copySource = `${sourceBucketName}/${sourceObjName}` +
- `?versionId=${versionId}`;
- etagTrim = etag.substring(1, etag.length - 1);
- copySourceVersionId = res.VersionId;
- return s3.headObject({
- Bucket: sourceBucketName,
- Key: sourceObjName,
- }).promise();
- }).then(res => {
- lastModified = res.LastModified;
- }).then(() => s3.putObject({ Bucket: sourceBucketName,
+ }));
+ etag = putRes.ETag;
+ versionId = putRes.VersionId;
+ copySource = `${sourceBucketName}/${sourceObjName}?versionId=${versionId}`;
+ etagTrim = etag.substring(1, etag.length - 1);
+ copySourceVersionId = putRes.VersionId;
+ const headRes = await s3.send(new HeadObjectCommand({
+ Bucket: sourceBucketName,
+ Key: sourceObjName,
+ }));
+ lastModified = headRes.LastModified;
+ await s3.send(new PutObjectCommand({
+ Bucket: sourceBucketName,
Key: sourceObjName,
- Body: secondContent }).promise())
- );
+ Body: secondContent,
+ }));
+ });
- afterEach(done => async.parallel([
- next => emptyAndDeleteBucket(sourceBucketName, next),
- next => emptyAndDeleteBucket(destBucketName, next),
- ], done));
+ afterEach(async () => {
+ await Promise.all([
+ emptyAndDeleteBucket(sourceBucketName),
+ emptyAndDeleteBucket(destBucketName),
+ ]);
+ });
- function requestCopy(fields, cb) {
- s3.copyObject(Object.assign({
+ async function requestCopy(fields) {
+ return s3.send(new CopyObjectCommand({
Bucket: destBucketName,
Key: destObjName,
CopySource: copySource,
- }, fields), cb);
+ ...fields,
+ }));
}
- function successCopyCheck(error, response, copyVersionMetadata,
- destBucketName, destObjName, done) {
+ async function successCopyCheck(error, response, copyVersionMetadata, destBucketName, destObjName) {
checkNoError(error);
- assert.strictEqual(response.CopySourceVersionId,
- copySourceVersionId);
- assert.notStrictEqual(response.CopySourceVersionId,
- response.VersionId);
+ assert.strictEqual(response.CopySourceVersionId, copySourceVersionId);
+ assert.notStrictEqual(response.CopySourceVersionId, response.VersionId);
const destinationVersionId = response.VersionId;
- assert.strictEqual(response.ETag, etag);
- const copyLastModified = new Date(response.LastModified)
- .toGMTString();
- s3.getObject({ Bucket: destBucketName,
- Key: destObjName }, (err, res) => {
- checkNoError(err);
- assert.strictEqual(res.VersionId, destinationVersionId);
- assert.strictEqual(res.Body.toString(), content);
- assert.deepStrictEqual(res.Metadata, copyVersionMetadata);
- assert.strictEqual(res.LastModified.toGMTString(),
- copyLastModified);
- done();
- });
+ assert.strictEqual(response.CopyObjectResult.ETag, etag);
+ const copyLastModified = new Date(response.CopyObjectResult.LastModified).toGMTString();
+ const res = await s3.send(new GetObjectCommand({ Bucket: destBucketName,
+ Key: destObjName }));
+ assert.strictEqual(res.VersionId, destinationVersionId);
+ const responseBody = await res.Body.transformToString();
+ assert.strictEqual(responseBody, content);
+ assert.deepStrictEqual(res.Metadata, copyVersionMetadata);
+ assert.strictEqual(res.LastModified.toGMTString(), copyLastModified);
}
- function checkSuccessTagging(key, value, cb) {
- s3.getObjectTagging({ Bucket: destBucketName, Key: destObjName },
- (err, data) => {
- checkNoError(err);
- assert.strictEqual(data.TagSet[0].Key, key);
- assert.strictEqual(data.TagSet[0].Value, value);
- cb();
- });
+ async function checkSuccessTagging(key, value) {
+ const data = await s3.send(new GetObjectTaggingCommand({ Bucket: destBucketName, Key: destObjName }));
+ assert.strictEqual(data.TagSet[0].Key, key);
+ assert.strictEqual(data.TagSet[0].Value, value);
}
- it('should copy an object from a source bucket to a different ' +
- 'destination bucket and copy the tag set if no tagging directive' +
- 'header provided', done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
- CopySource: copySource },
- err => {
- checkNoError(err);
- checkSuccessTagging(originalTagKey, originalTagValue, done);
- });
+ it('should copy an object from a source bucket to a different '+
+ 'destination bucket and copy the tag set if no tagging directive '+
+ 'header provided', async () => {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
+ CopySource: copySource }));
+ await checkSuccessTagging(originalTagKey, originalTagValue);
});
it('should copy an object from a source bucket to a different ' +
'destination bucket and copy the tag set if COPY tagging ' +
- 'directive header provided', done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
+ 'directive header provided', async () => {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
CopySource: copySource,
- TaggingDirective: 'COPY' },
- err => {
- checkNoError(err);
- checkSuccessTagging(originalTagKey, originalTagValue, done);
- });
+ TaggingDirective: 'COPY' }));
+ await checkSuccessTagging(originalTagKey, originalTagValue);
});
- it('should copy an object from a source to the same destination ' +
- 'updating tag if REPLACE tagging directive header provided',
- done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
+ it('should copy an object from a source to the same destination '+
+ 'updating tag if REPLACE tagging directive header provided', async () => {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
CopySource: copySource,
- TaggingDirective: 'REPLACE', Tagging: newTagging },
- err => {
- checkNoError(err);
- checkSuccessTagging(newTagKey, newTagValue, done);
- });
+ TaggingDirective: 'REPLACE', Tagging: newTagging }));
+ await checkSuccessTagging(newTagKey, newTagValue);
});
describe('Copy object with versioning updating tag set', () => {
taggingTests.forEach(taggingTest => {
- it(taggingTest.it, done => {
+ it(taggingTest.it, async () => {
const key = encodeURIComponent(taggingTest.tag.key);
const value = encodeURIComponent(taggingTest.tag.value);
const tagging = `${key}=${value}`;
- const params = { Bucket: destBucketName, Key: destObjName,
- CopySource: copySource,
- TaggingDirective: 'REPLACE', Tagging: tagging };
- s3.copyObject(params, err => {
+ const params = { Bucket: destBucketName, Key: destObjName, CopySource: copySource,
+ TaggingDirective: 'REPLACE',
+ Tagging: tagging };
+ try {
+ await s3.send(new CopyObjectCommand(params));
+ await checkSuccessTagging(taggingTest.tag.key, taggingTest.tag.value);
+ } catch (err) {
if (taggingTest.error) {
checkError(err, taggingTest.error);
- return done();
+ return;
}
- assert.equal(err, null, 'Expected success, ' +
- `got error ${JSON.stringify(err)}`);
- return checkSuccessTagging(taggingTest.tag.key,
- taggingTest.tag.value, done);
- });
+ checkNoError(err);
+ }
});
});
});
- it('should return InvalidArgument for a request with versionId query',
- done => {
- const params = { Bucket: destBucketName, Key: destObjName,
- CopySource: copySource };
+ it('should return InvalidArgument for a request with versionId query', async () => {
+ const params = { Bucket: destBucketName, Key: destObjName, CopySource: copySource };
const query = { versionId: 'testVersionId' };
- customS3Request(s3.copyObject, params, { query }, err => {
- assert(err, 'Expected error but did not find one');
- assert.strictEqual(err.code, 'InvalidArgument');
- assert.strictEqual(err.statusCode, 400);
- done();
- });
- });
-
- it('should return InvalidArgument for a request with empty string ' +
- 'versionId query', done => {
- const params = { Bucket: destBucketName, Key: destObjName,
- CopySource: copySource };
+ try {
+ await customS3Request(CopyObjectCommand, params, { query });
+ assert.fail('Expected error but did not find one');
+ } catch (err) {
+ assert.strictEqual(err.name, 'InvalidArgument');
+ assert.strictEqual(err.$metadata.httpStatusCode, 400);
+ }
+ });
+
+ it('should return InvalidArgument for a request with empty string '+
+ 'versionId query', async () => {
+ const params = { Bucket: destBucketName, Key: destObjName, CopySource: copySource };
const query = { versionId: '' };
- customS3Request(s3.copyObject, params, { query }, err => {
- assert(err, 'Expected error but did not find one');
- assert.strictEqual(err.code, 'InvalidArgument');
- assert.strictEqual(err.statusCode, 400);
- done();
- });
- });
-
- it('should copy a version from a source bucket to a different ' +
- 'destination bucket and copy the metadata if no metadata directve' +
- 'header provided', done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
- CopySource: copySource },
- (err, res) =>
- successCopyCheck(err, res, originalMetadata,
- destBucketName, destObjName, done)
- );
+ try {
+ await customS3Request(CopyObjectCommand, params, { query });
+ assert.fail('Expected error but did not find one');
+ } catch (err) {
+ assert.strictEqual(err.name, 'InvalidArgument');
+ assert.strictEqual(err.$metadata.httpStatusCode, 400);
+ }
+ });
+
+ it('should copy a version from a source bucket to a different' +
+ 'destination bucket and copy the metadata if no metadata directive' +
+ 'header provided', async () => {
+ const res = await s3.send(new CopyObjectCommand({ Bucket: destBucketName,
+ Key: destObjName,
+ CopySource: copySource }));
+ await successCopyCheck(null, res, originalMetadata, destBucketName, destObjName);
});
it('should also copy additional headers (CacheControl, ' +
- 'ContentDisposition, ContentEncoding, Expires) when copying an ' +
- 'object from a source bucket to a different destination bucket',
- done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
- CopySource: copySource },
- err => {
- checkNoError(err);
- s3.getObject({ Bucket: destBucketName, Key: destObjName },
- (err, res) => {
- if (err) {
- done(err);
- }
- assert.strictEqual(res.CacheControl,
- originalCacheControl);
- assert.strictEqual(res.ContentDisposition,
- originalContentDisposition);
- // Should remove V4 streaming value 'aws-chunked'
- // to be compatible with AWS behavior
- assert.strictEqual(res.ContentEncoding,
- 'base64,'
- );
- assert.strictEqual(res.Expires.toGMTString(),
- originalExpires.toGMTString());
- done();
- });
- });
- });
+ 'ContentDisposition, ContentEncoding, Expires) when copying an ' +
+ 'object from a source bucket to a different destination bucket', async () => {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName,
+ Key: destObjName,
+ CopySource: copySource }));
+ const res = await s3.send(new GetObjectCommand({ Bucket: destBucketName, Key: destObjName }));
+ assert.strictEqual(res.CacheControl, originalCacheControl);
+ assert.strictEqual(res.ContentDisposition, originalContentDisposition);
+ assert.strictEqual(res.ContentEncoding, 'base64,');
+ assert.strictEqual(res.Expires.toGMTString(), originalExpires.toGMTString());
+ });
- it('should copy an object from a source bucket to a different ' +
- 'key in the same bucket',
- done => {
- s3.copyObject({ Bucket: sourceBucketName, Key: destObjName,
- CopySource: copySource },
- (err, res) =>
- successCopyCheck(err, res, originalMetadata,
- sourceBucketName, destObjName, done)
- );
- });
+ it('should copy an object from a source bucket to a different '+
+ 'key in the same bucket', async () => {
+ const res = await s3.send(new CopyObjectCommand({ Bucket: sourceBucketName,
+ Key: destObjName,
+ CopySource: copySource }));
+ await successCopyCheck(null, res, originalMetadata,
+ sourceBucketName, destObjName);
+ });
it('should copy an object from a source to the same destination ' +
- '(update metadata)', done => {
- s3.copyObject({ Bucket: sourceBucketName, Key: sourceObjName,
+ '(update metadata)', async () => {
+ const res = await s3.send(new CopyObjectCommand({ Bucket: sourceBucketName, Key: sourceObjName,
CopySource: copySource,
MetadataDirective: 'REPLACE',
- Metadata: newMetadata },
- (err, res) =>
- successCopyCheck(err, res, newMetadata,
- sourceBucketName, sourceObjName, done)
- );
+ Metadata: newMetadata }));
+ await successCopyCheck(null, res, newMetadata, sourceBucketName, sourceObjName);
});
it('should copy an object and replace the metadata if replace ' +
- 'included as metadata directive header', done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
+ 'included as metadata directive header', async () => {
+ const res = await s3.send(new CopyObjectCommand({ Bucket: destBucketName,
+ Key: destObjName,
CopySource: copySource,
MetadataDirective: 'REPLACE',
- Metadata: newMetadata,
- },
- (err, res) =>
- successCopyCheck(err, res, newMetadata,
- destBucketName, destObjName, done)
- );
+ Metadata: newMetadata }));
+ await successCopyCheck(null, res, newMetadata, destBucketName, destObjName);
});
it('should copy an object and replace ContentType if replace ' +
'included as a metadata directive header, and new ContentType is ' +
- 'provided', done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
+ 'provided', async () => {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName,
+ Key: destObjName,
CopySource: copySource,
MetadataDirective: 'REPLACE',
- ContentType: 'image',
- }, () => {
- s3.getObject({ Bucket: destBucketName,
- Key: destObjName }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.ContentType, 'image');
- return done();
- });
- });
+ ContentType: 'image' }));
+ const res = await s3.send(new GetObjectCommand({ Bucket: destBucketName, Key: destObjName }));
+ assert.strictEqual(res.ContentType, 'image');
});
it('should copy an object and keep ContentType if replace ' +
'included as a metadata directive header, but no new ContentType ' +
- 'is provided', done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
- CopySource: copySource, MetadataDirective: 'REPLACE',
- }, () => {
- s3.getObject({ Bucket: destBucketName,
- Key: destObjName }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.ContentType,
- 'application/octet-stream');
- return done();
- });
- });
+ 'is provided', async () => {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName,
+ Key: destObjName,
+ CopySource: copySource,
+ MetadataDirective: 'REPLACE' }));
+ const res = await s3.send(new GetObjectCommand({ Bucket: destBucketName,
+ Key: destObjName }));
+ assert.strictEqual(res.ContentType, 'application/octet-stream');
});
it('should also replace additional headers if replace ' +
'included as metadata directive header and new headers are ' +
- 'specified', done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
+ 'specified', async () => {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
CopySource: copySource,
MetadataDirective: 'REPLACE',
CacheControl: newCacheControl,
ContentDisposition: newContentDisposition,
ContentEncoding: newContentEncoding,
- Expires: newExpires,
- }, err => {
- checkNoError(err);
- s3.getObject({ Bucket: destBucketName,
- Key: destObjName }, (err, res) => {
- if (err) {
- done(err);
- }
- assert.strictEqual(res.CacheControl, newCacheControl);
- assert.strictEqual(res.ContentDisposition,
- newContentDisposition);
- // Should remove V4 streaming value 'aws-chunked'
- // to be compatible with AWS behavior
- assert.strictEqual(res.ContentEncoding, 'gzip,');
- assert.strictEqual(res.Expires.toGMTString(),
- newExpires.toGMTString());
- done();
- });
- });
+ Expires: newExpires }));
+ const res = await s3.send(new GetObjectCommand({ Bucket: destBucketName, Key: destObjName }));
+ assert.strictEqual(res.CacheControl, newCacheControl);
+ assert.strictEqual(res.ContentDisposition, newContentDisposition);
+ assert.strictEqual(res.ContentEncoding, 'gzip,');
+ assert.strictEqual(res.Expires.toGMTString(), newExpires.toGMTString());
});
it('should copy an object and the metadata if copy ' +
'included as metadata directive header (and ignore any new ' +
- 'metadata sent with copy request)', done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
+ 'metadata sent with copy request)', async () => {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
CopySource: copySource,
MetadataDirective: 'COPY',
- Metadata: newMetadata,
- },
- err => {
- checkNoError(err);
- s3.getObject({ Bucket: destBucketName,
- Key: destObjName }, (err, res) => {
- assert.deepStrictEqual(res.Metadata, originalMetadata);
- done();
- });
- });
+ Metadata: newMetadata }));
+ const res = await s3.send(new GetObjectCommand({ Bucket: destBucketName, Key: destObjName }));
+ assert.deepStrictEqual(res.Metadata, originalMetadata);
});
it('should copy an object and its additional headers if copy ' +
'included as metadata directive header (and ignore any new ' +
- 'headers sent with copy request)', done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
+ 'headers sent with copy request)', async () => {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
CopySource: copySource,
MetadataDirective: 'COPY',
Metadata: newMetadata,
CacheControl: newCacheControl,
ContentDisposition: newContentDisposition,
ContentEncoding: newContentEncoding,
- Expires: newExpires,
- }, err => {
- checkNoError(err);
- s3.getObject({ Bucket: destBucketName, Key: destObjName },
- (err, res) => {
- if (err) {
- done(err);
- }
- assert.strictEqual(res.CacheControl,
- originalCacheControl);
- assert.strictEqual(res.ContentDisposition,
- originalContentDisposition);
- assert.strictEqual(res.ContentEncoding,
- 'base64,');
- assert.strictEqual(res.Expires.toGMTString(),
- originalExpires.toGMTString());
- done();
- });
- });
+ Expires: newExpires }));
+ const res = await s3.send(new GetObjectCommand({ Bucket: destBucketName, Key: destObjName }));
+ assert.strictEqual(res.CacheControl, originalCacheControl);
+ assert.strictEqual(res.ContentDisposition, originalContentDisposition);
+ assert.strictEqual(res.ContentEncoding, 'base64,');
+ assert.strictEqual(res.Expires.toGMTString(), originalExpires.toGMTString());
});
- it('should copy a 0 byte object to different destination', done => {
+ it('should copy a 0 byte object to different destination', async () => {
const emptyFileETag = '"d41d8cd98f00b204e9800998ecf8427e"';
- s3.putObject({ Bucket: sourceBucketName, Key: sourceObjName,
- Body: '', Metadata: originalMetadata }, (err, res) => {
- checkNoError(err);
- copySource = `${sourceBucketName}/${sourceObjName}` +
- `?versionId=${res.VersionId}`;
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
- CopySource: copySource,
- },
- (err, res) => {
- checkNoError(err);
- assert.strictEqual(res.ETag, emptyFileETag);
- s3.getObject({ Bucket: destBucketName,
- Key: destObjName }, (err, res) => {
- assert.deepStrictEqual(res.Metadata,
- originalMetadata);
- assert.strictEqual(res.ETag, emptyFileETag);
- done();
- });
- });
- });
+ const putRes = await s3.send(new PutObjectCommand({ Bucket: sourceBucketName, Key: sourceObjName,
+ Body: '',
+ Metadata: originalMetadata }));
+ copySource = `${sourceBucketName}/${sourceObjName}?versionId=${putRes.VersionId}`;
+ const copyRes = await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
+ CopySource: copySource }));
+ assert.strictEqual(copyRes.CopyObjectResult.ETag, emptyFileETag);
+ const getRes = await s3.send(new GetObjectCommand({ Bucket: destBucketName,
+ Key: destObjName }));
+ assert.deepStrictEqual(getRes.Metadata, originalMetadata);
+ assert.strictEqual(getRes.ETag, emptyFileETag);
});
- // TODO: remove (or update to use different location constraint) in CLDSRV-639
if (constants.validStorageClasses.includes('REDUCED_REDUNDANCY')) {
- it('should copy a 0 byte object to same destination', done => {
+ it('should copy a 0 byte object to same destination', async () => {
const emptyFileETag = '"d41d8cd98f00b204e9800998ecf8427e"';
- s3.putObject({
- Bucket: sourceBucketName, Key: sourceObjName,
- Body: ''
- }, (err, putRes) => {
- checkNoError(err);
- copySource = `${sourceBucketName}/${sourceObjName}` +
- `?versionId=${putRes.VersionId}`;
- s3.copyObject({
- Bucket: sourceBucketName, Key: sourceObjName,
- CopySource: copySource,
- StorageClass: 'REDUCED_REDUNDANCY',
- }, (err, copyRes) => {
- checkNoError(err);
- assert.notEqual(copyRes.VersionId, putRes.VersionId);
- assert.strictEqual(copyRes.ETag, emptyFileETag);
- s3.getObject({
- Bucket: sourceBucketName,
- Key: sourceObjName
- }, (err, res) => {
- assert.deepStrictEqual(res.Metadata,
- {});
- assert.deepStrictEqual(res.StorageClass,
- 'REDUCED_REDUNDANCY');
- assert.strictEqual(res.ETag, emptyFileETag);
- done();
- });
- });
- });
+ const putRes = await s3.send(new PutObjectCommand({ Bucket: sourceBucketName, Key: sourceObjName,
+ Body: '' }));
+ copySource = `${sourceBucketName}/${sourceObjName}?versionId=${putRes.VersionId}`;
+ const copyRes = await s3.send(new CopyObjectCommand({ Bucket: sourceBucketName, Key: sourceObjName,
+ CopySource: copySource,
+ StorageClass: 'REDUCED_REDUNDANCY' }));
+ assert.notEqual(copyRes.VersionId, putRes.VersionId);
+ assert.strictEqual(copyRes.ETag, emptyFileETag);
+ const getRes = await s3.send(new GetObjectCommand({ Bucket: sourceBucketName,
+ Key: sourceObjName }));
+ assert.deepStrictEqual(getRes.Metadata, {});
+ assert.strictEqual(getRes.StorageClass,
+ 'REDUCED_REDUNDANCY');
+ assert.strictEqual(getRes.ETag, emptyFileETag);
});
it('should copy an object to a different destination and change ' +
- 'the storage class if storage class header provided', done => {
- s3.copyObject({
- Bucket: destBucketName, Key: destObjName,
+ 'the storage class if storage class header provided', async () => {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
CopySource: copySource,
- StorageClass: 'REDUCED_REDUNDANCY',
- }, err => {
- checkNoError(err);
- s3.getObject({
- Bucket: destBucketName,
- Key: destObjName
- }, (err, res) => {
- assert.strictEqual(res.StorageClass,
- 'REDUCED_REDUNDANCY');
- done();
- });
- });
+ StorageClass: 'REDUCED_REDUNDANCY' }));
+ const res = await s3.send(new GetObjectCommand({ Bucket: destBucketName, Key: destObjName }));
+ assert.strictEqual(res.StorageClass, 'REDUCED_REDUNDANCY');
});
it('should copy an object to the same destination and change the ' +
- 'storage class if the storage class header provided', done => {
- s3.copyObject({
- Bucket: sourceBucketName, Key: sourceObjName,
+ 'storage class if the storage class header provided', async () => {
+ await s3.send(new CopyObjectCommand({ Bucket: sourceBucketName, Key: sourceObjName,
CopySource: copySource,
- StorageClass: 'REDUCED_REDUNDANCY',
- }, err => {
- checkNoError(err);
- s3.getObject({
- Bucket: sourceBucketName,
- Key: sourceObjName
- }, (err, res) => {
- checkNoError(err);
- assert.strictEqual(res.StorageClass,
- 'REDUCED_REDUNDANCY');
- done();
- });
- });
+ StorageClass: 'REDUCED_REDUNDANCY' }));
+ const res = await s3.send(new GetObjectCommand({ Bucket: sourceBucketName, Key: sourceObjName }));
+ assert.strictEqual(res.StorageClass, 'REDUCED_REDUNDANCY');
});
}
it('should copy an object to a new bucket and overwrite an already ' +
- 'existing object in the destination bucket', done => {
- s3.putObject({ Bucket: destBucketName, Key: destObjName,
- Body: 'overwrite me', Metadata: originalMetadata },
- err => {
- checkNoError(err);
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
- CopySource: copySource,
- MetadataDirective: 'REPLACE',
- Metadata: newMetadata,
- }, (err, res) => {
- checkNoError(err);
- assert.strictEqual(res.ETag, etag);
- s3.getObject({ Bucket: destBucketName,
- Key: destObjName }, (err, res) => {
- assert.deepStrictEqual(res.Metadata,
- newMetadata);
- assert.strictEqual(res.ETag, etag);
- assert.strictEqual(res.Body.toString(), content);
- done();
- });
- });
- });
+ 'existing object in the destination bucket', async () => {
+ await s3.send(new PutObjectCommand({ Bucket: destBucketName, Key: destObjName,
+ Body: 'overwrite me', Metadata: originalMetadata }));
+ const copyRes = await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
+ CopySource: copySource,
+ MetadataDirective: 'REPLACE',
+ Metadata: newMetadata }));
+ assert.strictEqual(copyRes.CopyObjectResult.ETag, etag);
+ const getRes = await s3.send(new GetObjectCommand({ Bucket: destBucketName, Key: destObjName }));
+ assert.deepStrictEqual(getRes.Metadata, newMetadata);
+ assert.strictEqual(getRes.ETag, etag);
+ const body = await getRes.Body.transformToString();
+ assert.strictEqual(body, content);
});
- // skipping test as object level encryption is not implemented yet
it.skip('should copy an object and change the server side encryption' +
- 'option if server side encryption header provided', done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
+ 'option if server side encryption header provided', async () => {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
CopySource: copySource,
- ServerSideEncryption: 'AES256',
- },
- err => {
- checkNoError(err);
- s3.getObject({ Bucket: destBucketName,
- Key: destObjName }, (err, res) => {
- assert.strictEqual(res.ServerSideEncryption,
- 'AES256');
- done();
- });
- });
+ ServerSideEncryption: 'AES256' }));
+ const res = await s3.send(new GetObjectCommand({ Bucket: destBucketName,
+ Key: destObjName }));
+ assert.strictEqual(res.ServerSideEncryption, 'AES256');
});
- it('should return Not Implemented error for obj. encryption using ' +
- 'customer-provided encryption keys', done => {
+ it('should return Not Implemented error for obj. encryption using '+
+ 'customer-provided encryption keys', async () => {
const params = { Bucket: destBucketName, Key: 'key',
CopySource: copySource,
SSECustomerAlgorithm: 'AES256' };
- s3.copyObject(params, err => {
- assert.strictEqual(err.code, 'NotImplemented');
- done();
- });
+ try {
+ await s3.send(new CopyObjectCommand(params));
+ assert.fail('Expected NotImplemented error');
+ } catch (err) {
+ assert.strictEqual(err.name, 'NotImplemented');
+ }
});
- it('should copy an object and set the acl on the new object', done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
+ it('should copy an object and set the acl on the new object', async () => {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
CopySource: copySource,
- ACL: 'authenticated-read',
- },
- err => {
- checkNoError(err);
- s3.getObjectAcl({ Bucket: destBucketName,
- Key: destObjName }, (err, res) => {
- // With authenticated-read ACL, there are two
- // grants:
- // (1) FULL_CONTROL to the object owner
- // (2) READ to the authenticated-read
- assert.strictEqual(res.Grants.length, 2);
- assert.strictEqual(res.Grants[0].Permission,
- 'FULL_CONTROL');
- assert.strictEqual(res.Grants[1].Permission,
- 'READ');
- assert.strictEqual(res.Grants[1].Grantee.URI,
- 'http://acs.amazonaws.com/groups/' +
- 'global/AuthenticatedUsers');
- done();
- });
- });
+ ACL: 'authenticated-read' }));
+ const res = await s3.send(new GetObjectAclCommand({ Bucket: destBucketName,
+ Key: destObjName }));
+ assert.strictEqual(res.Grants.length, 2);
+ assert.strictEqual(res.Grants[0].Permission, 'FULL_CONTROL');
+ assert.strictEqual(res.Grants[1].Permission, 'READ');
+ assert.strictEqual(res.Grants[1].Grantee.URI,
+ 'http://acs.amazonaws.com/groups/global/AuthenticatedUsers');
});
it('should copy an object and default the acl on the new object ' +
'to private even if the copied object had a ' +
- 'different acl', done => {
- s3.putObjectAcl({ Bucket: sourceBucketName, Key: sourceObjName,
- ACL: 'authenticated-read' }, () => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
+ 'different acl', async () => {
+ await s3.send(new PutObjectAclCommand({ Bucket: sourceBucketName, Key: sourceObjName,
+ ACL: 'authenticated-read',
+ VersionId: versionId }));
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
+ CopySource: copySource }));
+ const res = await s3.send(new GetObjectAclCommand({ Bucket: destBucketName,
+ Key: destObjName }));
+ assert.strictEqual(res.Grants.length, 1);
+ assert.strictEqual(res.Grants[0].Permission, 'FULL_CONTROL');
+ });
+
+ it('should copy a version to same object name to restore '+
+ 'version of object', async () => {
+ const res = await s3.send(new CopyObjectCommand({ Bucket: sourceBucketName, Key: sourceObjName,
+ CopySource: copySource }));
+ await successCopyCheck(null, res, originalMetadata, sourceBucketName, sourceObjName);
+ });
+
+ it('should return an error if attempt to copy from nonexistent bucket', async () => {
+ try {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
+ CopySource: `nobucket453234/${sourceObjName}` }));
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'NoSuchBucket');
+ }
+ });
+
+ it('should return an error if use invalid redirect location', async () => {
+ try {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
CopySource: copySource,
- },
- () => {
- s3.getObjectAcl({ Bucket: destBucketName,
- Key: destObjName }, (err, res) => {
- // With private ACL, there is only one grant
- // of FULL_CONTROL to the object owner
- assert.strictEqual(res.Grants.length, 1);
- assert.strictEqual(res.Grants[0].Permission,
- 'FULL_CONTROL');
- done();
- });
- });
- });
+ WebsiteRedirectLocation: 'google.com' }));
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'InvalidRedirectLocation');
+ }
+ });
+
+ it('should return an error if attempt to copy to nonexistent bucket', async () => {
+ try {
+ await s3.send(new CopyObjectCommand({ Bucket: 'nobucket453234', Key: destObjName,
+ CopySource: `${sourceBucketName}/${sourceObjName}` }));
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'NoSuchBucket');
+ }
+ });
+
+ it('should return an error if attempt to copy nonexistent object', async () => {
+ try {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
+ CopySource: `${sourceBucketName}/nokey` }));
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'NoSuchKey');
+ }
+ });
+
+ it('should return NoSuchKey if attempt to copy version with delete marker', async () => {
+ const delRes = await s3.send(new DeleteObjectCommand({ Bucket: sourceBucketName,
+ Key: sourceObjName }));
+ assert.strictEqual(delRes.DeleteMarker, true);
+ try {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName,
+ Key: destObjName, CopySource: `${sourceBucketName}/${sourceObjName}` }));
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'NoSuchKey');
+ }
+ });
+
+ it('should return InvalidRequest if attempt to copy specific version that is a delete marker', async () => {
+ const delRes = await s3.send(new DeleteObjectCommand({ Bucket: sourceBucketName,
+ Key: sourceObjName }));
+ assert.strictEqual(delRes.DeleteMarker, true);
+ const deleteMarkerId = delRes.VersionId;
+ try {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName,
+ Key: destObjName,
+ CopySource: `${sourceBucketName}/${sourceObjName}` +
+ `?versionId=${deleteMarkerId}` }));
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'InvalidRequest');
+ }
});
- it('should copy a version to same object name to restore ' +
- 'version of object', done => {
- s3.copyObject({ Bucket: sourceBucketName, Key: sourceObjName,
- CopySource: copySource },
- (err, res) =>
- successCopyCheck(err, res, originalMetadata,
- sourceBucketName, sourceObjName, done)
- );
- });
-
- it('should return an error if attempt to copy from nonexistent bucket',
- done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
- CopySource: `nobucket453234/${sourceObjName}`,
- },
- err => {
- checkError(err, 'NoSuchBucket');
- done();
- });
- });
-
- it('should return an error if use invalid redirect location',
- done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
+ it('should return an error if send invalid metadata directive header', async () => {
+ try {
+ await s3.send(new CopyObjectCommand({ Bucket: destBucketName, Key: destObjName,
CopySource: copySource,
- WebsiteRedirectLocation: 'google.com',
- },
- err => {
- checkError(err, 'InvalidRedirectLocation');
- done();
- });
- });
-
+ MetadataDirective: 'copyHalf' }));
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'InvalidArgument');
+ }
+ });
- it('should return an error if attempt to copy to nonexistent bucket',
- done => {
- s3.copyObject({ Bucket: 'nobucket453234', Key: destObjName,
- CopySource: `${sourceBucketName}/${sourceObjName}`,
- },
- err => {
- checkError(err, 'NoSuchBucket');
- done();
- });
+ describe('copying by another account', () => {
+ const otherAccountBucket = 'otheraccountbucket42342342342';
+ const otherAccountKey = 'key';
+ beforeEach(async () => {
+ await otherAccountBucketUtility.createOne(otherAccountBucket);
});
- it('should return an error if attempt to copy nonexistent object',
- done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
- CopySource: `${sourceBucketName}/nokey`,
- },
- err => {
- checkError(err, 'NoSuchKey');
- done();
- });
+ afterEach(async () => {
+ await otherAccountBucketUtility.empty(otherAccountBucket);
+ await otherAccountBucketUtility.deleteOne(otherAccountBucket);
});
- it('should return NoSuchKey if attempt to copy version with ' +
- 'delete marker', done => {
- s3.deleteObject({
- Bucket: sourceBucketName,
- Key: sourceObjName,
- }, (err, data) => {
- if (err) {
- done(err);
- }
- assert.strictEqual(data.DeleteMarker, true);
- s3.copyObject({
- Bucket: destBucketName,
- Key: destObjName,
- CopySource: `${sourceBucketName}/${sourceObjName}`,
- },
- err => {
- checkError(err, 'NoSuchKey');
- done();
- });
- });
- });
-
- it('should return InvalidRequest if attempt to copy specific ' +
- 'version that is a delete marker', done => {
- s3.deleteObject({
- Bucket: sourceBucketName,
- Key: sourceObjName,
- }, (err, data) => {
- if (err) {
- done(err);
+ it('should not allow an account without read permission on the ' +
+ 'source object to copy the object', async () => {
+ try {
+ await otherAccountS3.send(new CopyObjectCommand({ Bucket: otherAccountBucket,
+ Key: otherAccountKey,
+ CopySource: copySource }));
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'AccessDenied');
}
- assert.strictEqual(data.DeleteMarker, true);
- const deleteMarkerId = data.VersionId;
- s3.copyObject({
- Bucket: destBucketName,
- Key: destObjName,
- CopySource: `${sourceBucketName}/${sourceObjName}` +
- `?versionId=${deleteMarkerId}`,
- },
- err => {
- checkError(err, 'InvalidRequest');
- done();
- });
- });
- });
-
- it('should return an error if send invalid metadata directive header',
- done => {
- s3.copyObject({ Bucket: destBucketName, Key: destObjName,
- CopySource: copySource,
- MetadataDirective: 'copyHalf',
- },
- err => {
- checkError(err, 'InvalidArgument');
- done();
- });
});
- describe('copying by another account', () => {
- const otherAccountBucket = 'otheraccountbucket42342342342';
- const otherAccountKey = 'key';
- beforeEach(() => otherAccountBucketUtility
- .createOne(otherAccountBucket)
- );
-
- afterEach(() => otherAccountBucketUtility.empty(otherAccountBucket)
- .then(() => otherAccountBucketUtility
- .deleteOne(otherAccountBucket))
- );
-
- it('should not allow an account without read persmission on the ' +
- 'source object to copy the object', done => {
- otherAccountS3.copyObject({ Bucket: otherAccountBucket,
+ it('should not allow an account without write permission on the ' +
+ 'destination bucket to copy the object', async () => {
+ await otherAccountS3.send(new PutObjectCommand({ Bucket: otherAccountBucket,
Key: otherAccountKey,
- CopySource: copySource,
- },
- err => {
- checkError(err, 'AccessDenied');
- done();
- });
- });
-
- it('should not allow an account without write persmission on the ' +
- 'destination bucket to copy the object', done => {
- otherAccountS3.putObject({ Bucket: otherAccountBucket,
- Key: otherAccountKey, Body: '' }, () => {
- otherAccountS3.copyObject({ Bucket: destBucketName,
+ Body: '' }));
+ try {
+ await otherAccountS3.send(new CopyObjectCommand({ Bucket: destBucketName,
Key: destObjName,
- CopySource: `${otherAccountBucket}/${otherAccountKey}`,
- },
- err => {
- checkError(err, 'AccessDenied');
- done();
- });
- });
+ CopySource: `${otherAccountBucket}/${otherAccountKey}` }));
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'AccessDenied');
+ }
});
it('should allow an account with read permission on the ' +
'source object and write permission on the destination ' +
- 'bucket to copy the object', done => {
- s3.putObjectAcl({ Bucket: sourceBucketName,
- Key: sourceObjName, ACL: 'public-read', VersionId:
- versionId }, () => {
- otherAccountS3.copyObject({ Bucket: otherAccountBucket,
- Key: otherAccountKey,
- CopySource: copySource,
- },
- err => {
- checkNoError(err);
- done();
- });
- });
+ 'bucket to copy the object', async () => {
+ await s3.send(new PutObjectAclCommand({ Bucket: sourceBucketName,
+ Key: sourceObjName,
+ ACL: 'public-read',
+ VersionId: versionId }));
+ await otherAccountS3.send(new CopyObjectCommand({ Bucket: otherAccountBucket,
+ Key: otherAccountKey,
+ CopySource: copySource }));
});
});
it('If-Match: returns no error when ETag match, with double quotes ' +
- 'around ETag',
- done => {
- requestCopy({ CopySourceIfMatch: etag }, err => {
- checkNoError(err);
- done();
- });
- });
+ 'around ETag', async () => {
+ await requestCopy({ CopySourceIfMatch: etag });
+ });
it('If-Match: returns no error when one of ETags match, with double ' +
- 'quotes around ETag',
- done => {
- requestCopy({ CopySourceIfMatch:
- `non-matching,${etag}` }, err => {
- checkNoError(err);
- done();
- });
- });
+ 'quotes around ETag', async () => {
+ await requestCopy({ CopySourceIfMatch: `non-matching,${etag}` });
+ });
it('If-Match: returns no error when ETag match, without double ' +
- 'quotes around ETag',
- done => {
- requestCopy({ CopySourceIfMatch: etagTrim }, err => {
- checkNoError(err);
- done();
- });
- });
+ 'quotes around ETag', async () => {
+ await requestCopy({ CopySourceIfMatch: etagTrim });
+ });
it('If-Match: returns no error when one of ETags match, without ' +
- 'double quotes around ETag',
- done => {
- requestCopy({ CopySourceIfMatch:
- `non-matching,${etagTrim}` }, err => {
- checkNoError(err);
- done();
- });
- });
+ 'double quotes around ETag', async () => {
+ await requestCopy({ CopySourceIfMatch: `non-matching,${etagTrim}` });
+ });
- it('If-Match: returns no error when ETag match with *', done => {
- requestCopy({ CopySourceIfMatch: '*' }, err => {
- checkNoError(err);
- done();
- });
+ it('If-Match: returns no error when ETag match with *', async () => {
+ await requestCopy({ CopySourceIfMatch: '*' });
});
- it('If-Match: returns PreconditionFailed when ETag does not match',
- done => {
- requestCopy({ CopySourceIfMatch: 'non-matching ETag' }, err => {
- checkError(err, 'PreconditionFailed');
- done();
- });
- });
+ it('If-Match: returns PreconditionFailed when ETag does not match', async () => {
+ try {
+ await requestCopy({ CopySourceIfMatch: 'non-matching ETag' });
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'PreconditionFailed');
+ }
+ });
- it('If-None-Match: returns no error when ETag does not match', done => {
- requestCopy({ CopySourceIfNoneMatch: 'non-matching' }, err => {
- checkNoError(err);
- done();
- });
+ it('If-None-Match: returns no error when ETag does not match', async () => {
+ await requestCopy({ CopySourceIfNoneMatch: 'non-matching' });
});
- it('If-None-Match: returns no error when all ETags do not match',
- done => {
- requestCopy({
- CopySourceIfNoneMatch: 'non-matching,non-matching-either',
- }, err => {
- checkNoError(err);
- done();
- });
- });
+ it('If-None-Match: returns no error when all ETags do not match', async () => {
+ await requestCopy({ CopySourceIfNoneMatch: 'non-matching,non-matching-either' });
+ });
it('If-None-Match: returns NotModified when ETag match, with double ' +
- 'quotes around ETag',
- done => {
- requestCopy({ CopySourceIfNoneMatch: etag }, err => {
- checkError(err, 'PreconditionFailed');
- done();
- });
- });
+ 'quotes around ETag', async () => {
+ try {
+ await requestCopy({ CopySourceIfNoneMatch: etag });
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'PreconditionFailed');
+ }
+ });
it('If-None-Match: returns NotModified when one of ETags match, with ' +
- 'double quotes around ETag',
- done => {
- requestCopy({
- CopySourceIfNoneMatch: `non-matching,${etag}`,
- }, err => {
- checkError(err, 'PreconditionFailed');
- done();
- });
- });
+ 'double quotes around ETag', async () => {
+ try {
+ await requestCopy({ CopySourceIfNoneMatch: `non-matching,${etag}` });
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'PreconditionFailed');
+ }
+ });
it('If-None-Match: returns NotModified when ETag match, without ' +
- 'double quotes around ETag',
- done => {
- requestCopy({ CopySourceIfNoneMatch: etagTrim }, err => {
- checkError(err, 'PreconditionFailed');
- done();
- });
- });
+ 'double quotes around ETag', async () => {
+ try {
+ await requestCopy({ CopySourceIfNoneMatch: etagTrim });
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'PreconditionFailed');
+ }
+ });
it('If-None-Match: returns NotModified when one of ETags match, ' +
- 'without double quotes around ETag',
- done => {
- requestCopy({
- CopySourceIfNoneMatch: `non-matching,${etagTrim}`,
- }, err => {
- checkError(err, 'PreconditionFailed');
- done();
- });
- });
+ 'without double quotes around ETag', async () => {
+ try {
+ await requestCopy({ CopySourceIfNoneMatch: `non-matching,${etagTrim}` });
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'PreconditionFailed');
+ }
+ });
it('If-Modified-Since: returns no error if Last modified date is ' +
- 'greater',
- done => {
- requestCopy({ CopySourceIfModifiedSince: dateFromNow(-1) },
- err => {
- checkNoError(err);
- done();
- });
- });
-
+ 'greater', async () => {
+ await requestCopy({ CopySourceIfModifiedSince: dateFromNow(-1) });
+ });
// Skipping this test, because real AWS does not provide error as
// expected
it.skip('If-Modified-Since: returns NotModified if Last modified ' +
- 'date is lesser',
- done => {
- requestCopy({ CopySourceIfModifiedSince: dateFromNow(1) },
- err => {
- checkError(err, 'PreconditionFailed');
- done();
- });
- });
+ 'date is lesser', async () => {
+ try {
+ await requestCopy({ CopySourceIfModifiedSince: dateFromNow(1) });
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'PreconditionFailed');
+ }
+ });
- it('If-Modified-Since: returns NotModified if Last modified ' +
- 'date is equal',
- done => {
- requestCopy({ CopySourceIfModifiedSince:
- dateConvert(lastModified) },
- err => {
- checkError(err, 'PreconditionFailed');
- done();
- });
- });
+ it('If-Modified-Since: returns NotModified if Last modified '+
+ 'date is equal', async () => {
+ try {
+ await requestCopy({ CopySourceIfModifiedSince: dateConvert(lastModified) });
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'PreconditionFailed');
+ }
+ });
it('If-Unmodified-Since: returns no error when lastModified date is ' +
- 'greater',
- done => {
- requestCopy({ CopySourceIfUnmodifiedSince: dateFromNow(1) },
- err => {
- checkNoError(err);
- done();
- });
- });
+ 'greater', async () => {
+ await requestCopy({ CopySourceIfUnmodifiedSince: dateFromNow(1) });
+ });
it('If-Unmodified-Since: returns no error when lastModified ' +
- 'date is equal',
- done => {
- requestCopy({ CopySourceIfUnmodifiedSince:
- dateConvert(lastModified) },
- err => {
- checkNoError(err);
- done();
- });
- });
+ 'date is equal', async () => {
+ await requestCopy({ CopySourceIfUnmodifiedSince: dateConvert(lastModified) });
+ });
it('If-Unmodified-Since: returns PreconditionFailed when ' +
- 'lastModified date is lesser',
- done => {
- requestCopy({ CopySourceIfUnmodifiedSince: dateFromNow(-1) },
- err => {
- checkError(err, 'PreconditionFailed');
- done();
- });
- });
+ 'lastModified date is lesser', async () => {
+ try {
+ await requestCopy({ CopySourceIfUnmodifiedSince: dateFromNow(-1) });
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'PreconditionFailed');
+ }
+ });
it('If-Match & If-Unmodified-Since: returns no error when match Etag ' +
- 'and lastModified is greater',
- done => {
- requestCopy({
- CopySourceIfMatch: etagTrim,
- CopySourceIfUnmodifiedSince: dateFromNow(-1),
- }, err => {
- checkNoError(err);
- done();
- });
- });
+ 'and lastModified is greater', async () => {
+ await requestCopy({ CopySourceIfMatch: etagTrim, CopySourceIfUnmodifiedSince: dateFromNow(-1) });
+ });
- it('If-Match match & If-Unmodified-Since match', done => {
- requestCopy({
- CopySourceIfMatch: etagTrim,
- CopySourceIfUnmodifiedSince: dateFromNow(1),
- }, err => {
- checkNoError(err);
- done();
- });
+ it('If-Match match & If-Unmodified-Since match', async () => {
+ await requestCopy({ CopySourceIfMatch: etagTrim, CopySourceIfUnmodifiedSince: dateFromNow(1) });
});
- it('If-Match not match & If-Unmodified-Since not match', done => {
- requestCopy({
- CopySourceIfMatch: 'non-matching',
- CopySourceIfUnmodifiedSince: dateFromNow(-1),
- }, err => {
+ it('If-Match not match & If-Unmodified-Since not match', async () => {
+ try {
+ await requestCopy({ CopySourceIfMatch: 'non-matching', CopySourceIfUnmodifiedSince: dateFromNow(-1) });
+ assert.fail('Expected error');
+ } catch (err) {
checkError(err, 'PreconditionFailed');
- done();
- });
+ }
});
- it('If-Match not match & If-Unmodified-Since match', done => {
- requestCopy({
- CopySourceIfMatch: 'non-matching',
- CopySourceIfUnmodifiedSince: dateFromNow(1),
- }, err => {
+ it('If-Match not match & If-Unmodified-Since match', async () => {
+ try {
+ await requestCopy({
+ CopySourceIfMatch: 'non-matching',
+ CopySourceIfUnmodifiedSince: dateFromNow(1) });
+ assert.fail('Expected error');
+ } catch (err) {
checkError(err, 'PreconditionFailed');
- done();
- });
+ }
});
- // Skipping this test, because real AWS does not provide error as
- // expected
- it.skip('If-Match match & If-Modified-Since not match', done => {
- requestCopy({
- CopySourceIfMatch: etagTrim,
- CopySourceIfModifiedSince: dateFromNow(1),
- }, err => {
- checkNoError(err);
- done();
- });
+ it.skip('If-Match match & If-Modified-Since not match', async () => {
+ await requestCopy({ CopySourceIfMatch: etagTrim, CopySourceIfModifiedSince: dateFromNow(1) });
});
- it('If-Match match & If-Modified-Since match', done => {
- requestCopy({
+ it('If-Match match & If-Modified-Since match', async () => {
+ await requestCopy({
CopySourceIfMatch: etagTrim,
- CopySourceIfModifiedSince: dateFromNow(-1),
- }, err => {
- checkNoError(err);
- done();
- });
+ CopySourceIfModifiedSince: dateFromNow(-1) });
});
- it('If-Match not match & If-Modified-Since not match', done => {
- requestCopy({
- CopySourceIfMatch: 'non-matching',
- CopySourceIfModifiedSince: dateFromNow(1),
- }, err => {
+ it('If-Match not match & If-Modified-Since not match', async () => {
+ try {
+ await requestCopy({
+ CopySourceIfMatch: 'non-matching',
+ CopySourceIfModifiedSince: dateFromNow(1) });
+ assert.fail('Expected error');
+ } catch (err) {
checkError(err, 'PreconditionFailed');
- done();
- });
+ }
});
- it('If-Match not match & If-Modified-Since match', done => {
- requestCopy({
- CopySourceIfMatch: 'non-matching',
- CopySourceIfModifiedSince: dateFromNow(-1),
- }, err => {
+ it('If-Match not match & If-Modified-Since match', async () => {
+ try {
+ await requestCopy({
+ CopySourceIfMatch: 'non-matching',
+ CopySourceIfModifiedSince: dateFromNow(-1) });
+ assert.fail('Expected error');
+ } catch (err) {
checkError(err, 'PreconditionFailed');
- done();
- });
+ }
});
it('If-None-Match & If-Modified-Since: returns NotModified when Etag ' +
- 'does not match and lastModified is greater',
- done => {
- requestCopy({
+ 'does not match and lastModified is greater', async () => {
+ try {
+ await requestCopy({
CopySourceIfNoneMatch: etagTrim,
- CopySourceIfModifiedSince: dateFromNow(-1),
- }, err => {
- checkError(err, 'PreconditionFailed');
- done();
- });
- });
+ CopySourceIfModifiedSince: dateFromNow(-1) });
+ assert.fail('Expected error');
+ } catch (err) {
+ checkError(err, 'PreconditionFailed');
+ }
+ });
- it('If-None-Match not match & If-Modified-Since not match', done => {
- requestCopy({
- CopySourceIfNoneMatch: etagTrim,
- CopySourceIfModifiedSince: dateFromNow(1),
- }, err => {
+ it('If-None-Match not match & If-Modified-Since not match', async () => {
+ try {
+ await requestCopy({
+ CopySourceIfNoneMatch: etagTrim,
+ CopySourceIfModifiedSince: dateFromNow(1) });
+ assert.fail('Expected error');
+ } catch (err) {
checkError(err, 'PreconditionFailed');
- done();
- });
+ }
});
- it('If-None-Match match & If-Modified-Since match', done => {
- requestCopy({
+ it('If-None-Match match & If-Modified-Since match', async () => {
+ await requestCopy({
CopySourceIfNoneMatch: 'non-matching',
- CopySourceIfModifiedSince: dateFromNow(-1),
- }, err => {
- checkNoError(err);
- done();
- });
+ CopySourceIfModifiedSince: dateFromNow(-1) });
});
- // Skipping this test, because real AWS does not provide error as
- // expected
- it.skip('If-None-Match match & If-Modified-Since not match', done => {
- requestCopy({
- CopySourceIfNoneMatch: 'non-matching',
- CopySourceIfModifiedSince: dateFromNow(1),
- }, err => {
+ it.skip('If-None-Match match & If-Modified-Since not match', async () => {
+ try {
+ await requestCopy({
+ CopySourceIfNoneMatch: 'non-matching',
+ CopySourceIfModifiedSince: dateFromNow(1) });
+ assert.fail('Expected error');
+ } catch (err) {
checkError(err, 'PreconditionFailed');
- done();
- });
+ }
});
- it('If-None-Match match & If-Unmodified-Since match', done => {
- requestCopy({
+ it('If-None-Match match & If-Unmodified-Since match', async () => {
+ await requestCopy({
CopySourceIfNoneMatch: 'non-matching',
- CopySourceIfUnmodifiedSince: dateFromNow(1),
- }, err => {
- checkNoError(err);
- done();
- });
+ CopySourceIfUnmodifiedSince: dateFromNow(1) });
});
- it('If-None-Match match & If-Unmodified-Since not match', done => {
- requestCopy({
- CopySourceIfNoneMatch: 'non-matching',
- CopySourceIfUnmodifiedSince: dateFromNow(-1),
- }, err => {
+ it('If-None-Match match & If-Unmodified-Since not match', async () => {
+ try {
+ await requestCopy({
+ CopySourceIfNoneMatch: 'non-matching',
+ CopySourceIfUnmodifiedSince: dateFromNow(-1) });
+ assert.fail('Expected error');
+ } catch (err) {
checkError(err, 'PreconditionFailed');
- done();
- });
+ }
});
- it('If-None-Match not match & If-Unmodified-Since match', done => {
- requestCopy({
- CopySourceIfNoneMatch: etagTrim,
- CopySourceIfUnmodifiedSince: dateFromNow(1),
- }, err => {
+ it('If-None-Match not match & If-Unmodified-Since match', async () => {
+ try {
+ await requestCopy({
+ CopySourceIfNoneMatch: etagTrim,
+ CopySourceIfUnmodifiedSince: dateFromNow(1) });
+ assert.fail('Expected error');
+ } catch (err) {
checkError(err, 'PreconditionFailed');
- done();
- });
+ }
});
- it('If-None-Match not match & If-Unmodified-Since not match', done => {
- requestCopy({
- CopySourceIfNoneMatch: etagTrim,
- CopySourceIfUnmodifiedSince: dateFromNow(-1),
- }, err => {
+ it('If-None-Match not match & If-Unmodified-Since not match', async () => {
+ try {
+ await requestCopy({
+ CopySourceIfNoneMatch: etagTrim,
+ CopySourceIfUnmodifiedSince: dateFromNow(-1) });
+ assert.fail('Expected error');
+ } catch (err) {
checkError(err, 'PreconditionFailed');
- done();
- });
+ }
});
});
});
diff --git a/tests/functional/aws-node-sdk/test/versioning/objectDelete.js b/tests/functional/aws-node-sdk/test/versioning/objectDelete.js
index a23f697eba..3d8c47ac41 100644
--- a/tests/functional/aws-node-sdk/test/versioning/objectDelete.js
+++ b/tests/functional/aws-node-sdk/test/versioning/objectDelete.js
@@ -1,5 +1,14 @@
const assert = require('assert');
-const async = require('async');
+const {
+ CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ DeleteObjectCommand,
+ DeleteObjectsCommand,
+ GetObjectCommand,
+ ListObjectVersionsCommand,
+} = require('@aws-sdk/client-s3');
const withV4 = require('../support/withV4');
const BucketUtility = require('../../lib/utility/bucket-util');
@@ -9,6 +18,9 @@ const {
versioningEnabled,
removeAllVersions,
} = require('../../lib/utility/versioning-util.js');
+const { promisify } = require('util');
+
+const removeAllVersionsPromise = promisify(removeAllVersions);
const bucket = `versioning-bucket-${Date.now()}`;
const key = 'anObject';
@@ -18,107 +30,77 @@ const nonExistingId = process.env.AWS_ON_AIR ?
'MhhyTHhmZ4cxSi4Y9SMe5P7UJAz7HLJ9' :
'3939393939393939393936493939393939393939756e6437';
-function _assertNoError(err, desc) {
- assert.strictEqual(err, null, `Unexpected err ${desc || ''}: ${err}`);
-}
-
describe('delete marker creation in bucket with null version', () => {
withV4(sigCfg => {
const bucketUtil = new BucketUtility('default', sigCfg);
const s3 = bucketUtil.s3;
const nullVersionBody = 'nullversionbody';
- beforeEach(done => {
- s3.createBucket({ Bucket: bucket }, err => {
- if (err) {
- return done(err);
- } // put null object
- return s3.putObject({
- Bucket: bucket,
- Key: key,
- Body: nullVersionBody,
- }, done);
- });
- });
-
- afterEach(done => {
- removeAllVersions({ Bucket: bucket }, err => {
- if (err) {
- return done(err);
+ beforeEach(async () => {
+ await s3.send(new CreateBucketCommand({ Bucket: bucket }));
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: nullVersionBody,
+ }));
+ });
+
+ afterEach(async () => {
+ try {
+ await removeAllVersionsPromise({ Bucket: bucket });
+ await bucketUtil.empty(bucket);
+ await s3.send(new DeleteBucketCommand({ Bucket: bucket }));
+ } catch (err) {
+ if (err.name !== 'NoSuchBucket') {
+ throw err;
}
- return s3.deleteBucket({ Bucket: bucket }, err => {
- assert.strictEqual(err, null,
- `Error deleting bucket: ${err}`);
- return done();
- });
- });
+ }
});
- it('should keep the null version if versioning enabled', done => {
- async.waterfall([
- callback => s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningEnabled,
- }, err => callback(err)),
- callback =>
- s3.listObjectVersions({ Bucket: bucket }, (err, data) => {
- _assertNoError(err, 'listing object versions');
- assert.strictEqual(data.Versions.length, 1);
- assert.strictEqual(data.Versions[0].VersionId,
- 'null');
- return callback();
- }),
- callback => s3.deleteObject({ Bucket: bucket, Key: key },
- (err, data) => {
- _assertNoError(err, 'creating delete marker');
- assert.strictEqual(data.DeleteMarker, true);
- assert(data.VersionId);
- return callback(null, data.VersionId);
- }),
- (deleteMarkerVerId, callback) =>
- s3.listObjectVersions({ Bucket: bucket }, (err, data) => {
- _assertNoError(err, 'listing object versions');
- assert.strictEqual(data.Versions.length, 1);
- assert.strictEqual(data.Versions[0].VersionId,
- 'null');
- assert.strictEqual(data.DeleteMarkers[0].VersionId,
- deleteMarkerVerId);
- return callback();
- }),
- ], done);
+ it('should keep the null version if versioning enabled', async () => {
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningEnabled,
+ }));
+
+ // List versions to check null version exists
+ const listData = await s3.send(new ListObjectVersionsCommand({ Bucket: bucket }));
+ assert.strictEqual(listData.Versions.length, 1);
+ assert.strictEqual(listData.Versions[0].VersionId, 'null');
+
+ // Delete object to create delete marker
+ const deleteData = await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
+ assert.strictEqual(deleteData.DeleteMarker, true);
+ assert(deleteData.VersionId);
+
+ // List versions again to verify null version still exists with delete marker
+ const listData2 = await s3.send(new ListObjectVersionsCommand({ Bucket: bucket }));
+ assert.strictEqual(listData2.Versions.length, 1);
+ assert.strictEqual(listData2.Versions[0].VersionId, 'null');
+ assert.strictEqual(listData2.DeleteMarkers[0].VersionId, deleteData.VersionId);
});
it('delete marker overwrites null version if versioning suspended',
- done => {
- async.waterfall([
- callback => s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningSuspended,
- }, err => callback(err)),
- callback =>
- s3.listObjectVersions({ Bucket: bucket }, (err, data) => {
- _assertNoError(err, 'listing object versions');
- assert.strictEqual(data.Versions.length, 1);
- assert.strictEqual(data.Versions[0].VersionId,
- 'null');
- return callback();
- }),
- callback => s3.deleteObject({ Bucket: bucket, Key: key },
- (err, data) => {
- _assertNoError(err, 'creating delete marker');
- assert.strictEqual(data.DeleteMarker, true);
- assert.strictEqual(data.VersionId, 'null');
- return callback(null, data.VersionId);
- }),
- (deleteMarkerVerId, callback) =>
- s3.listObjectVersions({ Bucket: bucket }, (err, data) => {
- _assertNoError(err, 'listing object versions');
- assert.strictEqual(data.Versions.length, 0);
- assert.strictEqual(data.DeleteMarkers[0].VersionId,
- deleteMarkerVerId);
- return callback();
- }),
- ], done);
+ async () => {
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningSuspended,
+ }));
+
+ // List versions to check null version exists
+ const listData = await s3.send(new ListObjectVersionsCommand({ Bucket: bucket }));
+ assert.strictEqual(listData.Versions.length, 1);
+ assert.strictEqual(listData.Versions[0].VersionId, 'null');
+
+ // Delete object to create delete marker
+ const deleteData = await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
+ assert.strictEqual(deleteData.DeleteMarker, true);
+ assert.strictEqual(deleteData.VersionId, 'null');
+
+ // List versions again to verify null version was overwritten
+ const listData2 = await s3.send(new ListObjectVersionsCommand({ Bucket: bucket }));
+ assert.strictEqual(listData2.Versions, undefined);
+ assert.strictEqual(listData2.DeleteMarkers[0].VersionId, deleteData.VersionId);
});
});
});
@@ -130,554 +112,411 @@ describe('aws-node-sdk test delete object', () => {
let versionIds;
// setup test
- before(done => {
+ before(async () => {
versionIds = [];
- s3.createBucket({ Bucket: bucket }, done);
+ await s3.send(new CreateBucketCommand({ Bucket: bucket }));
});
// delete bucket after testing
- after(done => {
- removeAllVersions({ Bucket: bucket }, err => {
- if (err && err.code === 'NoSuchBucket') {
- return done();
- } else if (err) {
- return done(err);
+ after(async () => {
+ try {
+ await removeAllVersionsPromise({ Bucket: bucket });
+ await bucketUtil.empty(bucket);
+ await s3.send(new DeleteBucketCommand({ Bucket: bucket }));
+ } catch (err) {
+ if (err.name !== 'NoSuchBucket') {
+ throw err;
}
- return s3.deleteBucket({ Bucket: bucket }, err => {
- assert.strictEqual(err, null,
- `Error deleting bucket: ${err}`);
- return done();
- });
- });
+ }
});
it('delete non existent object should not create a delete marker',
- done => {
- s3.deleteObject({
+ async () => {
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: `${key}000`,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.DeleteMarker, undefined);
- assert.strictEqual(res.VersionId, undefined);
- return done();
- });
+ }));
+ assert.strictEqual(res.DeleteMarker, undefined);
+ assert.strictEqual(res.VersionId, undefined);
});
- it('creating non-versioned object', done => {
- s3.putObject({
+ it('creating non-versioned object', async () => {
+ const res = await s3.send(new PutObjectCommand({
Bucket: bucket,
Key: key,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.equal(res.VersionId, undefined);
- return done();
- });
+ }));
+ assert.equal(res.VersionId, undefined);
});
it('delete in non-versioned bucket should not create delete marker',
- done => {
- s3.putObject({
+ async () => {
+ const putRes = await s3.send(new PutObjectCommand({
Bucket: bucket,
Key: key,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.equal(res.VersionId, undefined);
- return s3.deleteObject({
- Bucket: bucket,
- Key: `${key}2`,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.DeleteMarker, undefined);
- assert.strictEqual(res.VersionId, undefined);
- return done();
- });
- });
+ }));
+ assert.equal(putRes.VersionId, undefined);
+
+ const deleteRes = await s3.send(new DeleteObjectCommand({
+ Bucket: bucket,
+ Key: `${key}2`,
+ }));
+ assert.strictEqual(deleteRes.DeleteMarker, undefined);
+ assert.strictEqual(deleteRes.VersionId, undefined);
});
- it('enable versioning', done => {
+ it('enable versioning', async () => {
const params = {
Bucket: bucket,
VersioningConfiguration: {
Status: 'Enabled',
},
};
- s3.putBucketVersioning(params, done);
+ await s3.send(new PutBucketVersioningCommand(params));
});
it('should not send back error for non-existing key (specific version)',
- done => {
- s3.deleteObject({
+ async () => {
+ await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: `${key}3`,
VersionId: 'null',
- }, err => {
- if (err) {
- return done(err);
- }
- return done();
- });
+ }));
});
- it('delete non existent object should create a delete marker', done => {
- s3.deleteObject({
+ it('delete non existent object should create a delete marker', async () => {
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: `${key}2`,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.DeleteMarker, true);
- assert.notEqual(res.VersionId, undefined);
- return s3.deleteObject({
- Bucket: bucket,
- Key: `${key}2`,
- }, (err, res2) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res2.DeleteMarker, true);
- assert.notEqual(res2.VersionId, res.VersionId);
- return s3.deleteObject({
- Bucket: bucket,
- Key: `${key}2`,
- VersionId: res.VersionId,
- }, err => {
- if (err) {
- return done(err);
- }
- return s3.deleteObject({
- Bucket: bucket,
- Key: `${key}2`,
- VersionId: res2.VersionId,
- }, err => done(err));
- });
- });
- });
+ }));
+ assert.strictEqual(res.DeleteMarker, true);
+ assert.notEqual(res.VersionId, undefined);
+
+ const res2 = await s3.send(new DeleteObjectCommand({
+ Bucket: bucket,
+ Key: `${key}2`,
+ }));
+ assert.strictEqual(res2.DeleteMarker, true);
+ assert.notEqual(res2.VersionId, res.VersionId);
+
+ await s3.send(new DeleteObjectCommand({
+ Bucket: bucket,
+ Key: `${key}2`,
+ VersionId: res.VersionId,
+ }));
+
+ await s3.send(new DeleteObjectCommand({
+ Bucket: bucket,
+ Key: `${key}2`,
+ VersionId: res2.VersionId,
+ }));
});
it('delete non existent version should not create delete marker',
- done => {
- s3.deleteObject({
+ async () => {
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: key,
VersionId: nonExistingId,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.VersionId, nonExistingId);
- return s3.listObjectVersions({ Bucket: bucket }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.DeleteMarkers.length, 0);
- return done();
- });
- });
+ }));
+ assert.strictEqual(res.VersionId, nonExistingId);
+
+ const listRes = await s3.send(new ListObjectVersionsCommand({ Bucket: bucket }));
+ assert.strictEqual(listRes.DeleteMarkers?.length || 0, 0);
});
- it('put a version to the object', done => {
- s3.putObject({
+ it('put a version to the object', async () => {
+ const res = await s3.send(new PutObjectCommand({
Bucket: bucket,
Key: key,
Body: 'test',
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- versionIds.push('null');
- versionIds.push(res.VersionId);
- assert.notEqual(res.VersionId, undefined);
- return done();
- });
+ }));
+ versionIds.push('null');
+ versionIds.push(res.VersionId);
+ assert.notEqual(res.VersionId, undefined);
});
- it('should create a delete marker', done => {
- s3.deleteObject({
+ it('should create a delete marker', async () => {
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: key,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.DeleteMarker, true);
- assert.strictEqual(
- versionIds.find(item => item === res.VersionId),
- undefined);
- versionIds.push(res.VersionId);
- return done();
- });
+ }));
+ assert.strictEqual(res.DeleteMarker, true);
+ assert.strictEqual(
+ versionIds.find(item => item === res.VersionId),
+ undefined);
+ versionIds.push(res.VersionId);
});
it('should return 404 with a delete marker', done => {
- s3.getObject({
+ s3.send(new GetObjectCommand({
Bucket: bucket,
Key: key,
- }, function test(err) {
- if (!err) {
- return done(new Error('should return 404'));
- }
- const headers = this.httpResponse.headers;
- assert.strictEqual(headers['x-amz-delete-marker'], 'true');
- return done();
+ })).then(() => {
+ done(new Error('should return 404'));
+ }).catch(err => {
+ assert.strictEqual(err.Code, 'NoSuchKey');
+ done();
});
});
- it('should delete the null version', done => {
+ it('should delete the null version', async () => {
const version = versionIds.shift();
- s3.deleteObject({
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: key,
VersionId: version,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.VersionId, version);
- assert.equal(res.DeleteMarker, undefined);
- return done();
- });
+ }));
+ assert.strictEqual(res.VersionId, version);
+ assert.equal(res.DeleteMarker, undefined);
});
- it('should delete the versioned object', done => {
+ it('should delete the versioned object', async () => {
const version = versionIds.shift();
- s3.deleteObject({
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: key,
VersionId: version,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.VersionId, version);
- assert.equal(res.DeleteMarker, undefined);
- return done();
- });
+ }));
+ assert.strictEqual(res.VersionId, version);
+ assert.equal(res.DeleteMarker, undefined);
});
- it('should delete the delete-marker version', done => {
+ it('should delete the delete-marker version', async () => {
const version = versionIds.shift();
- s3.deleteObject({
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: key,
VersionId: version,
- }, function test(err, res) {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.VersionId, version);
- assert.equal(res.DeleteMarker, true);
- // deleting a delete marker should set the x-amz-delete-marker header
- const headers = this.httpResponse.headers;
- assert.strictEqual(headers['x-amz-delete-marker'], 'true');
- return done();
- });
+ }));
+ assert.strictEqual(res.VersionId, version);
+ assert.equal(res.DeleteMarker, true);
+ // In AWS SDK v3, the delete marker flag is sufficient for validation
+ // The x-amz-delete-marker header is handled internally by the SDK
});
- it('put a new version', done => {
- s3.putObject({
+ it('put a new version', async () => {
+ const res = await s3.send(new PutObjectCommand({
Bucket: bucket,
Key: key,
Body: 'test',
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- versionIds.push(res.VersionId);
- assert.notEqual(res.VersionId, undefined);
- return done();
- });
+ }));
+ versionIds.push(res.VersionId);
+ assert.notEqual(res.VersionId, undefined);
});
- it('get the null version', done => {
- s3.getObject({
- Bucket: bucket,
- Key: key,
- VersionId: 'null',
- }, err => {
- if (!err || err.code !== 'NoSuchVersion') {
- return done(err || 'should send back an error');
+ it('get the null version', async () => {
+ try {
+ await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ VersionId: 'null',
+ }));
+ throw new Error('should send back an error');
+ } catch (err) {
+ if (err.Code !== 'NoSuchVersion') {
+ throw err;
}
- return done();
- });
+ }
});
- it('suspending versioning', done => {
+ it('suspending versioning', async () => {
const params = {
Bucket: bucket,
VersioningConfiguration: {
Status: 'Suspended',
},
};
- s3.putBucketVersioning(params, done);
+ await s3.send(new PutBucketVersioningCommand(params));
});
- it('delete non existent object should create a delete marker', done => {
- s3.deleteObject({
+ it('delete non existent object should create a delete marker', async () => {
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: `${key}2`,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.DeleteMarker, true);
- assert.notEqual(res.VersionId, undefined);
- return s3.deleteObject({
- Bucket: bucket,
- Key: `${key}2`,
- }, (err, res2) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res2.DeleteMarker, true);
- assert.strictEqual(res2.VersionId, res.VersionId);
- return s3.deleteObject({
- Bucket: bucket,
- Key: `${key}2`,
- VersionId: res.VersionId,
- }, err => done(err));
- });
- });
+ }));
+ assert.strictEqual(res.DeleteMarker, true);
+ assert.notEqual(res.VersionId, undefined);
+
+ const res2 = await s3.send(new DeleteObjectCommand({
+ Bucket: bucket,
+ Key: `${key}2`,
+ }));
+ assert.strictEqual(res2.DeleteMarker, true);
+ assert.strictEqual(res2.VersionId, res.VersionId);
+
+ await s3.send(new DeleteObjectCommand({
+ Bucket: bucket,
+ Key: `${key}2`,
+ VersionId: res.VersionId,
+ }));
});
- it('should put a new delete marker', done => {
- s3.deleteObject({
+ it('should put a new delete marker', async () => {
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: key,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.DeleteMarker, true);
- assert.strictEqual(res.VersionId, 'null');
- return done();
- });
+ }));
+ assert.strictEqual(res.DeleteMarker, true);
+ assert.strictEqual(res.VersionId, 'null');
});
- it('enabling versioning', done => {
+ it('enabling versioning', async () => {
const params = {
Bucket: bucket,
VersioningConfiguration: {
Status: 'Enabled',
},
};
- s3.putBucketVersioning(params, done);
+ await s3.send(new PutBucketVersioningCommand(params));
});
it('should get the null version', done => {
- s3.getObject({
+ s3.send(new GetObjectCommand({
Bucket: bucket,
Key: key,
VersionId: 'null',
- }, function test(err) {
- const headers = this.httpResponse.headers;
- assert.strictEqual(headers['x-amz-delete-marker'], 'true');
- assert.strictEqual(headers['x-amz-version-id'], 'null');
- if (err && err.code !== 'MethodNotAllowed') {
+ })).then(() => {
+ done('should return an error');
+ }).catch(err => {
+ if (err.Code !== 'MethodNotAllowed') {
return done(err);
- } else if (err) {
+ } else {
return done();
}
- return done('should return an error');
});
});
- it('put a new version to store the null version', done => {
- s3.putObject({
+ it('put a new version to store the null version', async () => {
+ const res = await s3.send(new PutObjectCommand({
Bucket: bucket,
Key: key,
Body: 'test',
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- versionIds.push(res.VersionId);
- return done();
- });
+ }));
+ versionIds.push(res.VersionId);
});
- it('suspending versioning', done => {
+ it('suspending versioning', async () => {
const params = {
Bucket: bucket,
VersioningConfiguration: {
Status: 'Suspended',
},
};
- s3.putBucketVersioning(params, done);
+ await s3.send(new PutBucketVersioningCommand(params));
});
- it('put null version', done => {
- s3.putObject({
+ it('put null version', async () => {
+ const res = await s3.send(new PutObjectCommand({
Bucket: bucket,
Key: key,
Body: 'test-null-version',
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.VersionId, undefined);
- return done();
- });
+ }));
+ assert.strictEqual(res.VersionId, undefined);
});
- it('enabling versioning', done => {
+ it('enabling versioning', async () => {
const params = {
Bucket: bucket,
VersioningConfiguration: {
Status: 'Enabled',
},
};
- s3.putBucketVersioning(params, done);
+ await s3.send(new PutBucketVersioningCommand(params));
});
- it('should get the null version', done => {
- s3.getObject({
+ it('should get the null version', async () => {
+ const res = await s3.send(new GetObjectCommand({
Bucket: bucket,
Key: key,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.Body.toString(), 'test-null-version');
- return done();
- });
+ }));
+ const body = await res.Body.transformToString();
+ assert.strictEqual(body, 'test-null-version');
});
- it('should add a delete marker', done => {
- s3.deleteObject({
+ it('should add a delete marker', async () => {
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: key,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.DeleteMarker, true);
- versionIds.push(res.VersionId);
- return done();
- });
+ }));
+ assert.strictEqual(res.DeleteMarker, true);
+ versionIds.push(res.VersionId);
});
- it('should get the null version', done => {
- s3.getObject({
+ it('should get the null version', async () => {
+ const res = await s3.send(new GetObjectCommand({
Bucket: bucket,
Key: key,
VersionId: 'null',
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.Body.toString(), 'test-null-version');
- return done();
- });
+ }));
+ const body = await res.Body.transformToString();
+ assert.strictEqual(body, 'test-null-version');
});
- it('should add a delete marker', done => {
- s3.deleteObject({
+ it('should add a delete marker', async () => {
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: key,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.DeleteMarker, true);
- assert.strictEqual(
- versionIds.find(item => item === res.VersionId),
- undefined);
- versionIds.push(res.VersionId);
- return done();
- });
+ }));
+ assert.strictEqual(res.DeleteMarker, true);
+ assert.strictEqual(
+ versionIds.find(item => item === res.VersionId),
+ undefined);
+ versionIds.push(res.VersionId);
});
- it('should set the null version as master', done => {
+ it('should set the null version as master', async () => {
let version = versionIds.pop();
- s3.deleteObject({
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: key,
VersionId: version,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.VersionId, version);
- assert.strictEqual(res.DeleteMarker, true);
- version = versionIds.pop();
- return s3.deleteObject({
- Bucket: bucket,
- Key: key,
- VersionId: version,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.VersionId, version);
- assert.strictEqual(res.DeleteMarker, true);
- return s3.getObject({
- Bucket: bucket,
- Key: key,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.Body.toString(),
- 'test-null-version');
- return done();
- });
- });
- });
+ }));
+ assert.strictEqual(res.VersionId, version);
+ assert.strictEqual(res.DeleteMarker, true);
+
+ version = versionIds.pop();
+ const res2 = await s3.send(new DeleteObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ VersionId: version,
+ }));
+ assert.strictEqual(res2.VersionId, version);
+ assert.strictEqual(res2.DeleteMarker, true);
+
+ const getRes = await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ }));
+ const body = await getRes.Body.transformToString();
+ assert.strictEqual(body, 'test-null-version');
});
- it('should delete null version', done => {
- s3.deleteObject({
+ it('should delete null version', async () => {
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: key,
VersionId: 'null',
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.VersionId, 'null');
- return s3.getObject({
- Bucket: bucket,
- Key: key,
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.VersionId,
- versionIds[versionIds.length - 1]);
- return done();
- });
- });
+ }));
+ assert.strictEqual(res.VersionId, 'null');
+
+ const getRes = await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ }));
+ assert.strictEqual(getRes.VersionId,
+ versionIds[versionIds.length - 1]);
});
- it('should be able to delete the bucket', done => {
- async.eachSeries(versionIds, (id, next) => {
- s3.deleteObject({
+ it('should be able to delete the bucket', async () => {
+ for (const id of versionIds) {
+ const res = await s3.send(new DeleteObjectCommand({
Bucket: bucket,
Key: key,
VersionId: id,
- }, (err, res) => {
- if (err) {
- return next(err);
- }
- assert.strictEqual(res.VersionId, id);
- return next();
- });
- }, err => {
- if (err) {
- return done(err);
- }
- return s3.deleteBucket({ Bucket: bucket }, err => done(err));
- });
+ }));
+ assert.strictEqual(res.VersionId, id);
+ }
+ await s3.send(new DeleteBucketCommand({ Bucket: bucket }));
});
});
});
@@ -687,89 +526,73 @@ describe('aws-node-sdk test concurrent version-specific deletes with null', () =
const bucketUtil = new BucketUtility('default', sigCfg);
const s3 = bucketUtil.s3;
- // setup test
- before(done => {
- s3.createBucket({ Bucket: bucket }, done);
- });
+ before(() => s3.send(new CreateBucketCommand({ Bucket: bucket })));
- // delete bucket after testing
- after(done => {
- removeAllVersions({ Bucket: bucket }, err => {
- if (err && err.code === 'NoSuchBucket') {
- return done();
- } else if (err) {
- return done(err);
+ after(async () => {
+ try {
+ await removeAllVersionsPromise({ Bucket: bucket });
+ await bucketUtil.empty(bucket);
+ await s3.send(new DeleteBucketCommand({ Bucket: bucket }));
+ } catch (err) {
+ if (err.name !== 'NoSuchBucket') {
+ throw err;
}
- return s3.deleteBucket({ Bucket: bucket }, err => {
- assert.strictEqual(err, null,
- `Error deleting bucket: ${err}`);
- return done();
- });
- });
+ }
});
- it('creating non-versioned object', done => {
- s3.putObject({
+ it('creating non-versioned object', async () => {
+ const res = await s3.send(new PutObjectCommand({
Bucket: bucket,
Key: key,
Body: 'null-body',
- }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.equal(res.VersionId, undefined);
- return done();
- });
+ }));
+ assert.equal(res.VersionId, undefined);
});
- it('enable versioning', done => {
+ it('enable versioning', async () => {
const params = {
Bucket: bucket,
VersioningConfiguration: {
Status: 'Enabled',
},
};
- s3.putBucketVersioning(params, done);
- });
-
- it('put 5 new versions to the object', done => {
- async.times(5, (i, putDone) => s3.putObject({
- Bucket: bucket,
- Key: key,
- Body: `test-body-${i}`,
- }, putDone), done);
+ await s3.send(new PutBucketVersioningCommand(params));
});
- it('list versions and batch-delete all except null version', done => {
- s3.listObjectVersions({ Bucket: bucket }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.DeleteMarkers.length, 0);
- assert.strictEqual(res.Versions.length, 6);
- assert.strictEqual(res.Versions[5].VersionId, 'null');
- return s3.deleteObjects({
+ it('put 5 new versions to the object', async () => {
+ const promises = [];
+ for (let i = 0; i < 5; i++) {
+ promises.push(s3.send(new PutObjectCommand({
Bucket: bucket,
- Delete: {
- Objects: res.Versions.slice(0, 5).map(item => ({
- Key: item.Key,
- VersionId: item.VersionId,
- })),
- },
- }, done);
- });
+ Key: key,
+ Body: `test-body-${i}`,
+ })));
+ }
+ await Promise.all(promises);
+ });
+
+ it('list versions and batch-delete all except null version', async () => {
+ const res = await s3.send(new ListObjectVersionsCommand({ Bucket: bucket }));
+ assert.strictEqual(res.DeleteMarkers, undefined);
+ assert.strictEqual(res.Versions.length, 6);
+ assert.strictEqual(res.Versions[5].VersionId, 'null');
+
+ await s3.send(new DeleteObjectsCommand({
+ Bucket: bucket,
+ Delete: {
+ Objects: res.Versions.slice(0, 5).map(item => ({
+ Key: item.Key,
+ VersionId: item.VersionId,
+ })),
+ },
+ }));
});
- it('list versions should return a list with just the null version', done => {
- s3.listObjectVersions({ Bucket: bucket }, (err, res) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(res.DeleteMarkers.length, 0);
- assert.strictEqual(res.Versions.length, 1);
- assert.strictEqual(res.Versions[0].VersionId, 'null');
- return done();
- });
+ it('list versions should return a list with just the null version', async () => {
+ const res = await s3.send(new ListObjectVersionsCommand({ Bucket: bucket }));
+ assert.strictEqual(res.DeleteMarkers, undefined);
+ assert.strictEqual(res.Versions.length, 1);
+ assert.strictEqual(res.Versions[0].VersionId, 'null');
});
});
});
diff --git a/tests/functional/aws-node-sdk/test/versioning/objectDeleteTagging.js b/tests/functional/aws-node-sdk/test/versioning/objectDeleteTagging.js
index e63cee30b9..70d039dc55 100644
--- a/tests/functional/aws-node-sdk/test/versioning/objectDeleteTagging.js
+++ b/tests/functional/aws-node-sdk/test/versioning/objectDeleteTagging.js
@@ -1,5 +1,13 @@
const assert = require('assert');
-const async = require('async');
+const {
+ CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ DeleteObjectCommand,
+ PutObjectTaggingCommand,
+ DeleteObjectTaggingCommand,
+} = require('@aws-sdk/client-s3');
const withV4 = require('../support/withV4');
const BucketUtility = require('../../lib/utility/bucket-util');
@@ -17,8 +25,8 @@ const {
function _checkError(err, code, statusCode) {
assert(err, 'Expected error but found none');
- assert.strictEqual(err.code, code);
- assert.strictEqual(err.statusCode, statusCode);
+ assert.strictEqual(err.name, code);
+ assert.strictEqual(err.$metadata?.httpStatusCode, statusCode);
}
@@ -26,150 +34,184 @@ describe('Delete object tagging with versioning', () => {
withV4(sigCfg => {
const bucketUtil = new BucketUtility('default', sigCfg);
const s3 = bucketUtil.s3;
- beforeEach(done => s3.createBucket({ Bucket: bucketName }, done));
- afterEach(done => {
- removeAllVersions({ Bucket: bucketName }, err => {
- if (err) {
- return done(err);
- }
- return s3.deleteBucket({ Bucket: bucketName }, done);
- });
+
+ beforeEach(async () => {
+ await s3.send(new CreateBucketCommand({ Bucket: bucketName }));
+ });
+
+ afterEach(async () => {
+ await removeAllVersions({ Bucket: bucketName });
+ await bucketUtil.empty(bucketName);
+ await s3.send(new DeleteBucketCommand({ Bucket: bucketName }));
});
- it('should be able to delete tag set with versioning', done => {
- async.waterfall([
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- (err, data) => next(err, data.VersionId)),
- (versionId, next) => s3.putObjectTagging({
- Bucket: bucketName,
- Key: objectName,
- VersionId: versionId,
- Tagging: { TagSet: [
- {
- Key: 'key1',
- Value: 'value1',
- }] },
- }, err => next(err, versionId)),
- (versionId, next) => s3.deleteObjectTagging({
- Bucket: bucketName,
- Key: objectName,
- VersionId: versionId,
- }, (err, data) => next(err, data, versionId)),
- ], (err, data, versionId) => {
- assert.ifError(err, `Found unexpected err ${err}`);
- assert.strictEqual(data.VersionId, versionId);
- done();
- });
+ it('should be able to delete tag set with versioning', async () => {
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled
+ }));
+
+ const putObjectResult = await s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }));
+ const versionId = putObjectResult.VersionId;
+
+ await s3.send(new PutObjectTaggingCommand({
+ Bucket: bucketName,
+ Key: objectName,
+ VersionId: versionId,
+ Tagging: {
+ TagSet: [{
+ Key: 'key1',
+ Value: 'value1',
+ }]
+ },
+ }));
+
+ const deleteResult = await s3.send(new DeleteObjectTaggingCommand({
+ Bucket: bucketName,
+ Key: objectName,
+ VersionId: versionId,
+ }));
+
+ assert.strictEqual(deleteResult.VersionId, versionId);
});
it('should not create version deleting object tags on a ' +
- ' version-enabled bucket where no version id is specified ', done => {
- async.waterfall([
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- (err, data) => next(err, data.VersionId)),
- (versionId, next) => s3.putObjectTagging({
- Bucket: bucketName,
- Key: objectName,
- VersionId: versionId,
- Tagging: { TagSet: [
- {
- Key: 'key1',
- Value: 'value1',
- }] },
- }, err => next(err, versionId)),
- (versionId, next) => s3.deleteObjectTagging({
- Bucket: bucketName,
- Key: objectName,
- }, err => next(err, versionId)),
- (versionId, next) =>
- checkOneVersion(s3, bucketName, versionId, next),
- ], done);
+ ' version-enabled bucket where no version id is specified ', async () => {
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled
+ }));
+
+ const putObjectResult = await s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }));
+ const versionId = putObjectResult.VersionId;
+
+ await s3.send(new PutObjectTaggingCommand({
+ Bucket: bucketName,
+ Key: objectName,
+ VersionId: versionId,
+ Tagging: {
+ TagSet: [{
+ Key: 'key1',
+ Value: 'value1',
+ }]
+ },
+ }));
+
+ await s3.send(new DeleteObjectTaggingCommand({
+ Bucket: bucketName,
+ Key: objectName,
+ }));
+
+ await checkOneVersion(s3, bucketName, versionId);
});
it('should be able to delete tag set with a version of id "null"',
- done => {
- async.waterfall([
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.deleteObjectTagging({
- Bucket: bucketName,
- Key: objectName,
- VersionId: 'null',
- }, (err, data) => next(err, data)),
- ], (err, data) => {
- assert.ifError(err, `Found unexpected err ${err}`);
- assert.strictEqual(data.VersionId, 'null');
- done();
- });
+ async () => {
+ await s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }));
+
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled
+ }));
+
+ const deleteResult = await s3.send(new DeleteObjectTaggingCommand({
+ Bucket: bucketName,
+ Key: objectName,
+ VersionId: 'null',
+ }));
+
+ assert.strictEqual(deleteResult.VersionId, 'null');
});
it('should return InvalidArgument deleting tag set with a non ' +
- 'existing version id', done => {
- async.waterfall([
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.deleteObjectTagging({
+ 'existing version id', async () => {
+ await s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }));
+
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled
+ }));
+
+ try {
+ await s3.send(new DeleteObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
VersionId: invalidId,
- }, (err, data) => next(err, data)),
- ], err => {
+ }));
+ assert.fail('Expected InvalidArgument error');
+ } catch (err) {
_checkError(err, 'InvalidArgument', 400);
- done();
- });
+ }
});
it('should return 405 MethodNotAllowed deleting tag set without ' +
- 'version id if version specified is a delete marker', done => {
- async.waterfall([
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.deleteObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.deleteObjectTagging({
+ 'version id if version specified is a delete marker', async () => {
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled
+ }));
+
+ await s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }));
+
+ await s3.send(new DeleteObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }));
+
+ try {
+ await s3.send(new DeleteObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
- }, (err, data) => next(err, data)),
- ], err => {
+ }));
+ assert.fail('Expected MethodNotAllowed error');
+ } catch (err) {
_checkError(err, 'MethodNotAllowed', 405);
- done();
- });
+ }
});
it('should return 405 MethodNotAllowed deleting tag set with ' +
- 'version id if version specified is a delete marker', done => {
- async.waterfall([
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.deleteObject({ Bucket: bucketName, Key: objectName },
- (err, data) => next(err, data.VersionId)),
- (versionId, next) => s3.deleteObjectTagging({
+ 'version id if version specified is a delete marker', async () => {
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled
+ }));
+
+ await s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }));
+
+ const deleteResult = await s3.send(new DeleteObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }));
+ const versionId = deleteResult.VersionId;
+
+ try {
+ await s3.send(new DeleteObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
VersionId: versionId,
- }, (err, data) => next(err, data)),
- ], err => {
+ }));
+ assert.fail('Expected MethodNotAllowed error');
+ } catch (err) {
_checkError(err, 'MethodNotAllowed', 405);
- done();
- });
+ }
});
});
});
diff --git a/tests/functional/aws-node-sdk/test/versioning/objectGet.js b/tests/functional/aws-node-sdk/test/versioning/objectGet.js
index 605e3b1ee7..32eb7f4805 100644
--- a/tests/functional/aws-node-sdk/test/versioning/objectGet.js
+++ b/tests/functional/aws-node-sdk/test/versioning/objectGet.js
@@ -1,5 +1,4 @@
const assert = require('assert');
-const async = require('async');
const withV4 = require('../support/withV4');
const BucketUtility = require('../../lib/utility/bucket-util');
@@ -9,6 +8,14 @@ const {
versioningEnabled,
versioningSuspended,
} = require('../../lib/utility/versioning-util.js');
+const { CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ GetObjectCommand,
+ DeleteObjectCommand,
+ PutObjectTaggingCommand
+ } = require('@aws-sdk/client-s3');
const key = 'objectKey';
// formats differ for AWS and S3, use respective sample ids to obtain
@@ -17,15 +24,11 @@ const nonExistingId = process.env.AWS_ON_AIR ?
'MhhyTHhmZ4cxSi4Y9SMe5P7UJAz7HLJ9' :
'3939393939393939393936493939393939393939756e6437';
-function _assertNoError(err, desc) {
- assert.ifError(err, `Unexpected err ${desc}: ${err}`);
-}
-
function _assertError(err, statusCode, code) {
assert.notEqual(err, null,
'Expected failure but got success');
- assert.strictEqual(err.code, code);
- assert.strictEqual(err.statusCode, statusCode);
+ assert.strictEqual(err.name, code);
+ assert.strictEqual(err.$metadata.httpStatusCode, statusCode);
}
@@ -34,192 +37,184 @@ describe('get behavior on versioning-enabled bucket', () => {
const bucketUtil = new BucketUtility('default', sigCfg);
const s3 = bucketUtil.s3;
let bucket;
+ let versionId;
- beforeEach(done => {
+ beforeEach(async () => {
bucket = `versioning-bucket-${Date.now()}`;
- s3.createBucket({ Bucket: bucket }, err => {
- _assertNoError(err, 'createBucket');
- return s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningEnabled,
- }, done);
- });
+ await s3.send(new CreateBucketCommand({ Bucket: bucket }));
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningEnabled,
+ }));
});
- afterEach(done => {
- removeAllVersions({ Bucket: bucket }, err => {
- _assertNoError(err, 'removeAllVersions');
- return s3.deleteBucket({ Bucket: bucket }, done);
- });
+ afterEach(async () => {
+ await removeAllVersions({ Bucket: bucket });
+ await bucketUtil.empty(bucket);
+ await s3.send(new DeleteBucketCommand({ Bucket: bucket }));
});
describe('behavior when only version put is a regular version', () => {
- beforeEach(function beforeEachF(done) {
- s3.putObject({ Bucket: bucket, Key: key }, (err, data) => {
- _assertNoError(err, 'putObject');
- this.currentTest.versionId = data.VersionId;
- done();
- });
+ beforeEach(async () => {
+ const data = await s3.send(new PutObjectCommand({ Bucket: bucket, Key: key }));
+ versionId = data.VersionId;
});
- it('should be able to get the object version', function itF(done) {
- s3.getObject({
+ it('should be able to get the object version', async () => {
+ const data = await s3.send(new GetObjectCommand({
Bucket: bucket,
Key: key,
- VersionId: this.test.versionId,
- }, (err, data) => {
- assert.ifError(err);
- assert.strictEqual(data.ContentLength, 0);
- done();
- });
+ VersionId: versionId,
+ }));
+ assert.strictEqual(data.ContentLength, 0);
});
- it('it should return NoSuchVersion if try to get a non-existing object version', done => {
- s3.getObject({
- Bucket: bucket,
- Key: key,
- VersionId: nonExistingId,
- },
- err => {
+ it('it should return NoSuchVersion if try to get a non-existing object version', async () => {
+ try {
+ await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ VersionId: nonExistingId,
+ }));
+ assert.fail('Expected NoSuchVersion error but got success');
+ } catch (err) {
_assertError(err, 404, 'NoSuchVersion');
- done();
- });
+ }
});
- it('it should return NoSuchVersion if try to get a non-existing null version', done => {
- s3.getObject({
- Bucket: bucket,
- Key: key,
- VersionId: 'null',
- },
- err => {
+ it('it should return NoSuchVersion if try to get a non-existing null version', async () => {
+ try {
+ await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ VersionId: 'null',
+ }));
+ assert.fail('Expected NoSuchVersion error but got success');
+ } catch (err) {
_assertError(err, 404, 'NoSuchVersion');
- done();
- });
+ }
});
- it('it should return NoSuchVersion if try to get a deleted noncurrent null version', done => {
- async.series([
- next => s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningSuspended,
- }, next),
- next => s3.putObject({ Bucket: bucket, Key: key }, next),
- next => s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningEnabled,
- }, next),
- next => s3.putObject({ Bucket: bucket, Key: key }, next),
- next => s3.deleteObject({ Bucket: bucket, Key: key, VersionId: 'null' }, next),
- next => s3.getObject({
+ it('it should return NoSuchVersion if try to get a deleted noncurrent null version', async () => {
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningSuspended,
+ }));
+ await s3.send(new PutObjectCommand({ Bucket: bucket, Key: key }));
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningEnabled,
+ }));
+ await s3.send(new PutObjectCommand({ Bucket: bucket, Key: key }));
+ await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key, VersionId: 'null' }));
+
+ try {
+ await s3.send(new GetObjectCommand({
Bucket: bucket,
Key: key,
VersionId: 'null',
- }, err => {
- _assertError(err, 404, 'NoSuchVersion');
- next();
- }),
- ], done);
+ }));
+ assert.fail('Expected NoSuchVersion error but got success');
+ } catch (err) {
+ _assertError(err, 404, 'NoSuchVersion');
+ }
});
});
describe('behavior when only version put is a delete marker', () => {
- beforeEach(function beforeEachF(done) {
- s3.deleteObject({ Bucket: bucket, Key: key },
- (err, data) => {
- _assertNoError(err, 'deleteObject');
- this.currentTest.deleteVersionId = data.VersionId;
- done(err);
- });
+ let deleteVersionId;
+
+ beforeEach(async () => {
+ const deleteResult = await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
+ deleteVersionId = deleteResult.VersionId;
});
- it('should not be able to get a delete marker', function itF(done) {
- s3.getObject({
- Bucket: bucket,
- Key: key,
- VersionId: this.test.deleteVersionId,
- }, function test1(err) {
+ it('should not be able to get a delete marker', async () => {
+ try {
+ await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ VersionId: deleteVersionId,
+ }));
+ assert.fail('Expected MethodNotAllowed error but got success');
+ } catch (err) {
_assertError(err, 405, 'MethodNotAllowed');
- const headers = this.httpResponse.headers;
+ // Note: In AWS SDK v3, response headers are accessible through err.$response
+ const headers = err.$response?.headers || {};
assert.strictEqual(headers['x-amz-delete-marker'], 'true');
- done();
- });
+ }
});
it('it should return NoSuchKey if try to get object whose ' +
- 'latest version is a delete marker', done => {
- s3.getObject({
- Bucket: bucket,
- Key: key,
- }, function test2(err) {
+ 'latest version is a delete marker', async () => {
+ try {
+ await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ }));
+ assert.fail('Expected NoSuchKey error but got success');
+ } catch (err) {
_assertError(err, 404, 'NoSuchKey');
- const headers = this.httpResponse.headers;
- assert.strictEqual(headers['x-amz-delete-marker'], 'true');
- done();
- });
+ }
});
});
describe('behavior when put version with content then put delete ' +
'marker', () => {
- beforeEach(function beforeEachF(done) {
- s3.putObject({ Bucket: bucket, Key: key }, (err, data) => {
- _assertNoError(err, 'putObject');
- this.currentTest.versionId = data.VersionId;
- s3.deleteObject({ Bucket: bucket, Key: key },
- (err, data) => {
- _assertNoError(err, 'deleteObject');
- this.currentTest.deleteVersionId = data.VersionId;
- done(err);
- });
- });
+ let putVersionId;
+ let deleteVersionId;
+
+ beforeEach(async () => {
+ const putResult = await s3.send(new PutObjectCommand({ Bucket: bucket, Key: key }));
+ putVersionId = putResult.VersionId;
+ const deleteResult = await s3.send(new DeleteObjectCommand({ Bucket: bucket, Key: key }));
+ deleteVersionId = deleteResult.VersionId;
});
- it('should not be able to get a delete marker', function itF(done) {
- s3.getObject({
- Bucket: bucket,
- Key: key,
- VersionId: this.test.deleteVersionId,
- }, function test3(err) {
+ it('should not be able to get a delete marker', async () => {
+ try {
+ await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ VersionId: deleteVersionId,
+ }));
+ assert.fail('Expected MethodNotAllowed error but got success');
+ } catch (err) {
_assertError(err, 405, 'MethodNotAllowed');
- const headers = this.httpResponse.headers;
- assert.strictEqual(headers['x-amz-delete-marker'], 'true');
- done();
- });
+ }
});
it('should be able to get a version that was put prior to the ' +
- 'delete marker', function itF(done) {
- s3.getObject({
+ 'delete marker', async () => {
+ const data = await s3.send(new GetObjectCommand({
Bucket: bucket,
Key: key,
- VersionId: this.test.versionId },
- (err, data) => {
- _assertNoError(err, 'getObject');
- assert.strictEqual(data.VersionId, this.test.versionId);
- done();
- });
+ VersionId: putVersionId
+ }));
+ assert.strictEqual(data.VersionId, putVersionId);
});
it('should return NoSuchKey if get object without version and ' +
'latest version is a delete marker',
- done => {
- s3.getObject({
- Bucket: bucket,
- Key: key,
- }, function test4(err) {
+ async () => {
+ try {
+ await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ }));
+ assert.fail('Expected NoSuchKey error but got success');
+ } catch (err) {
_assertError(err, 404, 'NoSuchKey');
- const headers = this.httpResponse.headers;
- assert.strictEqual(headers['x-amz-delete-marker'], 'true');
- done();
- });
+ }
});
});
describe('x-amz-tagging-count with versioning', () => {
let params;
let paramsTagging;
- beforeEach(function beforeEach(done) {
+ let objectVersionId;
+
+ beforeEach(async () => {
params = {
Bucket: bucket,
Key: key,
@@ -236,44 +231,33 @@ describe('get behavior on versioning-enabled bucket', () => {
],
},
};
- s3.putObject(params, (err, data) => {
- if (err) {
- return done(err);
- }
- this.currentTest.versionId = data.VersionId;
- return done();
- });
+ const data = await s3.send(new PutObjectCommand(params));
+ objectVersionId = data.VersionId;
});
it('should not return "x-amz-tagging-count" if no tag ' +
'associated with the object',
- function itF(done) {
- params.VersionId = this.test.VersionId;
- s3.getObject(params, (err, data) => {
- if (err) {
- return done(err);
- }
- assert.strictEqual(data.TagCount, undefined);
- return done();
- });
+ async () => {
+ params.VersionId = objectVersionId;
+ const data = await s3.send(new GetObjectCommand(params));
+ assert.strictEqual(data.TagCount, undefined);
});
describe('tag associated with the object ', () => {
- beforeEach(done => s3.putObjectTagging(paramsTagging, done));
+ beforeEach(async () => {
+ paramsTagging.VersionId = objectVersionId;
+ await s3.send(new PutObjectTaggingCommand(paramsTagging));
+ });
it('should return "x-amz-tagging-count" header that provides ' +
'the count of number of tags associated with the object',
- function itF(done) {
- params.VersionId = this.test.VersionId;
- s3.getObject(params, (err, data) => {
- if (err) {
- return done(err);
- }
- assert.equal(data.TagCount, 1);
- return done();
- });
+ async () => {
+ params.VersionId = objectVersionId;
+ const data = await s3.send(new GetObjectCommand(params));
+ assert.equal(data.TagCount, 1);
});
});
});
});
});
+
diff --git a/tests/functional/aws-node-sdk/test/versioning/objectGetTagging.js b/tests/functional/aws-node-sdk/test/versioning/objectGetTagging.js
index 7cd42350ac..28c8559ca8 100644
--- a/tests/functional/aws-node-sdk/test/versioning/objectGetTagging.js
+++ b/tests/functional/aws-node-sdk/test/versioning/objectGetTagging.js
@@ -1,5 +1,15 @@
const assert = require('assert');
const async = require('async');
+const { promisify } = require('util');
+const {
+ CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ PutObjectTaggingCommand,
+ GetObjectTaggingCommand,
+ DeleteObjectCommand,
+} = require('@aws-sdk/client-s3');
const withV4 = require('../support/withV4');
const BucketUtility = require('../../lib/utility/bucket-util');
@@ -9,6 +19,7 @@ const {
versioningEnabled,
} = require('../../lib/utility/versioning-util');
+const removeAllVersionsPromise = promisify(removeAllVersions);
const bucketName = 'testtaggingbucket';
const objectName = 'testtaggingobject';
@@ -16,23 +27,21 @@ const invalidId = 'invalidIdWithMoreThan40BytesAndThatIsNotLongEnoughYet';
function _checkError(err, code, statusCode) {
assert(err, 'Expected error but found none');
- assert.strictEqual(err.code, code);
- assert.strictEqual(err.statusCode, statusCode);
+ assert.strictEqual(err.name, code);
+ assert.strictEqual(err.$metadata?.httpStatusCode, statusCode);
}
-
describe('Get object tagging with versioning', () => {
withV4(sigCfg => {
const bucketUtil = new BucketUtility('default', sigCfg);
const s3 = bucketUtil.s3;
- beforeEach(done => s3.createBucket({ Bucket: bucketName }, done));
- afterEach(done => {
- removeAllVersions({ Bucket: bucketName }, err => {
- if (err) {
- return done(err);
- }
- return s3.deleteBucket({ Bucket: bucketName }, done);
- });
+
+ beforeEach(() => s3.send(new CreateBucketCommand({ Bucket: bucketName })));
+
+ afterEach(async () => {
+ await removeAllVersionsPromise({ Bucket: bucketName });
+ await bucketUtil.empty(bucketName);
+ await s3.send(new DeleteBucketCommand({ Bucket: bucketName }));
});
it('should be able to get tag with versioning', done => {
@@ -42,22 +51,28 @@ describe('Get object tagging with versioning', () => {
Value: 'value1',
}] };
async.waterfall([
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- (err, data) => next(err, data.VersionId)),
- (versionId, next) => s3.putObjectTagging({
+ next => s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled,
+ })).then(() => next()).catch(next),
+
+ next => s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName,
+ })).then(data => next(null, data.VersionId)).catch(next),
+
+ (versionId, next) => s3.send(new PutObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
VersionId: versionId,
Tagging: taggingConfig,
- }, err => next(err, versionId)),
- (versionId, next) => s3.getObjectTagging({
+ })).then(() => next(null, versionId)).catch(next),
+
+ (versionId, next) => s3.send(new GetObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
VersionId: versionId,
- }, (err, data) => next(err, data, versionId)),
+ })).then(data => next(null, data, versionId)).catch(next),
], (err, data, versionId) => {
assert.ifError(err, `Found unexpected err ${err}`);
assert.strictEqual(data.VersionId, versionId);
@@ -68,16 +83,21 @@ describe('Get object tagging with versioning', () => {
it('should be able to get tag with a version of id "null"', done => {
async.waterfall([
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.getObjectTagging({
+ next => s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName,
+ })).then(() => next()).catch(next),
+
+ next => s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled,
+ })).then(() => next()).catch(next),
+
+ next => s3.send(new GetObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
VersionId: 'null',
- }, (err, data) => next(err, data)),
+ })).then(data => next(null, data)).catch(next),
], (err, data) => {
assert.ifError(err, `Found unexpected err ${err}`);
assert.strictEqual(data.VersionId, 'null');
@@ -88,16 +108,21 @@ describe('Get object tagging with versioning', () => {
it('should return InvalidArgument getting tag with a non existing ' +
'version id', done => {
async.waterfall([
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.getObjectTagging({
+ next => s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName,
+ })).then(() => next()).catch(next),
+
+ next => s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled,
+ })).then(() => next()).catch(next),
+
+ next => s3.send(new GetObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
VersionId: invalidId,
- }, (err, data) => next(err, data)),
+ })).then(data => next(null, data)).catch(next),
], err => {
_checkError(err, 'InvalidArgument', 400);
done();
@@ -107,17 +132,25 @@ describe('Get object tagging with versioning', () => {
it('should return 404 NoSuchKey getting tag without ' +
'version id if version specified is a delete marker', done => {
async.waterfall([
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.deleteObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.getObjectTagging({
+ next => s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled,
+ })).then(() => next()).catch(next),
+
+ next => s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName,
+ })).then(() => next()).catch(next),
+
+ next => s3.send(new DeleteObjectCommand({
+ Bucket: bucketName,
+ Key: objectName,
+ })).then(() => next()).catch(next),
+
+ next => s3.send(new GetObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
- }, (err, data) => next(err, data)),
+ })).then(data => next(null, data)).catch(next),
], err => {
_checkError(err, 'NoSuchKey', 404);
done();
@@ -127,18 +160,26 @@ describe('Get object tagging with versioning', () => {
it('should return 405 MethodNotAllowed getting tag with ' +
'version id if version specified is a delete marker', done => {
async.waterfall([
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.deleteObject({ Bucket: bucketName, Key: objectName },
- (err, data) => next(err, data.VersionId)),
- (versionId, next) => s3.getObjectTagging({
+ next => s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled,
+ })).then(() => next()).catch(next),
+
+ next => s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName,
+ })).then(() => next()).catch(next),
+
+ next => s3.send(new DeleteObjectCommand({
+ Bucket: bucketName,
+ Key: objectName,
+ })).then(data => next(null, data.VersionId)).catch(next),
+
+ (versionId, next) => s3.send(new GetObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
VersionId: versionId,
- }, (err, data) => next(err, data)),
+ })).then(data => next(null, data)).catch(next),
], err => {
_checkError(err, 'MethodNotAllowed', 405);
done();
diff --git a/tests/functional/aws-node-sdk/test/versioning/objectHead.js b/tests/functional/aws-node-sdk/test/versioning/objectHead.js
index 2ff2af0934..df8e448533 100644
--- a/tests/functional/aws-node-sdk/test/versioning/objectHead.js
+++ b/tests/functional/aws-node-sdk/test/versioning/objectHead.js
@@ -1,5 +1,14 @@
const assert = require('assert');
const async = require('async');
+const { promisify } = require('util');
+
+const {
+ CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ HeadObjectCommand,
+} = require('@aws-sdk/client-s3');
const withV4 = require('../support/withV4');
const BucketUtility = require('../../lib/utility/bucket-util');
@@ -10,6 +19,7 @@ const {
versioningSuspended,
} = require('../../lib/utility/versioning-util.js');
+const removeAllVersionsPromise = promisify(removeAllVersions);
const data = ['foo1', 'foo2'];
const counter = 100;
let bucket;
@@ -19,7 +29,6 @@ function _assertNoError(err, desc) {
assert.strictEqual(err, null, `Unexpected err ${desc}: ${err}`);
}
-
// Same tests as objectPut versioning tests, but head object instead of get
describe('put and head object with versioning', function testSuite() {
this.timeout(600000);
@@ -28,69 +37,75 @@ describe('put and head object with versioning', function testSuite() {
const bucketUtil = new BucketUtility('default', sigCfg);
const s3 = bucketUtil.s3;
- beforeEach(done => {
+ beforeEach(async () => {
bucket = `versioning-bucket-${Date.now()}`;
- s3.createBucket({ Bucket: bucket }, done);
+ await s3.send(new CreateBucketCommand({ Bucket: bucket }));
});
- afterEach(done => {
- removeAllVersions({ Bucket: bucket }, err => {
- if (err) {
- return done(err);
- }
- return s3.deleteBucket({ Bucket: bucket }, done);
- });
+ afterEach(async () => {
+ await removeAllVersionsPromise({ Bucket: bucket });
+ await bucketUtil.empty(bucket, true);
+ await s3.send(new DeleteBucketCommand({ Bucket: bucket }));
});
it('should put and head a non-versioned object without including ' +
'version ids in response headers', done => {
const params = { Bucket: bucket, Key: key };
- s3.putObject(params, (err, data) => {
- _assertNoError(err, 'putting object');
- assert.strictEqual(data.VersionId, undefined);
- s3.headObject(params, (err, data) => {
- _assertNoError(err, 'heading object');
+ s3.send(new PutObjectCommand(params))
+ .then(data => {
+ _assertNoError(null, 'putting object');
+ assert.strictEqual(data.VersionId, undefined);
+ return s3.send(new HeadObjectCommand(params));
+ })
+ .then(data => {
+ _assertNoError(null, 'heading object');
assert.strictEqual(data.VersionId, undefined);
done();
- });
- });
+ })
+ .catch(done);
});
it('version-specific head should still not return version id in ' +
'response header', done => {
const params = { Bucket: bucket, Key: key };
- s3.putObject(params, (err, data) => {
- _assertNoError(err, 'putting object');
- assert.strictEqual(data.VersionId, undefined);
- params.VersionId = 'null';
- s3.headObject(params, (err, data) => {
- _assertNoError(err, 'heading specific version "null"');
+ s3.send(new PutObjectCommand(params))
+ .then(data => {
+ _assertNoError(null, 'putting object');
+ assert.strictEqual(data.VersionId, undefined);
+ params.VersionId = 'null';
+ return s3.send(new HeadObjectCommand(params));
+ })
+ .then(data => {
+ _assertNoError(null, 'heading specific version "null"');
assert.strictEqual(data.VersionId, undefined);
done();
- });
- });
+ })
+ .catch(done);
});
describe('on a version-enabled bucket', () => {
- beforeEach(done => {
- s3.putBucketVersioning({
+ beforeEach(async () => {
+ await s3.send(new PutBucketVersioningCommand({
Bucket: bucket,
VersioningConfiguration: versioningEnabled,
- }, done);
+ }));
});
it('should create a new version for an object', done => {
const params = { Bucket: bucket, Key: key };
- s3.putObject(params, (err, data) => {
- _assertNoError(err, 'putting object');
- params.VersionId = data.VersionId;
- s3.headObject(params, (err, data) => {
- _assertNoError(err, 'heading object');
+ s3.send(new PutObjectCommand(params))
+ .then(data => {
+ _assertNoError(null, 'putting object');
+ params.VersionId = data.VersionId;
+ return s3.send(new HeadObjectCommand(params));
+ })
+ .then(data => {
+ _assertNoError(null, 'heading object');
assert.strictEqual(params.VersionId, data.VersionId,
'version ids are not equal');
done();
- });
- });
+ })
+ .catch(done);
});
});
@@ -98,17 +113,20 @@ describe('put and head object with versioning', function testSuite() {
const eTags = [];
beforeEach(done => {
- s3.putObject({ Bucket: bucket, Key: key, Body: data[0] },
- (err, data) => {
- if (err) {
- done(err);
- }
+ s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: data[0]
+ }))
+ .then(data => {
eTags.push(data.ETag);
- s3.putBucketVersioning({
+ return s3.send(new PutBucketVersioningCommand({
Bucket: bucket,
VersioningConfiguration: versioningEnabled,
- }, done);
- });
+ }));
+ })
+ .then(() => done())
+ .catch(done);
});
afterEach(done => {
@@ -121,35 +139,47 @@ describe('put and head object with versioning', function testSuite() {
done => {
const paramsNull = {
Bucket: bucket,
- Key: '/', VersionId:
- 'null',
+ Key: '/',
+ VersionId: 'null',
};
- s3.headObject(paramsNull, err => {
- _assertNoError(err, 'heading null version');
- done();
- });
+ s3.send(new HeadObjectCommand(paramsNull))
+ .then(() => {
+ _assertNoError(null, 'heading null version');
+ done();
+ })
+ .catch(done);
});
it('should keep null version and create a new version', done => {
const params = { Bucket: bucket, Key: key, Body: data[1] };
- s3.putObject(params, (err, data) => {
- const newVersion = data.VersionId;
- eTags.push(data.ETag);
- s3.headObject({ Bucket: bucket, Key: key,
- VersionId: newVersion }, (err, data) => {
- assert.strictEqual(err, null);
+ let newVersion;
+ s3.send(new PutObjectCommand(params))
+ .then(data => {
+ newVersion = data.VersionId;
+ eTags.push(data.ETag);
+ return s3.send(new HeadObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ VersionId: newVersion
+ }));
+ })
+ .then(data => {
assert.strictEqual(data.VersionId, newVersion,
'version ids are not equal');
assert.strictEqual(data.ETag, eTags[1]);
- s3.headObject({ Bucket: bucket, Key: key,
- VersionId: 'null' }, (err, data) => {
- _assertNoError(err, 'heading null version');
- assert.strictEqual(data.VersionId, 'null');
- assert.strictEqual(data.ETag, eTags[0]);
- done();
- });
- });
- });
+ return s3.send(new HeadObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ VersionId: 'null'
+ }));
+ })
+ .then(data => {
+ _assertNoError(null, 'heading null version');
+ assert.strictEqual(data.VersionId, 'null');
+ assert.strictEqual(data.ETag, eTags[0]);
+ done();
+ })
+ .catch(done);
});
it('should create new versions but still keep nullVersionId',
@@ -158,51 +188,58 @@ describe('put and head object with versioning', function testSuite() {
const params = { Bucket: bucket, Key: key };
const paramsNull = {
Bucket: bucket,
- Key: '/', VersionId:
- 'null',
+ Key: '/',
+ VersionId: 'null',
};
// create new versions
- async.timesSeries(counter, (i, next) => s3.putObject(params,
- (err, data) => {
- versionIds.push(data.VersionId);
- // head the 'null' version
- s3.headObject(paramsNull, (err, nullVerData) => {
- assert.strictEqual(err, null);
+ async.timesSeries(counter, (i, next) => {
+ s3.send(new PutObjectCommand(params))
+ .then(data => {
+ versionIds.push(data.VersionId);
+ // head the 'null' version
+ return s3.send(new HeadObjectCommand(paramsNull));
+ })
+ .then(nullVerData => {
assert.strictEqual(nullVerData.ETag, eTags[0]);
assert.strictEqual(nullVerData.VersionId, 'null');
- next(err);
- });
- }), done);
+ next();
+ })
+ .catch(next);
+ }, done);
});
});
describe('on version-suspended bucket', () => {
- beforeEach(done => {
- s3.putBucketVersioning({
+ beforeEach(async () => {
+ await s3.send(new PutBucketVersioningCommand({
Bucket: bucket,
VersioningConfiguration: versioningSuspended,
- }, done);
+ }));
});
it('should not return version id for new object', done => {
const params = { Bucket: bucket, Key: key, Body: 'foo' };
const paramsNull = {
Bucket: bucket,
- Key: '/', VersionId:
- 'null',
+ Key: '/',
+ VersionId: 'null',
};
- s3.putObject(params, (err, data) => {
- const eTag = data.ETag;
- _assertNoError(err, 'putting object');
- assert.strictEqual(data.VersionId, undefined);
- // heading null version should return object we just put
- s3.headObject(paramsNull, (err, nullVerData) => {
- _assertNoError(err, 'heading null version');
+ let eTag;
+ s3.send(new PutObjectCommand(params))
+ .then(data => {
+ eTag = data.ETag;
+ _assertNoError(null, 'putting object');
+ assert.strictEqual(data.VersionId, undefined);
+ // heading null version should return object we just put
+ return s3.send(new HeadObjectCommand(paramsNull));
+ })
+ .then(nullVerData => {
+ _assertNoError(null, 'heading null version');
assert.strictEqual(nullVerData.ETag, eTag);
assert.strictEqual(nullVerData.VersionId, 'null');
done();
- });
- });
+ })
+ .catch(done);
});
it('should update null version if put object twice', done => {
@@ -211,37 +248,45 @@ describe('put and head object with versioning', function testSuite() {
const params2 = { Bucket: bucket, Key: key, Body: data[1] };
const paramsNull = {
Bucket: bucket,
- Key: '/', VersionId:
- 'null',
+ Key: '/',
+ VersionId: 'null',
};
const eTags = [];
async.waterfall([
- callback => s3.putObject(params1, (err, data) => {
- _assertNoError(err, 'putting first object');
- assert.strictEqual(data.VersionId, undefined);
- eTags.push(data.ETag);
- callback();
- }),
- callback => s3.headObject(params, (err, data) => {
- _assertNoError(err, 'heading master version');
- assert.strictEqual(data.VersionId, 'null');
- assert.strictEqual(data.ETag, eTags[0],
- 'wrong object data');
- callback();
- }),
- callback => s3.putObject(params2, (err, data) => {
- _assertNoError(err, 'putting second object');
- assert.strictEqual(data.VersionId, undefined);
- eTags.push(data.ETag);
- callback();
- }),
- callback => s3.headObject(paramsNull, (err, data) => {
- _assertNoError(err, 'heading null version');
- assert.strictEqual(data.VersionId, 'null');
- assert.strictEqual(data.ETag, eTags[1],
- 'wrong object data');
- callback();
- }),
+ callback => s3.send(new PutObjectCommand(params1))
+ .then(data => {
+ _assertNoError(null, 'putting first object');
+ assert.strictEqual(data.VersionId, undefined);
+ eTags.push(data.ETag);
+ callback();
+ })
+ .catch(callback),
+ callback => s3.send(new HeadObjectCommand(params))
+ .then(data => {
+ _assertNoError(null, 'heading master version');
+ assert.strictEqual(data.VersionId, 'null');
+ assert.strictEqual(data.ETag, eTags[0],
+ 'wrong object data');
+ callback();
+ })
+ .catch(callback),
+ callback => s3.send(new PutObjectCommand(params2))
+ .then(data => {
+ _assertNoError(null, 'putting second object');
+ assert.strictEqual(data.VersionId, undefined);
+ eTags.push(data.ETag);
+ callback();
+ })
+ .catch(callback),
+ callback => s3.send(new HeadObjectCommand(paramsNull))
+ .then(data => {
+ _assertNoError(null, 'heading null version');
+ assert.strictEqual(data.VersionId, 'null');
+ assert.strictEqual(data.ETag, eTags[1],
+ 'wrong object data');
+ callback();
+ })
+ .catch(callback),
], done);
});
});
@@ -251,17 +296,20 @@ describe('put and head object with versioning', function testSuite() {
const eTags = [];
beforeEach(done => {
- s3.putObject({ Bucket: bucket, Key: key, Body: data[0] },
- (err, data) => {
- if (err) {
- done(err);
- }
+ s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: data[0]
+ }))
+ .then(data => {
eTags.push(data.ETag);
- s3.putBucketVersioning({
+ return s3.send(new PutBucketVersioningCommand({
Bucket: bucket,
VersioningConfiguration: versioningSuspended,
- }, done);
- });
+ }));
+ })
+ .then(() => done())
+ .catch(done);
});
afterEach(done => {
@@ -274,13 +322,15 @@ describe('put and head object with versioning', function testSuite() {
done => {
const paramsNull = {
Bucket: bucket,
- Key: '/', VersionId:
- 'null',
+ Key: '/',
+ VersionId: 'null',
};
- s3.headObject(paramsNull, err => {
- _assertNoError(err, 'heading null version');
- done();
- });
+ s3.send(new HeadObjectCommand(paramsNull))
+ .then(() => {
+ _assertNoError(null, 'heading null version');
+ done();
+ })
+ .catch(done);
});
it('should update null version in versioning suspended bucket',
@@ -289,35 +339,43 @@ describe('put and head object with versioning', function testSuite() {
const putParams = { Bucket: bucket, Key: '/', Body: data[1] };
const paramsNull = {
Bucket: bucket,
- Key: '/', VersionId:
- 'null',
+ Key: '/',
+ VersionId: 'null',
};
async.waterfall([
- callback => s3.headObject(paramsNull, (err, data) => {
- _assertNoError(err, 'heading null version');
- assert.strictEqual(data.VersionId, 'null');
- callback();
- }),
- callback => s3.putObject(putParams, (err, data) => {
- _assertNoError(err, 'putting object');
- assert.strictEqual(data.VersionId, undefined);
- eTags.push(data.ETag);
- callback();
- }),
- callback => s3.headObject(paramsNull, (err, data) => {
- _assertNoError(err, 'heading null version');
- assert.strictEqual(data.VersionId, 'null');
- assert.strictEqual(data.ETag, eTags[1],
- 'wrong object data');
- callback();
- }),
- callback => s3.headObject(params, (err, data) => {
- _assertNoError(err, 'heading master version');
- assert.strictEqual(data.VersionId, 'null');
- assert.strictEqual(data.ETag, eTags[1],
- 'wrong object data');
- callback();
- }),
+ callback => s3.send(new HeadObjectCommand(paramsNull))
+ .then(data => {
+ _assertNoError(null, 'heading null version');
+ assert.strictEqual(data.VersionId, 'null');
+ callback();
+ })
+ .catch(callback),
+ callback => s3.send(new PutObjectCommand(putParams))
+ .then(data => {
+ _assertNoError(null, 'putting object');
+ assert.strictEqual(data.VersionId, undefined);
+ eTags.push(data.ETag);
+ callback();
+ })
+ .catch(callback),
+ callback => s3.send(new HeadObjectCommand(paramsNull))
+ .then(data => {
+ _assertNoError(null, 'heading null version');
+ assert.strictEqual(data.VersionId, 'null');
+ assert.strictEqual(data.ETag, eTags[1],
+ 'wrong object data');
+ callback();
+ })
+ .catch(callback),
+ callback => s3.send(new HeadObjectCommand(params))
+ .then(data => {
+ _assertNoError(null, 'heading master version');
+ assert.strictEqual(data.VersionId, 'null');
+ assert.strictEqual(data.ETag, eTags[1],
+ 'wrong object data');
+ callback();
+ })
+ .catch(callback),
], done);
});
});
@@ -328,21 +386,24 @@ describe('put and head object with versioning', function testSuite() {
beforeEach(done => {
const params = { Bucket: bucket, Key: key, Body: data[0] };
async.waterfall([
- callback => s3.putBucketVersioning({
+ callback => s3.send(new PutBucketVersioningCommand({
Bucket: bucket,
VersioningConfiguration: versioningSuspended,
- }, err => callback(err)),
- callback => s3.putObject(params, (err, data) => {
- if (err) {
- callback(err);
- }
- eTags.push(data.ETag);
- callback();
- }),
- callback => s3.putBucketVersioning({
+ }))
+ .then(() => callback())
+ .catch(callback),
+ callback => s3.send(new PutObjectCommand(params))
+ .then(data => {
+ eTags.push(data.ETag);
+ callback();
+ })
+ .catch(callback),
+ callback => s3.send(new PutBucketVersioningCommand({
Bucket: bucket,
VersioningConfiguration: versioningEnabled,
- }, callback),
+ }))
+ .then(() => callback())
+ .catch(callback),
], done);
});
@@ -357,27 +418,34 @@ describe('put and head object with versioning', function testSuite() {
const params = { Bucket: bucket, Key: key };
const paramsNull = {
Bucket: bucket,
- Key: '/', VersionId:
- 'null',
+ Key: '/',
+ VersionId: 'null',
};
async.waterfall([
- cb => s3.headObject(paramsNull, (err, nullVerData) => {
- _assertNoError(err, 'heading null version');
- assert.strictEqual(nullVerData.ETag, eTags[0]);
- assert.strictEqual(nullVerData.VersionId, 'null');
- cb();
- }),
+ cb => s3.send(new HeadObjectCommand(paramsNull))
+ .then(nullVerData => {
+ _assertNoError(null, 'heading null version');
+ assert.strictEqual(nullVerData.ETag, eTags[0]);
+ assert.strictEqual(nullVerData.VersionId, 'null');
+ cb();
+ })
+ .catch(cb),
cb => async.timesSeries(counter, (i, next) =>
- s3.putObject(params, (err, data) => {
- _assertNoError(err, `putting object #${i}`);
- assert.notEqual(data.VersionId, undefined);
- next();
- }), err => cb(err)),
- cb => s3.headObject(paramsNull, (err, nullVerData) => {
- _assertNoError(err, 'heading null version');
- assert.strictEqual(nullVerData.ETag, eTags[0]);
- cb();
- }),
+ s3.send(new PutObjectCommand(params))
+ .then(data => {
+ _assertNoError(null, `putting object #${i}`);
+ assert.notEqual(data.VersionId, undefined);
+ next();
+ })
+ .catch(next),
+ err => cb(err)),
+ cb => s3.send(new HeadObjectCommand(paramsNull))
+ .then(nullVerData => {
+ _assertNoError(null, 'heading null version');
+ assert.strictEqual(nullVerData.ETag, eTags[0]);
+ cb();
+ })
+ .catch(cb),
], done);
});
@@ -390,12 +458,14 @@ describe('put and head object with versioning', function testSuite() {
const key = `foo${i}`;
const params = { Bucket: bucket, Key: key, Body: value };
async.timesLimit(versioncount, 10, (j, next2) =>
- s3.putObject(params, (err, data) => {
- assert.strictEqual(err, null);
- assert(data.VersionId, 'invalid versionId');
- vids.push({ Key: key, VersionId: data.VersionId });
- next2();
- }), next1);
+ s3.send(new PutObjectCommand(params))
+ .then(data => {
+ assert(data.VersionId, 'invalid versionId');
+ vids.push({ Key: key, VersionId: data.VersionId });
+ next2();
+ })
+ .catch(next2),
+ next1);
}, err => {
assert.strictEqual(err, null);
assert.strictEqual(vids.length, keycount * versioncount);
diff --git a/tests/functional/aws-node-sdk/test/versioning/objectPut.js b/tests/functional/aws-node-sdk/test/versioning/objectPut.js
index 81d4cbfbca..ac2ded8e01 100644
--- a/tests/functional/aws-node-sdk/test/versioning/objectPut.js
+++ b/tests/functional/aws-node-sdk/test/versioning/objectPut.js
@@ -1,575 +1,419 @@
const assert = require('assert');
-const async = require('async');
+const {
+ S3Client,
+ CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ GetObjectCommand,
+ ListObjectVersionsCommand,
+} = require('@aws-sdk/client-s3');
const withV4 = require('../support/withV4');
-const BucketUtility = require('../../lib/utility/bucket-util');
-
+const getConfig = require('../support/config');
const {
- createDualNullVersion,
removeAllVersions,
versioningEnabled,
versioningSuspended,
- checkOneVersion,
-} = require('../../lib/utility/versioning-util');
-
-const customS3Request = require('../../lib/utility/customS3Request');
-
-const data = ['foo1', 'foo2'];
-const counter = 100;
-const key = 'objectKey';
+} = require('../../lib/utility/versioning-util.js');
-function _assertNoError(err, desc) {
- assert.strictEqual(err, null, `Unexpected err ${desc}: ${err}`);
-}
-
-
-describe('put and get object with versioning', function testSuite() {
- this.timeout(600000);
+const bucket = 'versioning-test-bucket';
+describe('versioning on object put', () => {
withV4(sigCfg => {
- const bucketUtil = new BucketUtility('default', sigCfg);
- const s3 = bucketUtil.s3;
- let bucket;
+ let s3;
- beforeEach(done => {
- bucket = `versioning-bucket-${Date.now()}`;
- s3.createBucket({ Bucket: bucket }, done);
+ before(async () => {
+ s3 = new S3Client(getConfig('default', sigCfg));
+ await s3.send(new CreateBucketCommand({ Bucket: bucket }));
});
- afterEach(done => {
+ after(done => {
removeAllVersions({ Bucket: bucket }, err => {
if (err) {
return done(err);
}
- return s3.deleteBucket({ Bucket: bucket }, done);
+ return s3.send(new DeleteBucketCommand({ Bucket: bucket }))
+ .then(() => done()).catch(done);
});
});
- it('should return InvalidArgument for a request with versionId query',
- done => {
- const params = { Bucket: bucket, Key: key };
- const query = { versionId: 'testVersionId' };
- customS3Request(s3.putObject, params, { query }, err => {
- assert(err, 'Expected error but did not find one');
- assert.strictEqual(err.code, 'InvalidArgument');
- assert.strictEqual(err.statusCode, 400);
- done();
- });
+ beforeEach(async () => {
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningEnabled,
+ }));
});
- it('should return InvalidArgument for a request with empty string ' +
- 'versionId query', done => {
- const params = { Bucket: bucket, Key: key };
- const query = { versionId: '' };
- customS3Request(s3.putObject, params, { query }, err => {
- assert(err, 'Expected error but did not find one');
- assert.strictEqual(err.code, 'InvalidArgument');
- assert.strictEqual(err.statusCode, 400);
- done();
- });
+ afterEach(done => {
+ removeAllVersions({ Bucket: bucket }, done);
});
- it('should put and get a non-versioned object without including ' +
- 'version ids in response headers', done => {
- const params = { Bucket: bucket, Key: key };
- s3.putObject(params, (err, data) => {
- _assertNoError(err, 'putting object');
- assert.strictEqual(data.VersionId, undefined);
- s3.getObject(params, (err, data) => {
- _assertNoError(err, 'getting object');
- assert.strictEqual(data.VersionId, undefined);
- done();
- });
- });
+ it('should create new version when putting object', async () => {
+ const key = 'key';
+
+ // Put first version
+ const putResult1 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'body1',
+ }));
+ const versionId1 = putResult1.VersionId;
+
+ assert(versionId1);
+ assert.notEqual(versionId1, 'null');
+
+ // Put second version
+ const putResult2 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'body2',
+ }));
+ const versionId2 = putResult2.VersionId;
+
+ assert(versionId2);
+ assert.notEqual(versionId2, versionId1);
+ assert.notEqual(versionId2, 'null');
+
+ // Verify both versions exist
+ const listResult = await s3.send(new ListObjectVersionsCommand({
+ Bucket: bucket,
+ }));
+
+ assert.strictEqual(listResult.Versions.length, 2);
+ const versionIds = listResult.Versions.map(v => v.VersionId);
+ assert(versionIds.includes(versionId1));
+ assert(versionIds.includes(versionId2));
});
- it('version-specific get should still not return version id in ' +
- 'response header', done => {
- const params = { Bucket: bucket, Key: key };
- s3.putObject(params, (err, data) => {
- _assertNoError(err, 'putting object');
- assert.strictEqual(data.VersionId, undefined);
- params.VersionId = 'null';
- s3.getObject(params, (err, data) => {
- _assertNoError(err, 'getting specific version "null"');
- assert.strictEqual(data.VersionId, undefined);
- done();
- });
- });
+ it('should return version id in response', async () => {
+ const key = 'key';
+
+ const putResult = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'body',
+ }));
+
+ assert(putResult.VersionId);
+ assert.notEqual(putResult.VersionId, 'null');
+ assert.strictEqual(putResult.$metadata.httpStatusCode, 200);
});
- describe('on a version-enabled bucket', () => {
- beforeEach(done => {
- s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningEnabled,
- }, done);
- });
-
- it('should create a new version for an object', done => {
- const params = { Bucket: bucket, Key: key };
- s3.putObject(params, (err, data) => {
- _assertNoError(err, 'putting object');
- params.VersionId = data.VersionId;
- s3.getObject(params, (err, data) => {
- _assertNoError(err, 'getting object');
- assert.strictEqual(params.VersionId, data.VersionId,
- 'version ids are not equal');
- done();
- });
- });
- });
-
- it('should create a new version with tag set for an object',
- done => {
- const tagKey = 'key1';
- const tagValue = 'value1';
- const putParams = { Bucket: bucket, Key: key,
- Tagging: `${tagKey}=${tagValue}` };
- s3.putObject(putParams, (err, data) => {
- _assertNoError(err, 'putting object');
- const getTagParams = { Bucket: bucket, Key:
- key, VersionId: data.VersionId };
- s3.getObjectTagging(getTagParams, (err, data) => {
- _assertNoError(err, 'getting object tagging');
- assert.strictEqual(getTagParams.VersionId,
- data.VersionId, 'version ids are not equal');
- assert.strictEqual(data.TagSet[0].Key, tagKey);
- assert.strictEqual(data.TagSet[0].Value, tagValue);
- done();
- });
- });
- });
+ it('should create different version ids for same content', async () => {
+ const key = 'key';
+ const body = 'same content';
+
+ // Put same content twice
+ const putResult1 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: body,
+ }));
+
+ const putResult2 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: body,
+ }));
+
+ // Should have different version ids even with same content
+ assert.notEqual(putResult1.VersionId, putResult2.VersionId);
+
+ // Both versions should exist
+ const listResult = await s3.send(new ListObjectVersionsCommand({
+ Bucket: bucket,
+ }));
+
+ assert.strictEqual(listResult.Versions.length, 2);
});
- describe('on a version-enabled bucket with non-versioned object',
- () => {
- const eTags = [];
-
- beforeEach(done => {
- s3.putObject({ Bucket: bucket, Key: key, Body: data[0] },
- (err, data) => {
- if (err) {
- done(err);
- }
- eTags.push(data.ETag);
- s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningEnabled,
- }, done);
- });
- });
-
- afterEach(done => {
- // reset eTags
- eTags.length = 0;
- done();
- });
-
- it('should get null (latest) version in versioning enabled ' +
- 'bucket when version id is not specified',
- done => {
- const paramsNull = {
- Bucket: bucket,
- Key: key,
- };
- s3.getObject(paramsNull, (err, data) => {
- _assertNoError(err, 'getting null version');
- assert.strictEqual(data.VersionId, 'null');
- done();
- });
- });
-
- it('should get null version in versioning enabled bucket ' +
- 'when version id is specified',
- done => {
- const paramsNull = {
- Bucket: bucket,
- Key: key,
- VersionId: 'null',
- };
- s3.getObject(paramsNull, (err, data) => {
- _assertNoError(err, 'getting null version');
- assert.strictEqual(data.VersionId, 'null');
- done();
- });
- });
-
- it('should keep null version and create a new version',
- done => {
- const params = { Bucket: bucket, Key: key, Body: data[1] };
- s3.putObject(params, (err, data) => {
- const newVersion = data.VersionId;
- eTags.push(data.ETag);
- s3.getObject({ Bucket: bucket, Key: key,
- VersionId: newVersion }, (err, data) => {
- assert.strictEqual(err, null);
- assert.strictEqual(data.VersionId, newVersion,
- 'version ids are not equal');
- assert.strictEqual(data.ETag, eTags[1]);
- s3.getObject({ Bucket: bucket, Key: key,
- VersionId: 'null' }, (err, data) => {
- _assertNoError(err, 'getting null version');
- assert.strictEqual(data.VersionId, 'null');
- assert.strictEqual(data.ETag, eTags[0]);
- done();
- });
- });
- });
- });
-
- it('should create new versions but still keep the null version',
- done => {
- const versionIds = [];
- const params = { Bucket: bucket, Key: key };
- const paramsNull = {
- Bucket: bucket,
- Key: key,
- VersionId: 'null',
- };
- // create new versions
- async.timesSeries(counter, (i, next) => s3.putObject(params,
- (err, data) => {
- versionIds.push(data.VersionId);
- // get the 'null' version
- s3.getObject(paramsNull, (err, nullVerData) => {
- assert.strictEqual(err, null);
- assert.strictEqual(nullVerData.ETag, eTags[0]);
- assert.strictEqual(nullVerData.VersionId, 'null');
- next(err);
- });
- }), done);
- });
+ it('should preserve each version independently', async () => {
+ const key = 'key';
+
+ // Put first version
+ const putResult1 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'version1',
+ ContentType: 'text/plain',
+ Metadata: { version: '1' },
+ }));
+
+ // Put second version
+ const putResult2 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'version2',
+ ContentType: 'application/json',
+ Metadata: { version: '2' },
+ }));
+
+ // Get first version
+ const getResult1 = await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ VersionId: putResult1.VersionId,
+ }));
+
+ const body1 = await getResult1.Body.transformToString();
+ assert.strictEqual(body1, 'version1');
+ assert.strictEqual(getResult1.ContentType, 'text/plain');
+ assert.strictEqual(getResult1.Metadata.version, '1');
+
+ // Get second version
+ const getResult2 = await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ VersionId: putResult2.VersionId,
+ }));
+
+ const body2 = await getResult2.Body.transformToString();
+ assert.strictEqual(body2, 'version2');
+ assert.strictEqual(getResult2.ContentType, 'application/json');
+ assert.strictEqual(getResult2.Metadata.version, '2');
+ });
- // S3C-5139
- it('should not fail PUT on versioning-suspended bucket if nullVersionId refers ' +
- 'to deleted null version', done => {
- async.series([
- // create a new version on top of non-versioned object
- next => s3.putObject({ Bucket: bucket, Key: key }, next),
- // suspend versioning
- next => s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningSuspended,
- }, next),
- // delete existing non-versioned object
- next => s3.deleteObject({ Bucket: bucket, Key: key, VersionId: 'null' }, next),
- // put a new null version
- next => s3.putObject({ Bucket: bucket, Key: key, Body: data[0] }, next),
- // get the new null version
- next => s3.getObject({
- Bucket: bucket,
- Key: key,
- VersionId: 'null',
- }, (err, nullVerData) => {
- assert.ifError(err);
- assert.strictEqual(nullVerData.ETag, eTags[0]);
- assert.strictEqual(nullVerData.VersionId, 'null');
- next();
- }),
- ], err => {
- assert.ifError(err);
- done();
- });
- });
+ it('should make latest version current', async () => {
+ const key = 'key';
+
+ // Put first version
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'version1',
+ }));
+
+ // Put second version
+ const putResult2 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'version2',
+ }));
+
+ // Get without version id (should get current/latest)
+ const getResult = await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ }));
+
+ assert.strictEqual(getResult.VersionId, putResult2.VersionId);
+ const body = await getResult.Body.transformToString();
+ assert.strictEqual(body, 'version2');
});
- describe('on version-suspended bucket', () => {
- beforeEach(done => {
- s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningSuspended,
- }, done);
- });
+ it('should work with versioning suspended', async () => {
+ // Suspend versioning
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningSuspended,
+ }));
+
+ const key = 'key';
+
+ // Put first object (creates null version)
+ const putResult1 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'body1',
+ }));
+
+ assert.strictEqual(putResult1.VersionId, undefined);
+
+ // Put second object (overwrites null version)
+ const putResult2 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'body2',
+ }));
+
+ assert.strictEqual(putResult2.VersionId, undefined);
+
+ // Should only have one version (null version)
+ const listResult = await s3.send(new ListObjectVersionsCommand({
+ Bucket: bucket,
+ }));
+
+ assert.strictEqual(listResult.Versions.length, 1);
+ assert.strictEqual(listResult.Versions[0].VersionId, 'null');
+
+ // Get object should return latest content
+ const getResult = await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ }));
+
+ const body = await getResult.Body.transformToString();
+ assert.strictEqual(body, 'body2');
+ });
- it('should not return version id for new object', done => {
- const params = { Bucket: bucket, Key: key, Body: 'foo' };
- const paramsNull = {
- Bucket: bucket,
- Key: key,
- VersionId: 'null',
- };
- s3.putObject(params, (err, data) => {
- const eTag = data.ETag;
- _assertNoError(err, 'putting object');
- assert.strictEqual(data.VersionId, undefined);
- // getting null version should return object we just put
- s3.getObject(paramsNull, (err, nullVerData) => {
- _assertNoError(err, 'getting null version');
- assert.strictEqual(nullVerData.ETag, eTag);
- assert.strictEqual(nullVerData.VersionId, 'null');
- done();
- });
- });
- });
+ it('should handle transition from suspended to enabled', async () => {
+ const key = 'key';
+
+ // Start with versioning suspended
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningSuspended,
+ }));
+
+ // Put object (creates null version)
+ await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'null-version',
+ }));
+
+ // Enable versioning
+ await s3.send(new PutBucketVersioningCommand({
+ Bucket: bucket,
+ VersioningConfiguration: versioningEnabled,
+ }));
+
+ // Put new object (creates versioned version)
+ const putResult = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'versioned',
+ }));
+
+ assert(putResult.VersionId);
+ assert.notEqual(putResult.VersionId, 'null');
+
+ // Should have both null version and new version
+ const listResult = await s3.send(new ListObjectVersionsCommand({
+ Bucket: bucket,
+ }));
+
+ assert.strictEqual(listResult.Versions.length, 2);
+ const versionIds = listResult.Versions.map(v => v.VersionId);
+ assert(versionIds.includes('null'));
+ assert(versionIds.includes(putResult.VersionId));
+ });
- it('should update null version if put object twice', done => {
- const params = { Bucket: bucket, Key: key };
- const params1 = { Bucket: bucket, Key: key, Body: data[0] };
- const params2 = { Bucket: bucket, Key: key, Body: data[1] };
- const paramsNull = {
+ it('should handle different content types and metadata', async () => {
+ const key = 'key';
+
+ // Put JSON version
+ const putResult1 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: JSON.stringify({ type: 'json' }),
+ ContentType: 'application/json',
+ Metadata: { format: 'json' },
+ }));
+
+ // Put XML version
+ const putResult2 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'xml',
+ ContentType: 'application/xml',
+ Metadata: { format: 'xml' },
+ }));
+
+ // Put text version
+ const putResult3 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: 'plain text content',
+ ContentType: 'text/plain',
+ Metadata: { format: 'text' },
+ }));
+
+ // Verify all versions exist with correct metadata
+ const versions = [putResult1, putResult2, putResult3];
+ const expectedFormats = ['json', 'xml', 'text'];
+ const expectedTypes = ['application/json', 'application/xml', 'text/plain'];
+
+ for (let i = 0; i < versions.length; i++) {
+ const getResult = await s3.send(new GetObjectCommand({
Bucket: bucket,
Key: key,
- VersionId: 'null',
- };
- const eTags = [];
- async.waterfall([
- callback => s3.putObject(params1, (err, data) => {
- _assertNoError(err, 'putting first object');
- assert.strictEqual(data.VersionId, undefined);
- eTags.push(data.ETag);
- callback();
- }),
- callback => s3.getObject(params, (err, data) => {
- _assertNoError(err, 'getting master version');
- assert.strictEqual(data.VersionId, 'null');
- assert.strictEqual(data.ETag, eTags[0],
- 'wrong object data');
- callback();
- }),
- callback => s3.putObject(params2, (err, data) => {
- _assertNoError(err, 'putting second object');
- assert.strictEqual(data.VersionId, undefined);
- eTags.push(data.ETag);
- callback();
- }),
- callback => s3.getObject(paramsNull, (err, data) => {
- _assertNoError(err, 'getting null version');
- assert.strictEqual(data.VersionId, 'null');
- assert.strictEqual(data.ETag, eTags[1],
- 'wrong object data');
- callback();
- }),
- ], done);
- });
-
- // Jira issue: S3C-444
- it('put object after put object acl on null version which is ' +
- 'latest version should not result in two null version with ' +
- 'different version ids', done => {
- async.waterfall([
- // create new null version (master version in metadata)
- callback => s3.putObject({ Bucket: bucket, Key: key },
- err => callback(err)),
- callback => checkOneVersion(s3, bucket, 'null', callback),
- // note after put object acl in metadata will have null
- // version (with same version ID) stored in both master and
- // separate version due to using versionId=
- // option in metadata PUT call
- callback => s3.putObjectAcl({
- Bucket: bucket,
- Key: key,
- ACL: 'public-read-write',
- VersionId: 'null',
- }, err => callback(err)),
- // before overwriting master version, put object should
- // clean up latest null version (both master version and
- // separate version in metadata)
- callback => s3.putObject({ Bucket: bucket, Key: key },
- err => callback(err)),
- // if clean-up did not occur, would see two null versions
- // with different version IDs in version listing
- callback => checkOneVersion(s3, bucket, 'null', callback),
- ], done);
- });
+ VersionId: versions[i].VersionId,
+ }));
- // Jira issue: S3C-444
- it('put object after creating dual null version another way ' +
- 'should not result in two null version with different version ids',
- done => {
- async.waterfall([
- // create dual null version state another way
- callback =>
- createDualNullVersion(s3, bucket, key, callback),
- // versioning is left enabled after above step
- callback => s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningSuspended,
- }, err => callback(err)),
- // before overwriting master version, put object should
- // clean up latest null version (both master version and
- // separate version in metadata)
- callback => s3.putObject({ Bucket: bucket, Key: key },
- err => callback(err)),
- // if clean-up did not occur, would see two null versions
- // with different version IDs in version listing
- callback => checkOneVersion(s3, bucket, 'null', callback),
- ], done);
- });
+ assert.strictEqual(getResult.ContentType, expectedTypes[i]);
+ assert.strictEqual(getResult.Metadata.format, expectedFormats[i]);
+ }
});
- describe('on a version-suspended bucket with non-versioned object',
- () => {
- const eTags = [];
-
- beforeEach(done => {
- s3.putObject({ Bucket: bucket, Key: key, Body: data[0] },
- (err, data) => {
- if (err) {
- done(err);
- }
- eTags.push(data.ETag);
- s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningSuspended,
- }, done);
- });
- });
-
- afterEach(done => {
- // reset eTags
- eTags.length = 0;
- done();
- });
+ it('should handle large objects across versions', async () => {
+ const key = 'key';
+ const largeBody1 = 'a'.repeat(10000);
+ const largeBody2 = 'b'.repeat(15000);
+
+ // Put first large version
+ const putResult1 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: largeBody1,
+ }));
+
+ // Put second large version
+ const putResult2 = await s3.send(new PutObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ Body: largeBody2,
+ }));
+
+ // Verify both versions exist with correct sizes
+ const getResult1 = await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ VersionId: putResult1.VersionId,
+ }));
+
+ assert.strictEqual(getResult1.ContentLength, 10000);
+
+ const getResult2 = await s3.send(new GetObjectCommand({
+ Bucket: bucket,
+ Key: key,
+ VersionId: putResult2.VersionId,
+ }));
+
+ assert.strictEqual(getResult2.ContentLength, 15000);
+ });
- it('should get null version (latest) in versioning ' +
- 'suspended bucket without specifying version id',
- done => {
- const paramsNull = {
+ it('should handle concurrent puts to same key', async () => {
+ const key = 'key';
+
+ // Put multiple versions concurrently
+ const putPromises = [];
+ for (let i = 0; i < 5; i++) {
+ putPromises.push(s3.send(new PutObjectCommand({
Bucket: bucket,
Key: key,
- };
- s3.getObject(paramsNull, (err, data) => {
- assert.strictEqual(data.VersionId, 'null');
- _assertNoError(err, 'getting null version');
- done();
- });
- });
+ Body: `version-${i}`,
+ Metadata: { index: i.toString() },
+ })));
+ }
- it('should get null version in versioning suspended bucket ' +
- 'specifying version id',
- done => {
- const paramsNull = {
- Bucket: bucket,
- Key: key,
- VersionId: 'null',
- };
- s3.getObject(paramsNull, (err, data) => {
- assert.strictEqual(data.VersionId, 'null');
- _assertNoError(err, 'getting null version');
- done();
- });
- });
+ const putResults = await Promise.all(putPromises);
- it('should update null version in versioning suspended bucket',
- done => {
- const params = { Bucket: bucket, Key: key };
- const putParams = { Bucket: bucket, Key: key, Body: data[1] };
- const paramsNull = {
- Bucket: bucket,
- Key: key,
- VersionId: 'null',
- };
- async.waterfall([
- callback => s3.getObject(paramsNull, (err, data) => {
- _assertNoError(err, 'getting null version');
- assert.strictEqual(data.VersionId, 'null');
- callback();
- }),
- callback => s3.putObject(putParams, (err, data) => {
- _assertNoError(err, 'putting object');
- assert.strictEqual(data.VersionId, undefined);
- eTags.push(data.ETag);
- callback();
- }),
- callback => s3.getObject(paramsNull, (err, data) => {
- _assertNoError(err, 'getting null version');
- assert.strictEqual(data.VersionId, 'null');
- assert.strictEqual(data.ETag, eTags[1],
- 'wrong object data');
- callback();
- }),
- callback => s3.getObject(params, (err, data) => {
- _assertNoError(err, 'getting master version');
- assert.strictEqual(data.VersionId, 'null');
- assert.strictEqual(data.ETag, eTags[1],
- 'wrong object data');
- callback();
- }),
- ], done);
- });
- });
+ // All should have unique version ids
+ const versionIds = putResults.map(r => r.VersionId);
+ const uniqueVersionIds = new Set(versionIds);
+ assert.strictEqual(uniqueVersionIds.size, 5);
- describe('on versioning suspended then enabled bucket w/ null version',
- () => {
- const eTags = [];
- beforeEach(done => {
- const params = { Bucket: bucket, Key: key, Body: data[0] };
- async.waterfall([
- callback => s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningSuspended,
- }, err => callback(err)),
- callback => s3.putObject(params, (err, data) => {
- if (err) {
- callback(err);
- }
- eTags.push(data.ETag);
- callback();
- }),
- callback => s3.putBucketVersioning({
- Bucket: bucket,
- VersioningConfiguration: versioningEnabled,
- }, callback),
- ], done);
- });
+ // All versions should exist
+ const listResult = await s3.send(new ListObjectVersionsCommand({
+ Bucket: bucket,
+ }));
- afterEach(done => {
- // reset eTags
- eTags.length = 0;
- done();
- });
+ assert.strictEqual(listResult.Versions.length, 5);
- it('should preserve the null version when creating new versions',
- done => {
- const params = { Bucket: bucket, Key: key };
- const paramsNull = {
+ // Verify each version has correct content
+ for (let i = 0; i < putResults.length; i++) {
+ const getResult = await s3.send(new GetObjectCommand({
Bucket: bucket,
Key: key,
- VersionId: 'null',
- };
- async.waterfall([
- callback => s3.getObject(paramsNull, (err, nullVerData) => {
- _assertNoError(err, 'getting null version');
- assert.strictEqual(nullVerData.ETag, eTags[0]);
- assert.strictEqual(nullVerData.VersionId, 'null');
- callback();
- }),
- callback => async.timesSeries(counter, (i, next) =>
- s3.putObject(params, (err, data) => {
- _assertNoError(err, `putting object #${i}`);
- assert.notEqual(data.VersionId, undefined);
- next();
- }), err => callback(err)),
- callback => s3.getObject(paramsNull, (err, nullVerData) => {
- _assertNoError(err, 'getting null version');
- assert.strictEqual(nullVerData.ETag, eTags[0]);
- callback();
- }),
- ], done);
- });
+ VersionId: putResults[i].VersionId,
+ }));
- it('should create a bunch of objects and their versions', done => {
- const vids = [];
- const keycount = 50;
- const versioncount = 20;
- const value = '{"foo":"bar"}';
- async.timesLimit(keycount, 10, (i, next1) => {
- const key = `foo${i}`;
- const params = { Bucket: bucket, Key: key, Body: value };
- async.timesLimit(versioncount, 10, (j, next2) =>
- s3.putObject(params, (err, data) => {
- assert.strictEqual(err, null);
- assert(data.VersionId, 'invalid versionId');
- vids.push({ Key: key, VersionId: data.VersionId });
- next2();
- }), next1);
- }, err => {
- assert.strictEqual(err, null);
- assert.strictEqual(vids.length, keycount * versioncount);
- done();
- });
- });
+ const body = await getResult.Body.transformToString();
+ assert.strictEqual(body, `version-${i}`);
+ assert.strictEqual(getResult.Metadata.index, i.toString());
+ }
});
});
});
diff --git a/tests/functional/aws-node-sdk/test/versioning/objectPutCopyPart.js b/tests/functional/aws-node-sdk/test/versioning/objectPutCopyPart.js
index 241eab1ec9..fa1183b2cf 100644
--- a/tests/functional/aws-node-sdk/test/versioning/objectPutCopyPart.js
+++ b/tests/functional/aws-node-sdk/test/versioning/objectPutCopyPart.js
@@ -1,5 +1,18 @@
const assert = require('assert');
const async = require('async');
+const { promisify } = require('util');
+
+const {
+ CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ DeleteObjectCommand,
+ UploadPartCopyCommand,
+ CreateMultipartUploadCommand,
+ AbortMultipartUploadCommand,
+ ListObjectVersionsCommand,
+} = require('@aws-sdk/client-s3');
const withV4 = require('../support/withV4');
const BucketUtility = require('../../lib/utility/bucket-util');
@@ -10,16 +23,13 @@ const {
versioningSuspended,
} = require('../../lib/utility/versioning-util.js');
+const removeAllVersionsPromise = promisify(removeAllVersions);
let sourceBucket;
let destBucket;
const sourceKey = 'sourceobjectkey';
const destKey = 'destobjectkey';
const invalidId = 'invalidIdWithMoreThan40BytesAndThatIsNotLongEnoughYet';
-function _assertNoError(err, desc) {
- assert.strictEqual(err, null, `Unexpected err ${desc}: ${err}`);
-}
-
describe('Object Part Copy with Versioning', () => {
withV4(sigCfg => {
@@ -31,28 +41,32 @@ describe('Object Part Copy with Versioning', () => {
sourceBucket = `copypartsourcebucket-${Date.now()}`;
destBucket = `copypartdestbucket-${Date.now()}`;
async.forEach([sourceBucket, destBucket], (bucket, cb) => {
- s3.createBucket({ Bucket: bucket }, cb);
+ s3.send(new CreateBucketCommand({ Bucket: bucket }))
+ .then(() => cb())
+ .catch(cb);
}, done);
});
afterEach(done => {
- s3.abortMultipartUpload({
+ s3.send(new AbortMultipartUploadCommand({
Bucket: destBucket,
Key: destKey,
UploadId: uploadId,
- }, err => {
- if (err) {
- return done(err);
- }
- return async.each([sourceBucket, destBucket], (bucket, cb) => {
- removeAllVersions({ Bucket: bucket }, err => {
- if (err) {
- return cb(err);
- }
- return s3.deleteBucket({ Bucket: bucket }, cb);
- });
- }, done);
- });
+ }))
+ .then(() => {
+ async.each([sourceBucket, destBucket], (bucket, cb) => {
+ removeAllVersionsPromise({ Bucket: bucket })
+ .then(() => s3.send(new DeleteBucketCommand({ Bucket: bucket })))
+ .then(() => cb())
+ .catch(cb);
+ }, done);
+ })
+ .catch(err => {
+ if (err) {
+ return done(err);
+ }
+ return done();
+ });
});
describe('on bucket without versioning', () => {
@@ -60,12 +74,21 @@ describe('Object Part Copy with Versioning', () => {
beforeEach(done => {
async.waterfall([
- next => s3.putObject({ Bucket: sourceBucket, Key: sourceKey,
- Body: 'foobar' }, next),
+ next => s3.send(new PutObjectCommand({
+ Bucket: sourceBucket,
+ Key: sourceKey,
+ Body: 'foobar'
+ }))
+ .then(data => next(null, data))
+ .catch(next),
(data, next) => {
eTags.push(data.ETag);
- s3.createMultipartUpload({ Bucket: destBucket,
- Key: destKey }, next);
+ s3.send(new CreateMultipartUploadCommand({
+ Bucket: destBucket,
+ Key: destKey
+ }))
+ .then(data => next(null, data))
+ .catch(next);
},
], (err, data) => {
if (err) {
@@ -83,52 +106,57 @@ describe('Object Part Copy with Versioning', () => {
it('should not return a version id when put part by copying ' +
'without specifying version id', done => {
- s3.uploadPartCopy({
+ s3.send(new UploadPartCopyCommand({
Bucket: destBucket,
CopySource: `${sourceBucket}/${sourceKey}`,
Key: destKey,
PartNumber: 1,
UploadId: uploadId,
- }, (err, data) => {
- _assertNoError(err, 'uploading part copy w/o version id');
- assert.strictEqual(data.CopySourceVersionId, undefined);
- assert.strictEqual(data.CopyPartResult.ETag, eTags[0]);
- done();
- });
+ }))
+ .then(data => {
+ assert.strictEqual(data.CopySourceVersionId, undefined);
+ assert.strictEqual(data.CopyPartResult.ETag, eTags[0]);
+ done();
+ })
+ .catch(done);
});
it('should return NoSuchKey if copy source version id is invalid ' +
'id', done => {
- s3.uploadPartCopy({
+ s3.send(new UploadPartCopyCommand({
Bucket: destBucket,
CopySource: `${sourceBucket}/${sourceKey}?` +
`versionId=${invalidId}`,
Key: destKey,
PartNumber: 1,
UploadId: uploadId,
- }, err => {
- assert(err, `Expected err but got ${err}`);
- assert.strictEqual(err.code, 'InvalidArgument');
- assert.strictEqual(err.statusCode, 400);
- done();
- });
+ }))
+ .then(() => {
+ done(new Error('Expected error but got success'));
+ })
+ .catch(err => {
+ assert(err, `Expected err but got ${err}`);
+ assert.strictEqual(err.name, 'InvalidArgument');
+ assert.strictEqual(err.$metadata?.httpStatusCode, 400);
+ done();
+ });
});
it('should allow specific version "null" for copy source ' +
'and return version id "null" in response headers', done => {
- s3.uploadPartCopy({
+ s3.send(new UploadPartCopyCommand({
Bucket: destBucket,
CopySource: `${sourceBucket}/${sourceKey}?versionId=null`,
Key: destKey,
PartNumber: 1,
UploadId: uploadId,
- }, (err, data) => {
- _assertNoError(err,
- 'using specific version "null" for copy source');
- assert.strictEqual(data.CopySourceVersionId, 'null');
- assert.strictEqual(data.ETag, eTags[0]);
- done();
- });
+ }))
+ .then(data => {
+ assert.strictEqual(data.CopySourceVersionId, 'null');
+ assert.strictEqual(data.CopyPartResult.ETag, eTags[0]);
+ done();
+ })
+ .catch(done);
});
});
@@ -140,25 +168,38 @@ describe('Object Part Copy with Versioning', () => {
beforeEach(done => {
const params = { Bucket: sourceBucket, Key: sourceKey };
async.waterfall([
- next => s3.putObject(params, next),
+ next => s3.send(new PutObjectCommand(params))
+ .then(data => next(null, data))
+ .catch(next),
(data, next) => {
eTags.push(data.ETag);
versionIds.push('null');
- s3.putBucketVersioning({
+ s3.send(new PutBucketVersioningCommand({
Bucket: sourceBucket,
VersioningConfiguration: versioningEnabled,
- }, err => next(err));
+ }))
+ .then(() => next())
+ .catch(next);
},
next => async.timesSeries(counter, (i, cb) =>
- s3.putObject({ Bucket: sourceBucket, Key: sourceKey,
- Body: `foo${i}` }, (err, data) => {
- _assertNoError(err, `putting version #${i}`);
- eTags.push(data.ETag);
- versionIds.push(data.VersionId);
- cb(err);
- }), err => next(err)),
- next => s3.createMultipartUpload({ Bucket: destBucket,
- Key: destKey }, next),
+ s3.send(new PutObjectCommand({
+ Bucket: sourceBucket,
+ Key: sourceKey,
+ Body: `foo${i}`
+ }))
+ .then(data => {
+ eTags.push(data.ETag);
+ versionIds.push(data.VersionId);
+ cb();
+ })
+ .catch(cb),
+ err => next(err)),
+ next => s3.send(new CreateMultipartUploadCommand({
+ Bucket: destBucket,
+ Key: destKey
+ }))
+ .then(data => next(null, data))
+ .catch(next),
], (err, data) => {
if (err) {
return done(err);
@@ -178,64 +219,76 @@ describe('Object Part Copy with Versioning', () => {
'version id of latest version', done => {
const lastVersion = versionIds[versionIds.length - 1];
const lastETag = eTags[eTags.length - 1];
- s3.uploadPartCopy({
+ s3.send(new UploadPartCopyCommand({
Bucket: destBucket,
CopySource: `${sourceBucket}/${sourceKey}`,
Key: destKey,
PartNumber: 1,
UploadId: uploadId,
- }, (err, data) => {
- _assertNoError(err, 'uploading part copy w/o version id');
- assert.strictEqual(data.CopySourceVersionId, lastVersion);
- assert.strictEqual(data.CopyPartResult.ETag, lastETag);
- done();
- });
+ }))
+ .then(data => {
+ assert.strictEqual(data.CopySourceVersionId, lastVersion);
+ assert.strictEqual(data.CopyPartResult.ETag, lastETag);
+ done();
+ })
+ .catch(done);
});
it('copy part without specifying version should return NoSuchKey ' +
'if latest version has a delete marker', done => {
- s3.deleteObject({ Bucket: sourceBucket, Key: sourceKey },
- err => {
- _assertNoError(err, 'deleting latest version');
- s3.uploadPartCopy({
+ s3.send(new DeleteObjectCommand({
+ Bucket: sourceBucket,
+ Key: sourceKey
+ }))
+ .then(() => s3.send(new UploadPartCopyCommand({
Bucket: destBucket,
CopySource: `${sourceBucket}/${sourceKey}`,
Key: destKey,
PartNumber: 1,
UploadId: uploadId,
- }, err => {
- assert(err, 'Expected err but did not find one');
- assert.strictEqual(err.code, 'NoSuchKey');
- assert.strictEqual(err.statusCode, 404);
- done();
- });
+ })))
+ .then(() => {
+ done(new Error('Expected err but did not find one'));
+ })
+ .catch(err => {
+ assert(err, 'Expected err but did not find one');
+ assert.strictEqual(err.name, 'NoSuchKey');
+ assert.strictEqual(err.$metadata?.httpStatusCode, 404);
+ done();
});
});
it('copy part with specific version id should return ' +
'InvalidRequest if that id is a delete marker', done => {
async.waterfall([
- next => s3.deleteObject({
+ next => s3.send(new DeleteObjectCommand({
Bucket: sourceBucket,
Key: sourceKey,
- }, err => next(err)),
- next => s3.listObjectVersions({ Bucket: sourceBucket },
- next),
+ }))
+ .then(() => next())
+ .catch(next),
+ next => s3.send(new ListObjectVersionsCommand({
+ Bucket: sourceBucket
+ }))
+ .then(data => next(null, data))
+ .catch(next),
(data, next) => {
const deleteMarkerId = data.DeleteMarkers[0].VersionId;
- return s3.uploadPartCopy({
+ return s3.send(new UploadPartCopyCommand({
Bucket: destBucket,
CopySource: `${sourceBucket}/${sourceKey}` +
`?versionId=${deleteMarkerId}`,
Key: destKey,
PartNumber: 1,
UploadId: uploadId,
- }, next);
+ }))
+ .then(data => next(null, data))
+ .catch(next);
},
], err => {
assert(err, 'Expected err but did not find one');
- assert.strictEqual(err.code, 'InvalidRequest');
- assert.strictEqual(err.statusCode, 400);
+ assert.strictEqual(err.name, 'InvalidRequest');
+ assert.strictEqual(err.$metadata?.httpStatusCode, 400);
done();
});
});
@@ -243,58 +296,67 @@ describe('Object Part Copy with Versioning', () => {
it('copy part with specific version should return NoSuchVersion ' +
'if version does not exist', done => {
const versionId = versionIds[1];
- s3.deleteObject({ Bucket: sourceBucket, Key: sourceKey,
- VersionId: versionId }, (err, data) => {
- _assertNoError(err, `deleting version ${versionId}`);
- assert.strictEqual(data.VersionId, versionId);
- s3.uploadPartCopy({
- Bucket: destBucket,
- CopySource: `${sourceBucket}/${sourceKey}` +
- `?versionId=${versionId}`,
- Key: destKey,
- PartNumber: 1,
- UploadId: uploadId,
- }, err => {
+ s3.send(new DeleteObjectCommand({
+ Bucket: sourceBucket,
+ Key: sourceKey,
+ VersionId: versionId
+ }))
+ .then(data => {
+ assert.strictEqual(data.VersionId, versionId);
+ return s3.send(new UploadPartCopyCommand({
+ Bucket: destBucket,
+ CopySource: `${sourceBucket}/${sourceKey}` +
+ `?versionId=${versionId}`,
+ Key: destKey,
+ PartNumber: 1,
+ UploadId: uploadId,
+ }));
+ })
+ .then(() => {
+ done(new Error('Expected err but did not find one'));
+ })
+ .catch(err => {
assert(err, 'Expected err but did not find one');
- assert.strictEqual(err.code, 'NoSuchVersion');
- assert.strictEqual(err.statusCode, 404);
+ assert.strictEqual(err.name, 'NoSuchVersion');
+ assert.strictEqual(err.$metadata?.httpStatusCode, 404);
done();
});
- });
});
it('copy part with specific version should return copy source ' +
'version id if it exists', done => {
const versionId = versionIds[1];
- s3.uploadPartCopy({
+ s3.send(new UploadPartCopyCommand({
Bucket: destBucket,
CopySource: `${sourceBucket}/${sourceKey}` +
`?versionId=${versionId}`,
Key: destKey,
PartNumber: 1,
UploadId: uploadId,
- }, (err, data) => {
- _assertNoError(err, 'copy part from specific version');
- assert.strictEqual(data.CopySourceVersionId, versionId);
- assert.strictEqual(data.CopyPartResult.ETag, eTags[1]);
- done();
- });
+ }))
+ .then(data => {
+ assert.strictEqual(data.CopySourceVersionId, versionId);
+ assert.strictEqual(data.CopyPartResult.ETag, eTags[1]);
+ done();
+ })
+ .catch(done);
});
it('copy part with specific version "null" should return copy ' +
'source version id "null" if it exists', done => {
- s3.uploadPartCopy({
+ s3.send(new UploadPartCopyCommand({
Bucket: destBucket,
CopySource: `${sourceBucket}/${sourceKey}?versionId=null`,
Key: destKey,
PartNumber: 1,
UploadId: uploadId,
- }, (err, data) => {
- _assertNoError(err, 'copy part from specific version');
- assert.strictEqual(data.CopySourceVersionId, 'null');
- assert.strictEqual(data.CopyPartResult.ETag, eTags[0]);
- done();
- });
+ }))
+ .then(data => {
+ assert.strictEqual(data.CopySourceVersionId, 'null');
+ assert.strictEqual(data.CopyPartResult.ETag, eTags[0]);
+ done();
+ })
+ .catch(done);
});
});
@@ -306,31 +368,46 @@ describe('Object Part Copy with Versioning', () => {
beforeEach(done => {
const params = { Bucket: sourceBucket, Key: sourceKey };
async.waterfall([
- next => s3.putObject(params, next),
+ next => s3.send(new PutObjectCommand(params))
+ .then(data => next(null, data))
+ .catch(next),
(data, next) => {
eTags.push(data.ETag);
versionIds.push('null');
- s3.putBucketVersioning({
+ s3.send(new PutBucketVersioningCommand({
Bucket: sourceBucket,
VersioningConfiguration: versioningEnabled,
- }, err => next(err));
+ }))
+ .then(() => next())
+ .catch(next);
},
next => async.timesSeries(counter, (i, cb) =>
- s3.putObject({ Bucket: sourceBucket, Key: sourceKey,
- Body: `foo${i}` }, (err, data) => {
- _assertNoError(err, `putting version #${i}`);
- eTags.push(data.ETag);
- versionIds.push(data.VersionId);
- cb(err);
- }), err => next(err)),
+ s3.send(new PutObjectCommand({
+ Bucket: sourceBucket,
+ Key: sourceKey,
+ Body: `foo${i}`
+ }))
+ .then(data => {
+ eTags.push(data.ETag);
+ versionIds.push(data.VersionId);
+ cb();
+ })
+ .catch(cb),
+ err => next(err)),
next => {
- s3.putBucketVersioning({
+ s3.send(new PutBucketVersioningCommand({
Bucket: sourceBucket,
VersioningConfiguration: versioningSuspended,
- }, err => next(err));
+ }))
+ .then(() => next())
+ .catch(next);
},
- next => s3.createMultipartUpload({ Bucket: destBucket,
- Key: destKey }, next),
+ next => s3.send(new CreateMultipartUploadCommand({
+ Bucket: destBucket,
+ Key: destKey
+ }))
+ .then(data => next(null, data))
+ .catch(next),
], (err, data) => {
if (err) {
return done(err);
@@ -350,52 +427,55 @@ describe('Object Part Copy with Versioning', () => {
'version id of latest version', done => {
const lastVersion = versionIds[versionIds.length - 1];
const lastETag = eTags[eTags.length - 1];
- s3.uploadPartCopy({
+ s3.send(new UploadPartCopyCommand({
Bucket: destBucket,
CopySource: `${sourceBucket}/${sourceKey}`,
Key: destKey,
PartNumber: 1,
UploadId: uploadId,
- }, (err, data) => {
- _assertNoError(err, 'uploading part copy w/o version id');
- assert.strictEqual(data.CopySourceVersionId, lastVersion);
- assert.strictEqual(data.CopyPartResult.ETag, lastETag);
- done();
- });
+ }))
+ .then(data => {
+ assert.strictEqual(data.CopySourceVersionId, lastVersion);
+ assert.strictEqual(data.CopyPartResult.ETag, lastETag);
+ done();
+ })
+ .catch(done);
});
it('copy part with specific version should still return copy ' +
'source version id if it exists', done => {
const versionId = versionIds[1];
- s3.uploadPartCopy({
+ s3.send(new UploadPartCopyCommand({
Bucket: destBucket,
CopySource: `${sourceBucket}/${sourceKey}` +
`?versionId=${versionId}`,
Key: destKey,
PartNumber: 1,
UploadId: uploadId,
- }, (err, data) => {
- _assertNoError(err, 'copy part from specific version');
- assert.strictEqual(data.CopySourceVersionId, versionId);
- assert.strictEqual(data.CopyPartResult.ETag, eTags[1]);
- done();
- });
+ }))
+ .then(data => {
+ assert.strictEqual(data.CopySourceVersionId, versionId);
+ assert.strictEqual(data.CopyPartResult.ETag, eTags[1]);
+ done();
+ })
+ .catch(done);
});
it('copy part with specific version "null" should still return ' +
'copy source version id "null" if it exists', done => {
- s3.uploadPartCopy({
+ s3.send(new UploadPartCopyCommand({
Bucket: destBucket,
CopySource: `${sourceBucket}/${sourceKey}?versionId=null`,
Key: destKey,
PartNumber: 1,
UploadId: uploadId,
- }, (err, data) => {
- _assertNoError(err, 'copy part from specific version');
- assert.strictEqual(data.CopySourceVersionId, 'null');
- assert.strictEqual(data.CopyPartResult.ETag, eTags[0]);
- done();
- });
+ }))
+ .then(data => {
+ assert.strictEqual(data.CopySourceVersionId, 'null');
+ assert.strictEqual(data.CopyPartResult.ETag, eTags[0]);
+ done();
+ })
+ .catch(done);
});
});
});
diff --git a/tests/functional/aws-node-sdk/test/versioning/objectPutTagging.js b/tests/functional/aws-node-sdk/test/versioning/objectPutTagging.js
index eab3c9fe23..b71919fba8 100644
--- a/tests/functional/aws-node-sdk/test/versioning/objectPutTagging.js
+++ b/tests/functional/aws-node-sdk/test/versioning/objectPutTagging.js
@@ -1,5 +1,15 @@
const assert = require('assert');
const async = require('async');
+const {promisify} = require('util');
+
+const {
+ CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ PutObjectTaggingCommand,
+ DeleteObjectCommand,
+} = require('@aws-sdk/client-s3');
const withV4 = require('../support/withV4');
const BucketUtility = require('../../lib/utility/bucket-util');
@@ -10,6 +20,8 @@ const {
versioningEnabled,
} = require('../../lib/utility/versioning-util');
+const removeAllVersionsPromise= promisify(removeAllVersions);
+
const bucketName = 'testtaggingbucket';
const objectName = 'testtaggingobject';
@@ -17,34 +29,42 @@ const invalidId = 'invalidIdWithMoreThan40BytesAndThatIsNotLongEnoughYet';
function _checkError(err, code, statusCode) {
assert(err, 'Expected error but found none');
- assert.strictEqual(err.code, code);
- assert.strictEqual(err.statusCode, statusCode);
+ assert.strictEqual(err.name, code);
+ assert.strictEqual(err.$metadata?.httpStatusCode, statusCode);
}
-
describe('Put object tagging with versioning', () => {
withV4(sigCfg => {
const bucketUtil = new BucketUtility('default', sigCfg);
const s3 = bucketUtil.s3;
- beforeEach(done => s3.createBucket({ Bucket: bucketName }, done));
- afterEach(done => {
- removeAllVersions({ Bucket: bucketName }, err => {
- if (err) {
- return done(err);
- }
- return s3.deleteBucket({ Bucket: bucketName }, done);
- });
+ beforeEach(async () => {
+ await s3.send(new CreateBucketCommand({ Bucket: bucketName }));
+ });
+
+ afterEach(async () => {
+ await removeAllVersionsPromise({ Bucket: bucketName });
+ await bucketUtil.empty(bucketName);
+ await s3.send(new DeleteBucketCommand({ Bucket: bucketName }));
});
it('should be able to put tag with versioning', done => {
async.waterfall([
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- (err, data) => next(err, data.VersionId)),
- (versionId, next) => s3.putObjectTagging({
+ next => s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled,
+ }))
+ .then(() => next())
+ .catch(next),
+
+ next => s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }))
+ .then(data => next(null, data.VersionId))
+ .catch(next),
+
+ (versionId, next) => s3.send(new PutObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
VersionId: versionId,
@@ -53,7 +73,9 @@ describe('Put object tagging with versioning', () => {
Key: 'key1',
Value: 'value1',
}] },
- }, (err, data) => next(err, data, versionId)),
+ }))
+ .then(data => next(null, data, versionId))
+ .catch(next),
], (err, data, versionId) => {
assert.ifError(err, `Found unexpected err ${err}`);
assert.strictEqual(data.VersionId, versionId);
@@ -64,12 +86,21 @@ describe('Put object tagging with versioning', () => {
it('should not create version putting object tags on a ' +
' version-enabled bucket where no version id is specified ', done => {
async.waterfall([
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- (err, data) => next(err, data.VersionId)),
- (versionId, next) => s3.putObjectTagging({
+ next => s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled,
+ }))
+ .then(() => next())
+ .catch(next),
+
+ next => s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }))
+ .then(data => next(null, data.VersionId))
+ .catch(next),
+
+ (versionId, next) => s3.send(new PutObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
Tagging: { TagSet: [
@@ -77,20 +108,34 @@ describe('Put object tagging with versioning', () => {
Key: 'key1',
Value: 'value1',
}] },
- }, err => next(err, versionId)),
+ }))
+ .then(() => next(null, versionId))
+ .catch(next),
+
(versionId, next) =>
- checkOneVersion(s3, bucketName, versionId, next),
+ checkOneVersion(s3, bucketName, versionId)
+ .then(() => next())
+ .catch(next),
], done);
});
it('should be able to put tag with a version of id "null"', done => {
async.waterfall([
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.putObjectTagging({
+ next => s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }))
+ .then(() => next())
+ .catch(next),
+
+ next => s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled,
+ }))
+ .then(() => next())
+ .catch(next),
+
+ next => s3.send(new PutObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
VersionId: 'null',
@@ -99,7 +144,9 @@ describe('Put object tagging with versioning', () => {
Key: 'key1',
Value: 'value1',
}] },
- }, (err, data) => next(err, data)),
+ }))
+ .then(data => next(null, data))
+ .catch(next),
], (err, data) => {
assert.ifError(err, `Found unexpected err ${err}`);
assert.strictEqual(data.VersionId, 'null');
@@ -110,12 +157,21 @@ describe('Put object tagging with versioning', () => {
it('should return InvalidArgument putting tag with a non existing ' +
'version id', done => {
async.waterfall([
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.putObjectTagging({
+ next => s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }))
+ .then(() => next())
+ .catch(next),
+
+ next => s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled,
+ }))
+ .then(() => next())
+ .catch(next),
+
+ next => s3.send(new PutObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
VersionId: invalidId,
@@ -124,7 +180,9 @@ describe('Put object tagging with versioning', () => {
Key: 'key1',
Value: 'value1',
}] },
- }, (err, data) => next(err, data)),
+ }))
+ .then(data => next(null, data))
+ .catch(next),
], err => {
_checkError(err, 'InvalidArgument', 400);
done();
@@ -134,14 +192,28 @@ describe('Put object tagging with versioning', () => {
it('should return 405 MethodNotAllowed putting tag without ' +
'version id if version specified is a delete marker', done => {
async.waterfall([
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.deleteObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.putObjectTagging({
+ next => s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled,
+ }))
+ .then(() => next())
+ .catch(next),
+
+ next => s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }))
+ .then(() => next())
+ .catch(next),
+
+ next => s3.send(new DeleteObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }))
+ .then(() => next())
+ .catch(next),
+
+ next => s3.send(new PutObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
Tagging: { TagSet: [
@@ -149,7 +221,9 @@ describe('Put object tagging with versioning', () => {
Key: 'key1',
Value: 'value1',
}] },
- }, (err, data) => next(err, data)),
+ }))
+ .then(data => next(null, data))
+ .catch(next),
], err => {
_checkError(err, 'MethodNotAllowed', 405);
done();
@@ -159,14 +233,28 @@ describe('Put object tagging with versioning', () => {
it('should return 405 MethodNotAllowed putting tag with ' +
'version id if version specified is a delete marker', done => {
async.waterfall([
- next => s3.putBucketVersioning({ Bucket: bucketName,
- VersioningConfiguration: versioningEnabled },
- err => next(err)),
- next => s3.putObject({ Bucket: bucketName, Key: objectName },
- err => next(err)),
- next => s3.deleteObject({ Bucket: bucketName, Key: objectName },
- (err, data) => next(err, data.VersionId)),
- (versionId, next) => s3.putObjectTagging({
+ next => s3.send(new PutBucketVersioningCommand({
+ Bucket: bucketName,
+ VersioningConfiguration: versioningEnabled,
+ }))
+ .then(() => next())
+ .catch(next),
+
+ next => s3.send(new PutObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }))
+ .then(() => next())
+ .catch(next),
+
+ next => s3.send(new DeleteObjectCommand({
+ Bucket: bucketName,
+ Key: objectName
+ }))
+ .then(data => next(null, data.VersionId))
+ .catch(next),
+
+ (versionId, next) => s3.send(new PutObjectTaggingCommand({
Bucket: bucketName,
Key: objectName,
VersionId: versionId,
@@ -175,7 +263,9 @@ describe('Put object tagging with versioning', () => {
Key: 'key1',
Value: 'value1',
}] },
- }, (err, data) => next(err, data)),
+ }))
+ .then(data => next(null, data))
+ .catch(next),
], err => {
_checkError(err, 'MethodNotAllowed', 405);
done();
diff --git a/tests/functional/aws-node-sdk/test/versioning/replicationBucket.js b/tests/functional/aws-node-sdk/test/versioning/replicationBucket.js
index 230fe0d5a1..9bc9af2ad4 100644
--- a/tests/functional/aws-node-sdk/test/versioning/replicationBucket.js
+++ b/tests/functional/aws-node-sdk/test/versioning/replicationBucket.js
@@ -1,15 +1,21 @@
const assert = require('assert');
const async = require('async');
+const {
+ CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutBucketReplicationCommand,
+ DeleteBucketReplicationCommand,
+} = require('@aws-sdk/client-s3');
const withV4 = require('../support/withV4');
const BucketUtility = require('../../lib/utility/bucket-util');
const bucketName = `versioning-bucket-${Date.now()}`;
-
function checkError(err, code) {
assert.notEqual(err, null, 'Expected failure but got success');
- assert.strictEqual(err.code, code);
+ assert.strictEqual(err.name, code);
}
function checkNoError(err) {
@@ -17,8 +23,10 @@ function checkNoError(err) {
}
function testVersioning(s3, versioningStatus, replicationStatus, removeReplication, cb) {
- const versioningParams = { Bucket: bucketName,
- VersioningConfiguration: { Status: versioningStatus } };
+ const versioningParams = {
+ Bucket: bucketName,
+ VersioningConfiguration: { Status: versioningStatus }
+ };
const replicationParams = {
Bucket: bucketName,
ReplicationConfiguration: {
@@ -36,15 +44,22 @@ function testVersioning(s3, versioningStatus, replicationStatus, removeReplicati
],
},
};
+
async.waterfall([
- cb => s3.putBucketReplication(replicationParams, e => cb(e)),
+ cb => s3.send(new PutBucketReplicationCommand(replicationParams))
+ .then(() => cb())
+ .catch(cb),
cb => {
if (removeReplication) {
- return s3.deleteBucketReplication({ Bucket: bucketName }, e => cb(e));
+ return s3.send(new DeleteBucketReplicationCommand({ Bucket: bucketName }))
+ .then(() => cb())
+ .catch(cb);
}
return process.nextTick(() => cb());
},
- cb => s3.putBucketVersioning(versioningParams, e => cb(e)),
+ cb => s3.send(new PutBucketVersioningCommand(versioningParams))
+ .then(() => cb())
+ .catch(cb),
], cb);
}
@@ -55,17 +70,23 @@ describe('Versioning on a replication source bucket', () => {
beforeEach(done => {
async.waterfall([
- cb => s3.createBucket({ Bucket: bucketName }, e => cb(e)),
- cb => s3.putBucketVersioning({
+ cb => s3.send(new CreateBucketCommand({ Bucket: bucketName }))
+ .then(() => cb())
+ .catch(cb),
+ cb => s3.send(new PutBucketVersioningCommand({
Bucket: bucketName,
VersioningConfiguration: {
Status: 'Enabled',
},
- }, err => cb(err)),
+ }))
+ .then(() => cb())
+ .catch(cb),
], done);
});
- afterEach(done => s3.deleteBucket({ Bucket: bucketName }, done));
+ afterEach(async () => {
+ await s3.send(new DeleteBucketCommand({ Bucket: bucketName }));
+ });
it('should not be able to disable versioning if replication enabled',
done => {
diff --git a/tests/functional/aws-node-sdk/test/versioning/versioningGeneral1.js b/tests/functional/aws-node-sdk/test/versioning/versioningGeneral1.js
index 3c8ac77131..ecba087ebc 100644
--- a/tests/functional/aws-node-sdk/test/versioning/versioningGeneral1.js
+++ b/tests/functional/aws-node-sdk/test/versioning/versioningGeneral1.js
@@ -1,7 +1,18 @@
const assert = require('assert');
-const { S3 } = require('aws-sdk');
const async = require('async');
+const {
+ S3Client,
+ CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ PutObjectCommand,
+ ListObjectsCommand,
+ DeleteObjectCommand,
+ ListObjectVersionsCommand,
+ DeleteObjectsCommand,
+} = require('@aws-sdk/client-s3');
+
const getConfig = require('../support/config');
const bucket = `versioning-bucket-${Date.now()}`;
@@ -22,31 +33,30 @@ function comp(v1, v2) {
return 0;
}
-
describe('aws-node-sdk test bucket versioning listing', function testSuite() {
this.timeout(600000);
let s3;
const masterVersions = [];
const allVersions = [];
- // setup test
- before(done => {
+ before(async () => {
const config = getConfig('default', { signatureVersion: 'v4' });
- s3 = new S3(config);
- s3.createBucket({ Bucket: bucket }, done);
+ s3 = new S3Client(config);
+ await s3.send(new CreateBucketCommand({ Bucket: bucket }));
});
- // delete bucket after testing
- after(done => s3.deleteBucket({ Bucket: bucket }, done));
+ after(async () => {
+ await s3.send(new DeleteBucketCommand({ Bucket: bucket }));
+ });
- it('should accept valid versioning configuration', done => {
+ it('should accept valid versioning configuration', async () => {
const params = {
Bucket: bucket,
VersioningConfiguration: {
Status: 'Enabled',
},
};
- s3.putBucketVersioning(params, done);
+ await s3.send(new PutBucketVersioningCommand(params));
});
it('should create a bunch of objects and their versions', done => {
@@ -58,12 +68,14 @@ describe('aws-node-sdk test bucket versioning listing', function testSuite() {
masterVersions.push(key);
const params = { Bucket: bucket, Key: key, Body: value };
async.timesLimit(versioncount, 10, (j, next2) =>
- s3.putObject(params, (err, data) => {
- assert.strictEqual(err, null);
- assert(data.VersionId, 'invalid versionId');
- allVersions.push({ Key: key, VersionId: data.VersionId });
- next2();
- }), next1);
+ s3.send(new PutObjectCommand(params))
+ .then(data => {
+ assert(data.VersionId, 'invalid versionId');
+ allVersions.push({ Key: key, VersionId: data.VersionId });
+ next2();
+ })
+ .catch(next2),
+ next1);
}, err => {
assert.strictEqual(err, null);
assert.strictEqual(allVersions.length, keycount * versioncount);
@@ -71,14 +83,12 @@ describe('aws-node-sdk test bucket versioning listing', function testSuite() {
});
});
- it('should list all latest versions', done => {
+ it('should list all latest versions', async () => {
const params = { Bucket: bucket, MaxKeys: 1000, Delimiter: '/' };
- s3.listObjects(params, (err, data) => {
- const keys = data.Contents.map(entry => entry.Key);
- assert.deepStrictEqual(keys.sort(), masterVersions.sort(),
- 'not same keys');
- done();
- });
+ const data = await s3.send(new ListObjectsCommand(params));
+ const keys = data.Contents.map(entry => entry.Key);
+ assert.deepStrictEqual(keys.sort(), masterVersions.sort(),
+ 'not same keys');
});
it('should create some delete markers', done => {
@@ -86,44 +96,78 @@ describe('aws-node-sdk test bucket versioning listing', function testSuite() {
async.times(keycount, (i, next) => {
const key = masterVersions[i];
const params = { Bucket: bucket, Key: key };
- s3.deleteObject(params, (err, data) => {
- assert.strictEqual(err, null);
- assert(data.VersionId, 'invalid versionId');
- allVersions.push({ Key: key, VersionId: data.VersionId });
- next();
- });
+ s3.send(new DeleteObjectCommand(params))
+ .then(data => {
+ assert(data.VersionId, 'invalid versionId');
+ allVersions.push({ Key: key, VersionId: data.VersionId });
+ next();
+ })
+ .catch(next);
}, done);
});
- it('should list all latest versions', done => {
+ it('should list all latest versions', async () => {
const params = { Bucket: bucket, MaxKeys: 1000, Delimiter: '/' };
- s3.listObjects(params, (err, data) => {
- const keys = data.Contents.map(entry => entry.Key);
- assert.deepStrictEqual(keys.sort(), masterVersions.sort().slice(15),
- 'not same keys');
- done();
- });
+ const data = await s3.send(new ListObjectsCommand(params));
+ const keys = data.Contents.map(entry => entry.Key);
+ assert.deepStrictEqual(keys.sort(), masterVersions.sort().slice(15),
+ 'not same keys');
});
it('should list all versions', done => {
const versions = [];
const params = { Bucket: bucket, MaxKeys: 15, Delimiter: '/' };
- async.retry(100, done => s3.listObjectVersions(params, (err, data) => {
- data.Versions.forEach(version => versions.push({
- Key: version.Key, VersionId: version.VersionId }));
- data.DeleteMarkers.forEach(version => versions.push({
- Key: version.Key, VersionId: version.VersionId }));
- if (data.IsTruncated) {
- params.KeyMarker = data.NextKeyMarker;
- params.VersionIdMarker = data.NextVersionIdMarker;
- return done('not done yet');
+
+ async.retry(100, done => {
+ s3.send(new ListObjectVersionsCommand(params))
+ .then(data => {
+ if (data.Versions) {
+ data.Versions.forEach(version => versions.push({
+ Key: version.Key, VersionId: version.VersionId }));
+ }
+ if (data.DeleteMarkers) {
+ data.DeleteMarkers.forEach(version => versions.push({
+ Key: version.Key, VersionId: version.VersionId }));
+ }
+ if (data.IsTruncated) {
+ params.KeyMarker = data.NextKeyMarker;
+ params.VersionIdMarker = data.NextVersionIdMarker;
+ return done('not done yet');
+ }
+ return done();
+ })
+ .catch(err => {
+ done(err);
+ });
+ }, err => {
+ if (err) {
+ return done(err);
}
- return done();
- }), () => {
+
assert.deepStrictEqual(versions.sort(comp), allVersions.sort(comp),
'not same versions');
- const params = { Bucket: bucket, Delete: { Objects: allVersions } };
- s3.deleteObjects(params, done);
+
+ const objectsToDelete = versions
+ .filter(v => v && v.Key && v.VersionId)
+ .map(v => ({
+ Key: String(v.Key),
+ VersionId: String(v.VersionId),
+ }));
+
+ const deleteParams = {
+ Bucket: bucket,
+ Delete: {
+ Objects: objectsToDelete,
+ }
+ };
+ return s3.send(new DeleteObjectsCommand(deleteParams))
+ .then(() => {
+ done();
+ })
+ .catch(err => {
+ done(err);
+ });
});
});
});
+
diff --git a/tests/functional/aws-node-sdk/test/versioning/versioningGeneral2.js b/tests/functional/aws-node-sdk/test/versioning/versioningGeneral2.js
index f38a2d2b71..a7dc1b7ee6 100644
--- a/tests/functional/aws-node-sdk/test/versioning/versioningGeneral2.js
+++ b/tests/functional/aws-node-sdk/test/versioning/versioningGeneral2.js
@@ -1,5 +1,15 @@
const assert = require('assert');
-const { S3 } = require('aws-sdk');
+const {
+ S3Client,
+ CreateBucketCommand,
+ DeleteBucketCommand,
+ PutBucketVersioningCommand,
+ GetBucketVersioningCommand,
+ PutObjectCommand,
+ GetObjectCommand,
+ DeleteObjectCommand,
+ DeleteObjectsCommand,
+} = require('@aws-sdk/client-s3');
const async = require('async');
const getConfig = require('../support/config');
@@ -12,40 +22,36 @@ describe('aws-node-sdk test bucket versioning', function testSuite() {
const versionIds = [];
const counter = 100;
- // setup test
- before(done => {
+ before(async () => {
const config = getConfig('default', { signatureVersion: 'v4' });
- s3 = new S3(config);
- s3.createBucket({ Bucket: bucket }, done);
+ s3 = new S3Client(config);
+ await s3.send(new CreateBucketCommand({ Bucket: bucket }));
});
- // delete bucket after testing
- after(done => s3.deleteBucket({ Bucket: bucket }, done));
+ after(() => s3.send(new DeleteBucketCommand({ Bucket: bucket })));
it('should not accept empty versioning configuration', done => {
const params = {
Bucket: bucket,
VersioningConfiguration: {},
};
- s3.putBucketVersioning(params, error => {
- if (error) {
- assert.strictEqual(error.statusCode, 400);
+ s3.send(new PutBucketVersioningCommand(params))
+ .then(() => {
+ done('accepted empty versioning configuration');
+ })
+ .catch(error => {
+ assert.strictEqual(error.$metadata?.httpStatusCode, 400);
assert.strictEqual(
- error.code, 'IllegalVersioningConfigurationException');
+ error.name, 'IllegalVersioningConfigurationException');
done();
- } else {
- done('accepted empty versioning configuration');
- }
- });
+ });
});
- it('should retrieve an empty versioning configuration', done => {
+ it('should retrieve an empty versioning configuration', async () => {
const params = { Bucket: bucket };
- s3.getBucketVersioning(params, (error, data) => {
- assert.strictEqual(error, null);
- assert.deepStrictEqual(data, {});
- done();
- });
+ const {$metadata, ...data} = await s3.send(new GetBucketVersioningCommand(params));
+ assert.strictEqual($metadata?.httpStatusCode, 200);
+ assert.deepStrictEqual(data, {});
});
it('should not accept versioning configuration w/o "Status"', done => {
@@ -55,25 +61,23 @@ describe('aws-node-sdk test bucket versioning', function testSuite() {
MFADelete: 'Enabled',
},
};
- s3.putBucketVersioning(params, error => {
- if (error) {
- assert.strictEqual(error.statusCode, 400);
+ s3.send(new PutBucketVersioningCommand(params))
+ .then(() => {
+ done('accepted empty versioning configuration');
+ })
+ .catch(error => {
+ assert.strictEqual(error.$metadata?.httpStatusCode, 400);
assert.strictEqual(
- error.code, 'IllegalVersioningConfigurationException');
+ error.name, 'IllegalVersioningConfigurationException');
done();
- } else {
- done('accepted empty versioning configuration');
- }
- });
+ });
});
- it('should retrieve an empty versioning configuration', done => {
+ it('should retrieve an empty versioning configuration', async () => {
const params = { Bucket: bucket };
- s3.getBucketVersioning(params, (error, data) => {
- assert.strictEqual(error, null);
- assert.deepStrictEqual(data, {});
- done();
- });
+ const {$metadata, ...data} = await s3.send(new GetBucketVersioningCommand(params));
+ assert.strictEqual($metadata?.httpStatusCode, 200);
+ assert.deepStrictEqual(data, {});
});
it('should not accept versioning configuration w/ invalid value', done => {
@@ -84,73 +88,67 @@ describe('aws-node-sdk test bucket versioning', function testSuite() {
Status: 'let\'s do it',
},
};
- s3.putBucketVersioning(params, error => {
- if (error) {
- assert.strictEqual(error.statusCode, 400);
+ s3.send(new PutBucketVersioningCommand(params))
+ .then(() => {
+ done('accepted empty versioning configuration');
+ })
+ .catch(error => {
+ assert.strictEqual(error.$metadata?.httpStatusCode, 400);
assert.strictEqual(
- error.code, 'IllegalVersioningConfigurationException');
+ error.name, 'IllegalVersioningConfigurationException');
done();
- } else {
- done('accepted empty versioning configuration');
- }
- });
+ });
});
- it('should retrieve an empty versioning configuration', done => {
+ it('should retrieve an empty versioning configuration', async () => {
const params = { Bucket: bucket };
- s3.getBucketVersioning(params, (error, data) => {
- assert.strictEqual(error, null);
- assert.deepStrictEqual(data, {});
- done();
- });
+ const {$metadata, ...data} = await s3.send(new GetBucketVersioningCommand(params));
+ assert.strictEqual($metadata?.httpStatusCode, 200);
+ assert.deepStrictEqual(data, {});
});
it('should create a non-versioned object', done => {
const params = { Bucket: bucket, Key: '/' };
- s3.putObject(params, err => {
- assert.strictEqual(err, null);
- s3.getObject(params, err => {
- assert.strictEqual(err, null);
- done();
- });
- });
+ s3.send(new PutObjectCommand(params))
+ .then(() => s3.send(new GetObjectCommand(params)))
+ .then(() => done())
+ .catch(done);
});
- it('should accept valid versioning configuration', done => {
+ it('should accept valid versioning configuration', async () => {
const params = {
Bucket: bucket,
VersioningConfiguration: {
Status: 'Enabled',
},
};
- s3.putBucketVersioning(params, done);
+ await s3.send(new PutBucketVersioningCommand(params));
});
- it('should retrieve the valid versioning configuration', done => {
+ it('should retrieve the valid versioning configuration', async () => {
const params = { Bucket: bucket };
- s3.getBucketVersioning(params, (error, data) => {
- assert.strictEqual(error, null);
- assert.deepStrictEqual(data, { Status: 'Enabled' });
- done();
- });
+ const data = await s3.send(new GetBucketVersioningCommand(params));
+ assert.deepStrictEqual(data.Status, 'Enabled');
});
it('should create a new version for an object', done => {
const params = { Bucket: bucket, Key: '/' };
- s3.putObject(params, (err, data) => {
- assert.strictEqual(err, null);
- params.VersionId = data.VersionId;
- versionIds.push(data.VersionId);
- s3.getObject(params, (err, data) => {
- assert.strictEqual(err, null);
+ s3.send(new PutObjectCommand(params))
+ .then(data => {
+ params.VersionId = data.VersionId;
+ versionIds.push(data.VersionId);
+ return s3.send(new GetObjectCommand(params));
+ })
+ .then(data => {
assert.strictEqual(params.VersionId, data.VersionId,
'version ids are not equal');
// TODO compare the value of null version and the original
// version when find out how to include value in the put
params.VersionId = 'null';
- s3.getObject(params, done);
- });
- });
+ return s3.send(new GetObjectCommand(params));
+ })
+ .then(() => done())
+ .catch(done);
});
it('should create new versions but still keep nullVersionId', done => {
@@ -158,71 +156,70 @@ describe('aws-node-sdk test bucket versioning', function testSuite() {
const paramsNull = { Bucket: bucket, Key: '/', VersionId: 'null' };
let nullVersionId;
// create new versions
- async.timesSeries(counter, (i, next) => s3.putObject(params,
- (err, data) => {
- versionIds.push(data.VersionId);
- // get the 'null' version
- s3.getObject(paramsNull, (err, data) => {
- assert.strictEqual(err, null);
+ async.timesSeries(counter, (i, next) => {
+ s3.send(new PutObjectCommand(params))
+ .then(data => {
+ versionIds.push(data.VersionId);
+ // get the 'null' version
+ return s3.send(new GetObjectCommand(paramsNull));
+ })
+ .then(data => {
if (nullVersionId === undefined) {
nullVersionId = data.VersionId;
}
// what to expect: nullVersionId should be the same
assert(nullVersionId, 'nullVersionId should be valid');
assert.strictEqual(nullVersionId, data.VersionId);
- next(err);
- });
- }), done);
+ next();
+ })
+ .catch(next);
+ }, done);
});
- it('should accept valid versioning configuration', done => {
+ it('should accept valid versioning configuration', async () => {
const params = {
Bucket: bucket,
VersioningConfiguration: {
Status: 'Suspended',
},
};
- s3.putBucketVersioning(params, done);
+ await s3.send(new PutBucketVersioningCommand(params));
});
- it('should retrieve the valid versioning configuration', done => {
+ it('should retrieve the valid versioning configuration', async () => {
const params = { Bucket: bucket };
- // s3.getBucketVersioning(params, done);
- s3.getBucketVersioning(params, (error, data) => {
- assert.strictEqual(error, null);
- assert.deepStrictEqual(data, { Status: 'Suspended' });
- done();
- });
+ const data = await s3.send(new GetBucketVersioningCommand(params));
+ assert.deepStrictEqual(data.Status, 'Suspended');
});
it('should update null version in versioning suspended bucket', done => {
const params = { Bucket: bucket, Key: '/' };
const paramsNull = { Bucket: bucket, Key: '/', VersionId: 'null' };
- // let nullVersionId = undefined;
- // let newNullVersionId = undefined;
+
async.waterfall([
- callback => s3.getObject(paramsNull, err => {
- assert.strictEqual(err, null);
- // nullVersionId = data.VersionId;
- callback();
- }),
- callback => s3.putObject(params, err => {
- assert.strictEqual(err, null);
- versionIds.push('null');
- callback();
- }),
- callback => s3.getObject(paramsNull, (err, data) => {
- assert.strictEqual(err, null);
- assert.strictEqual(data.VersionId, 'null',
- 'version ids are equal');
- callback();
- }),
- callback => s3.getObject(params, (err, data) => {
- assert.strictEqual(err, null);
- assert.strictEqual(data.VersionId, 'null',
- 'version ids are not equal');
- callback();
- }),
+ callback => s3.send(new GetObjectCommand(paramsNull))
+ .then(() => callback())
+ .catch(callback),
+ callback => s3.send(new PutObjectCommand(params))
+ .then(() => {
+ versionIds.push('null');
+ callback();
+ })
+ .catch(callback),
+ callback => s3.send(new GetObjectCommand(paramsNull))
+ .then(data => {
+ assert.strictEqual(data.VersionId, 'null',
+ 'version ids are equal');
+ callback();
+ })
+ .catch(callback),
+ callback => s3.send(new GetObjectCommand(params))
+ .then(data => {
+ assert.strictEqual(data.VersionId, 'null',
+ 'version ids are not equal');
+ callback();
+ })
+ .catch(callback),
], done);
});
@@ -236,78 +233,96 @@ describe('aws-node-sdk test bucket versioning', function testSuite() {
const params = { Bucket: bucket, Key: '/' };
const paramsNull = { Bucket: bucket, Key: '/', VersionId: 'null' };
let nullVersionId;
+
async.waterfall([
- callback => s3.getObject(paramsNull, (err, data) => {
- assert.strictEqual(err, null);
- nullVersionId = data.VersionId;
- callback();
- }),
- callback => s3.putBucketVersioning(paramsVersioning,
- err => callback(err)),
+ callback => s3.send(new GetObjectCommand(paramsNull))
+ .then(data => {
+ nullVersionId = data.VersionId;
+ callback();
+ })
+ .catch(callback),
+ callback => s3.send(new PutBucketVersioningCommand(paramsVersioning))
+ .then(() => callback())
+ .catch(callback),
callback => async.timesSeries(counter, (i, next) =>
- s3.putObject(params, (err, data) => {
- assert.strictEqual(err, null);
- versionIds.push(data.VersionId);
- next();
- }), err => callback(err)),
- callback => s3.getObject(paramsNull, (err, data) => {
- assert.strictEqual(err, null);
- assert.strictEqual(nullVersionId, data.VersionId,
- 'version ids are not equal');
- callback();
- }),
+ s3.send(new PutObjectCommand(params))
+ .then(data => {
+ versionIds.push(data.VersionId);
+ next();
+ })
+ .catch(next),
+ err => callback(err)),
+ callback => s3.send(new GetObjectCommand(paramsNull))
+ .then(data => {
+ assert.strictEqual(nullVersionId, data.VersionId,
+ 'version ids are not equal');
+ callback();
+ })
+ .catch(callback),
], done);
});
it('should create delete marker and keep the null version', done => {
const params = { Bucket: bucket, Key: '/' };
const paramsNull = { Bucket: bucket, Key: '/', VersionId: 'null' };
- s3.getObject(paramsNull, (err, data) => {
- assert.strictEqual(err, null);
- const nullVersionId = data.VersionId;
- async.timesSeries(counter, (i, next) => s3.deleteObject(params,
- (err, data) => {
- assert.strictEqual(err, null);
- versionIds.push(data.VersionId);
- s3.getObject(params, err => {
- assert.strictEqual(err.code, 'NoSuchKey');
- next();
- });
- }), err => {
- assert.strictEqual(err, null);
- s3.getObject(paramsNull, (err, data) => {
- assert.strictEqual(nullVersionId, data.VersionId,
- 'version ids are not equal');
- done();
- });
+
+ s3.send(new GetObjectCommand(paramsNull))
+ .then(data => {
+ const nullVersionId = data.VersionId;
+ async.timesSeries(counter, (i, next) => {
+ s3.send(new DeleteObjectCommand(params))
+ .then(data => {
+ versionIds.push(data.VersionId);
+ return s3.send(new GetObjectCommand(params));
+ })
+ .then(() => {
+ next(new Error('Expected NoSuchKey error'));
+ })
+ .catch(err => {
+ assert.strictEqual(err.name, 'NoSuchKey');
+ next();
+ });
+ }, err => {
+ if (err) {
+ return done(err);
+ }
+ return s3.send(new GetObjectCommand(paramsNull))
+ .then(data => {
+ assert.strictEqual(nullVersionId, data.VersionId,
+ 'version ids are not equal');
+ done();
+ })
+ .catch(done);
});
- });
+ })
+ .catch(done);
});
it('should delete latest version and get the next version', done => {
versionIds.reverse();
const params = { Bucket: bucket, Key: '/' };
+
async.timesSeries(versionIds.length, (i, next) => {
const versionId = versionIds[i];
- const nextVersionId = i < versionIds.length ?
+ const nextVersionId = i < versionIds.length - 1 ?
versionIds[i + 1] : undefined;
const paramsVersion =
{ Bucket: bucket, Key: '/', VersionId: versionId };
- s3.deleteObject(paramsVersion, err => {
- assert.strictEqual(err, null);
- s3.getObject(params, (err, data) => {
- if (err) {
- assert(err.code === 'NotFound' ||
- err.code === 'NoSuchKey', 'error');
- } else {
- assert(data.VersionId, 'invalid versionId');
- if (nextVersionId !== 'null') {
- assert.strictEqual(data.VersionId, nextVersionId);
- }
+
+ s3.send(new DeleteObjectCommand(paramsVersion))
+ .then(() => s3.send(new GetObjectCommand(params)))
+ .then(data => {
+ assert(data.VersionId, 'invalid versionId');
+ if (nextVersionId !== 'null') {
+ assert.strictEqual(data.VersionId, nextVersionId);
}
next();
+ })
+ .catch(err => {
+ assert(err.name === 'NotFound' ||
+ err.name === 'NoSuchKey', 'error');
+ next();
});
- });
}, done);
});
@@ -316,23 +331,38 @@ describe('aws-node-sdk test bucket versioning', function testSuite() {
const keycount = 50;
const versioncount = 20;
const value = '{"foo":"bar"}';
+
async.timesLimit(keycount, 10, (i, next1) => {
const key = `foo${i}`;
const params = { Bucket: bucket, Key: key, Body: value };
async.timesLimit(versioncount, 10, (j, next2) =>
- s3.putObject(params, (err, data) => {
- assert.strictEqual(err, null);
- assert(data.VersionId, 'invalid versionId');
- vids.push({ Key: key, VersionId: data.VersionId });
- next2();
- }), next1);
+ s3.send(new PutObjectCommand(params))
+ .then(data => {
+ assert(data.VersionId, 'invalid versionId');
+ vids.push({ Key: key, VersionId: data.VersionId });
+ next2();
+ })
+ .catch(next2),
+ next1);
}, err => {
- assert.strictEqual(err, null);
+ if (err) {
+ return done(err);
+ }
assert.strictEqual(vids.length, keycount * versioncount);
- const params = { Bucket: bucket, Delete: { Objects: vids } };
+ const params = {
+ Bucket: bucket,
+ Delete: {
+ Objects: vids.map(v => ({
+ Key: v.Key,
+ VersionId: v.VersionId,
+ })),
+ }
+ };
// TODO use delete marker and check with the result
process.stdout.write('creating objects done, now deleting...');
- s3.deleteObjects(params, done);
+ return s3.send(new DeleteObjectsCommand(params))
+ .then(() => done())
+ .catch(done);
});
});
});