From f26aaad287c9bf6e302fafed320c16cd26741fac Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Wed, 7 Feb 2024 11:57:31 -0500 Subject: [PATCH 1/4] refer to the bucket directly from the environment Declaring the variable as a const outside of the function scope makes it more difficult to run unit tests. Using it directly makes it easier for unit tests to control the value. --- src/getOrCreateObject/getOrCreateObject.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/getOrCreateObject/getOrCreateObject.js b/src/getOrCreateObject/getOrCreateObject.js index 0e5e6e9..ba2cf89 100644 --- a/src/getOrCreateObject/getOrCreateObject.js +++ b/src/getOrCreateObject/getOrCreateObject.js @@ -4,8 +4,6 @@ import { lookupCustomCrop } from './resizeAndSave/lookupCustomCrop.js'; import { resizeAndSave } from './resizeAndSave.js'; import { ORIGINAL_PATH_ROOT, RENDER_PATH_ROOT } from './pathConstants.js'; -const bucketName = process.env.ORIGINAL_BUCKET; - const s3 = new S3(); // Try to get an object from S3, and return either the valid response, or the error. @@ -13,7 +11,7 @@ async function tryGetObject(userRequest, s3Key) { let response; try { response = await s3.getObject({ - Bucket: bucketName, + Bucket: process.env.ORIGINAL_BUCKET, Key: s3Key, Range: userRequest.headers?.Range, }); From 4766d63f5a58627a29540b0d339f766cb6c12851 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Wed, 7 Feb 2024 12:03:33 -0500 Subject: [PATCH 2/4] add a single pixel image definition and run it through the tests, engaging the sharp library to make sure it works --- .../getOrCreateObject.test.js | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/getOrCreateObject/getOrCreateObject.test.js b/src/getOrCreateObject/getOrCreateObject.test.js index 908289a..6eaeffe 100644 --- a/src/getOrCreateObject/getOrCreateObject.test.js +++ b/src/getOrCreateObject/getOrCreateObject.test.js @@ -3,11 +3,17 @@ import { describe, it, expect } from 'vitest'; import { mockClient } from 'aws-sdk-client-mock'; import { GetObjectCommand, S3Client } from '@aws-sdk/client-s3'; import { DynamoDBDocumentClient, GetCommand } from '@aws-sdk/lib-dynamodb'; +import { Readable } from 'stream'; // Import the function to test. import { getOrCreateObject } from './getOrCreateObject.js'; process.env.DYNAMODB_TABLE = 'test-table'; +process.env.ORIGINAL_BUCKET = 'test-bucket'; + +// Create a 1 pixel jpg image as a readable stream, +// so that the sharp library has something to resize. +const singlePixelJpgReadable = Readable.from(Buffer.from('/9j/4AAQSkZJRgABAQEAAAAAAAD/2wBDAAoHBwkHBgoJCAkLCwoMDxkQDw4ODx4WFxIZJCAmJSMgIyIoLTkwKCo2KyIjMkQyNjs9QEBAJjBGS0U+Sjk/QD3/2wBDAQsLCw8NDx0QEB09KSMpPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT3/wAARCAAIAAgDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9/KKKKAP/2Q==', 'base64')); // Mock the ddb client. const ddbMock = mockClient(DynamoDBDocumentClient); @@ -19,15 +25,31 @@ ddbMock.on(GetCommand).resolves({ // Mock the s3 client. const s3Mock = mockClient(S3Client); -s3Mock.on(GetObjectCommand).resolves({ - Body: 'test', + +// Reject all GetObjectCommand calls by default. +s3Mock.on(GetObjectCommand).rejects({ Code: 'NoSuchKey' }); + +// Define an existing object in the bucket, that returns a valid and rescalable image. +s3Mock.on(GetObjectCommand, { + Bucket: 'test-bucket', + Key: 'original_media/www.bu.edu/somesite/files/01/exists.jpg', +}).resolves({ + Body: singlePixelJpgReadable, +}); + +// Define a second object in the bucket with a unicode filename. +s3Mock.on(GetObjectCommand, { + Bucket: 'test-bucket', + Key: 'original_media/www.bu.edu/site/files/01/file-with-ñ.jpg', +}).resolves({ + Body: singlePixelJpgReadable, }); describe('getOrCreateObject', () => { - it('should return an object', async () => { + it('should return an object if it exists', async () => { const result = await getOrCreateObject( { - url: 'https://example-1111.s3-object-lambda.us-east-1.amazonaws.com/somesite/files/01/example-150x150.jpg', + url: 'https://example-1111.s3-object-lambda.us-east-1.amazonaws.com/somesite/files/01/exists.jpg', headers: { }, }, 'www.bu.edu', @@ -35,10 +57,10 @@ describe('getOrCreateObject', () => { expect(result.Body).toBeDefined(); }); - it('should return an an object, and parse the crop value', async () => { + it('should find the unscaled original for the request, scale it with the parsed crop value, and return an an object', async () => { const result = await getOrCreateObject( { - url: 'https://example-1111.s3-object-lambda.us-east-1.amazonaws.com/files/01/example-758x460.jpg?resize-position=left', + url: 'https://example-1111.s3-object-lambda.us-east-1.amazonaws.com/somesite/files/01/exists-758x460.jpg?resize-position=left', headers: { }, }, 'www.bu.edu', From da3f5d8fe3e67d08ed3a6e9879498456a264a997 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Wed, 7 Feb 2024 12:11:38 -0500 Subject: [PATCH 3/4] add test for non-existent objects --- src/getOrCreateObject/getOrCreateObject.test.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/getOrCreateObject/getOrCreateObject.test.js b/src/getOrCreateObject/getOrCreateObject.test.js index 6eaeffe..c3b3539 100644 --- a/src/getOrCreateObject/getOrCreateObject.test.js +++ b/src/getOrCreateObject/getOrCreateObject.test.js @@ -78,4 +78,15 @@ describe('getOrCreateObject', () => { ); expect(result.Body).toBeDefined(); }); + + it('should return an error if the object does not exist', async () => { + const result = await getOrCreateObject( + { + url: 'https://example-1111.s3-object-lambda.us-east-1.amazonaws.com/somesite/files/01/does-not-exist.jpg', + headers: { }, + }, + 'www.bu.edu', + ); + expect(result.Code).toEqual('NoSuchKey'); + }); }); From 65d26311fc6937161d72ff233225f705e3867881 Mon Sep 17 00:00:00 2001 From: Jonathan Williams Date: Mon, 12 Feb 2024 12:57:39 -0500 Subject: [PATCH 4/4] :pencil: fix typo --- src/getOrCreateObject/getOrCreateObject.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/getOrCreateObject/getOrCreateObject.test.js b/src/getOrCreateObject/getOrCreateObject.test.js index c3b3539..a5c0a87 100644 --- a/src/getOrCreateObject/getOrCreateObject.test.js +++ b/src/getOrCreateObject/getOrCreateObject.test.js @@ -57,7 +57,7 @@ describe('getOrCreateObject', () => { expect(result.Body).toBeDefined(); }); - it('should find the unscaled original for the request, scale it with the parsed crop value, and return an an object', async () => { + it('should find the unscaled original for the request, scale it with the parsed crop value, and return an object', async () => { const result = await getOrCreateObject( { url: 'https://example-1111.s3-object-lambda.us-east-1.amazonaws.com/somesite/files/01/exists-758x460.jpg?resize-position=left',