diff --git a/.eslintrc b/.eslintrc index a8a67a4..2cc4f32 100644 --- a/.eslintrc +++ b/.eslintrc @@ -9,6 +9,7 @@ }, "globals": { // Allow specific global types present in the k6 JS runtime natively + "ArrayBuffer": "readonly", "Uint8Array": "readonly", "Set": "readonly", "console": "readonly", diff --git a/localstack/init/ready.d/s3.sh b/localstack/init/ready.d/s3.sh index 70af45b..eebaec9 100755 --- a/localstack/init/ready.d/s3.sh +++ b/localstack/init/ready.d/s3.sh @@ -5,7 +5,7 @@ BUCKET="test-jslib-aws" # The localstack exposes its init script in the `/etc/localstack/init` folder. # For convinience we've setup a `testdata` folder in the same directory. testdata_folder="/etc/localstack/init/testdata/s3" -testdata_files="bonjour.txt tschuss.txt delete.txt" +testdata_files="bonjour.txt tschuss.txt delete.txt z-load-impact.png" # Create the test-jslib-aws bucket awslocal s3api create-bucket \ diff --git a/localstack/init/testdata/s3/z-load-impact.png b/localstack/init/testdata/s3/z-load-impact.png new file mode 100644 index 0000000..390babc Binary files /dev/null and b/localstack/init/testdata/s3/z-load-impact.png differ diff --git a/package-lock.json b/package-lock.json index eafce00..7c425a4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "@babel/plugin-transform-block-scoping": "^7.14.1", "@babel/preset-env": "^7.4.4", "@babel/preset-typescript": "^7.16.7", - "@types/k6": "^0.45.0", + "@types/k6": "^0.51.0", "@types/uuid": "^3.4.0", "@types/webpack": "^5.28.0", "@typescript-eslint/eslint-plugin": "^6.11.0", @@ -2170,9 +2170,9 @@ "dev": true }, "node_modules/@types/k6": { - "version": "0.45.3", - "resolved": "https://registry.npmjs.org/@types/k6/-/k6-0.45.3.tgz", - "integrity": "sha512-HkB61Bz08E9462J72igdDf+M6uMn5GLEIYUxfojWcOm/7lLEapySgsEPVXYRyPbCX/xUn77iCG8PxOJnndNZzQ==", + "version": "0.51.0", + "resolved": "https://registry.npmjs.org/@types/k6/-/k6-0.51.0.tgz", + "integrity": "sha512-xelcvFGPI4VYrV5ozADmRuFQBKmDqDRzxfHVuCDD1/firZiSQvTP0pntxHuYUSkRyL8I83kvABXUlnLYNT2VuA==", "dev": true }, "node_modules/@types/minimatch": { diff --git a/package.json b/package.json index 72d1356..399664a 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@babel/plugin-transform-block-scoping": "^7.14.1", "@babel/preset-env": "^7.4.4", "@babel/preset-typescript": "^7.16.7", - "@types/k6": "^0.45.0", + "@types/k6": "^0.51.0", "@types/uuid": "^3.4.0", "@types/webpack": "^5.28.0", "@typescript-eslint/eslint-plugin": "^6.11.0", diff --git a/src/internal/s3.ts b/src/internal/s3.ts index f9debdf..18a5073 100644 --- a/src/internal/s3.ts +++ b/src/internal/s3.ts @@ -1,4 +1,3 @@ -import { bytes } from 'k6' import { parseHTML } from 'k6/html' import http, { RefinedResponse, ResponseType } from 'k6/http' @@ -62,6 +61,7 @@ export class S3Client extends AWSClient { const res = await http.asyncRequest(method, signedRequest.url, signedRequest.body || null, { headers: signedRequest.headers, + responseType: 'text', }) this._handle_error('ListBuckets', res) @@ -121,6 +121,7 @@ export class S3Client extends AWSClient { const res = await http.asyncRequest(method, signedRequest.url, signedRequest.body || null, { headers: signedRequest.headers, + responseType: 'text', }) this._handle_error('ListObjectsV2', res) @@ -164,11 +165,16 @@ export class S3Client extends AWSClient { * * @param {string} bucketName - The bucket name containing the object. * @param {string} objectKey - Key of the object to get. + * @param {string} responseType - The desired interpretation of the response body ('text' or 'binary'). * @return {S3Object} - returns the content of the fetched S3 Object. * @throws {S3ServiceError} * @throws {InvalidSignatureError} */ - async getObject(bucketName: string, objectKey: string): Promise { + async getObject( + bucketName: string, + objectKey: string, + responseType: string = 'text' + ): Promise { // Prepare request const method = 'GET' @@ -184,6 +190,7 @@ export class S3Client extends AWSClient { const res = await http.asyncRequest(method, signedRequest.url, null, { headers: signedRequest.headers, + responseType: responseType as ResponseType, }) this._handle_error('GetObject', res) @@ -344,6 +351,7 @@ export class S3Client extends AWSClient { const res = await http.asyncRequest(method, signedRequest.url, signedRequest.body || null, { headers: signedRequest.headers, + responseType: 'text', }) this._handle_error('CreateMultipartUpload', res) @@ -537,7 +545,7 @@ export class S3Object { etag: string size: number storageClass: StorageClass - data?: string | bytes | null + data?: string | ArrayBuffer | null /** * Create an S3 Object @@ -547,7 +555,7 @@ export class S3Object { * @param {string} etag - S3 object's etag * @param {number} size - S3 object's size * @param {StorageClass} storageClass - S3 object's storage class - * @param {string | bytes | null} data=null - S3 Object's data + * @param {string | ArrayBuffer | null} data=null - S3 Object's data */ constructor( key: string, @@ -555,7 +563,7 @@ export class S3Object { etag: string, size: number, storageClass: StorageClass, - data?: string | bytes | null + data?: string | ArrayBuffer | null ) { this.key = key this.lastModified = lastModified diff --git a/tests/index.js b/tests/index.js index 7ea2685..8025ebb 100644 --- a/tests/index.js +++ b/tests/index.js @@ -58,6 +58,10 @@ const testData = { key: 'delete.txt', body: 'Delete me in a test!', }, + { + key: 'z-load-impact.png', + body: open('../localstack/init/testdata/s3/z-load-impact.png', 'b'), + }, ], }, diff --git a/tests/internal/s3.js b/tests/internal/s3.js index a65c0e8..0b9c760 100644 --- a/tests/internal/s3.js +++ b/tests/internal/s3.js @@ -11,7 +11,7 @@ export async function s3TestSuite(data) { s3Client.endpoint = s3Endpoint await asyncDescribe('s3.listBuckets', async (expect) => { - let buckets; + let buckets // Act buckets = await s3Client.listBuckets() @@ -28,10 +28,11 @@ export async function s3TestSuite(data) { // Assert expect(objects).to.be.an('array') - expect(objects).to.have.lengthOf(3) + expect(objects).to.have.lengthOf(4) expect(objects[0].key).to.equal('bonjour.txt') expect(objects[1].key).to.equal('delete.txt') expect(objects[2].key).to.equal('tschuss.txt') + expect(objects[3].key).to.equal('z-load-impact.png') }) await asyncDescribe('s3.getObject', async (expect) => { @@ -46,6 +47,12 @@ export async function s3TestSuite(data) { data.s3.testObjects[1].key ) + const gotBinaryObject = await s3Client.getObject( + data.s3.testBucketName, + data.s3.testObjects[3].key, + 'binary' + ) + let getObjectFromNonExistingBucketError try { await s3Client.getObject('non-existent-bucket', data.s3.testObjects[0].key) @@ -67,6 +74,10 @@ export async function s3TestSuite(data) { expect(gotSecondObject).to.be.an('object') expect(gotSecondObject.key).to.equal(data.s3.testObjects[1].key) expect(gotSecondObject.data).to.equal(data.s3.testObjects[1].body) + expect(gotBinaryObject).to.be.an('object') + expect(gotBinaryObject.data).to.be.an.instanceof(ArrayBuffer) + expect(gotBinaryObject.key).to.equal(data.s3.testObjects[3].key) + expect(gotBinaryObject.data.byteLength).to.equal(data.s3.testObjects[3].body.byteLength) expect(getObjectFromNonExistingBucketError).to.not.be.undefined expect(getObjectFromNonExistingBucketError).to.be.an.instanceOf(S3ServiceError) expect(getNonExistingObjectError).to.not.be.undefined