From 679638e4ce56e8663e61a8285fece3b1c855805e Mon Sep 17 00:00:00 2001 From: Sahil Bondre Date: Tue, 11 Mar 2025 21:08:05 +0000 Subject: [PATCH 1/3] add built artifacts to .gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 40f6187b..91f8d9ef 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,7 @@ dist/ # Stores VSCode versions used for testing VSCode extensions .vscode-test + +deps/artifacts/ +deps/aws-lambda-cpp*/ +deps/curl*/ From 6e200b297c8c370c4f10fd589b9cbb95836373a4 Mon Sep 17 00:00:00 2001 From: Sahil Bondre Date: Tue, 11 Mar 2025 21:08:29 +0000 Subject: [PATCH 2/3] add module loading tests --- package-lock.json | 4 +- test/handlers/extensionless/esm-extensionless | 6 + test/handlers/extensionless/index | 8 + test/handlers/pkg-less/cjsAndMjs.js | 9 + test/handlers/pkg-less/cjsImportCjs.js | 9 + test/handlers/pkg-less/cjsImportESM.cjs | 10 ++ test/handlers/pkg-less/cjsInMjs.mjs | 8 + test/handlers/pkg-less/cjsModule.cjs | 7 + test/handlers/pkg-less/esmImportCjs.mjs | 7 + test/handlers/pkg-less/esmInCjs.cjs | 6 + test/handlers/pkg-less/esmModule.js | 9 + test/handlers/pkg-less/esmRequireCjs.mjs | 7 + test/handlers/pkg/type-cjs/cjs | 8 + test/handlers/pkg/type-cjs/cjsModule.js | 7 + test/handlers/pkg/type-cjs/esm | 6 + test/handlers/pkg/type-cjs/esmModule.js | 6 + test/handlers/pkg/type-cjs/package.json | 3 + test/handlers/pkg/type-esm/cjs | 8 + test/handlers/pkg/type-esm/cjsModule.js | 8 + test/handlers/pkg/type-esm/esm | 6 + test/handlers/pkg/type-esm/esmModule.js | 5 + test/handlers/pkg/type-esm/package.json | 3 + test/unit/UserFunctionTest.js | 161 ++++++++++++++++++ 23 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 test/handlers/extensionless/esm-extensionless create mode 100644 test/handlers/extensionless/index create mode 100644 test/handlers/pkg-less/cjsAndMjs.js create mode 100644 test/handlers/pkg-less/cjsImportCjs.js create mode 100644 test/handlers/pkg-less/cjsImportESM.cjs create mode 100644 test/handlers/pkg-less/cjsInMjs.mjs create mode 100644 test/handlers/pkg-less/cjsModule.cjs create mode 100644 test/handlers/pkg-less/esmImportCjs.mjs create mode 100644 test/handlers/pkg-less/esmInCjs.cjs create mode 100644 test/handlers/pkg-less/esmModule.js create mode 100644 test/handlers/pkg-less/esmRequireCjs.mjs create mode 100644 test/handlers/pkg/type-cjs/cjs create mode 100644 test/handlers/pkg/type-cjs/cjsModule.js create mode 100644 test/handlers/pkg/type-cjs/esm create mode 100644 test/handlers/pkg/type-cjs/esmModule.js create mode 100644 test/handlers/pkg/type-cjs/package.json create mode 100644 test/handlers/pkg/type-esm/cjs create mode 100644 test/handlers/pkg/type-esm/cjsModule.js create mode 100644 test/handlers/pkg/type-esm/esm create mode 100644 test/handlers/pkg/type-esm/esmModule.js create mode 100644 test/handlers/pkg/type-esm/package.json diff --git a/package-lock.json b/package-lock.json index a755d3ba..e632b9a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "aws-lambda-ric", - "version": "3.2.0", + "version": "3.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "aws-lambda-ric", - "version": "3.2.0", + "version": "3.2.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { diff --git a/test/handlers/extensionless/esm-extensionless b/test/handlers/extensionless/esm-extensionless new file mode 100644 index 00000000..537c57b1 --- /dev/null +++ b/test/handlers/extensionless/esm-extensionless @@ -0,0 +1,6 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +// This should fail because it's ESM syntax in a CJS context +export const handler = async (event) => { + return "This should fail"; +}; diff --git a/test/handlers/extensionless/index b/test/handlers/extensionless/index new file mode 100644 index 00000000..00b048de --- /dev/null +++ b/test/handlers/extensionless/index @@ -0,0 +1,8 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +'use strict'; +// This is a CommonJS module without file extension + +module.exports.handler = async (event) => { + return "Hello from extensionless CJS"; +}; diff --git a/test/handlers/pkg-less/cjsAndMjs.js b/test/handlers/pkg-less/cjsAndMjs.js new file mode 100644 index 00000000..b3f2ec95 --- /dev/null +++ b/test/handlers/pkg-less/cjsAndMjs.js @@ -0,0 +1,9 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +import { someESMFunction } from './esmModule.js'; // ESM import + +module.exports.handler = async (event) => { // CJS export + return someESMFunction(event); +}; + +export const esm = 'This is ESM syntax'; // ESM export diff --git a/test/handlers/pkg-less/cjsImportCjs.js b/test/handlers/pkg-less/cjsImportCjs.js new file mode 100644 index 00000000..6ba9088d --- /dev/null +++ b/test/handlers/pkg-less/cjsImportCjs.js @@ -0,0 +1,9 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +'use strict'; + +const { getMessage } = require('./cjsModule.cjs') + +exports.handler = async (_event) => { + return getMessage(); +} diff --git a/test/handlers/pkg-less/cjsImportESM.cjs b/test/handlers/pkg-less/cjsImportESM.cjs new file mode 100644 index 00000000..76aa80f9 --- /dev/null +++ b/test/handlers/pkg-less/cjsImportESM.cjs @@ -0,0 +1,10 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +'use strict'; + +// This static import is not allowed in CJS +import { getMessage } from './esmModule'; + +module.exports.handler = async () => { + return getMessage(); +}; diff --git a/test/handlers/pkg-less/cjsInMjs.mjs b/test/handlers/pkg-less/cjsInMjs.mjs new file mode 100644 index 00000000..e331a104 --- /dev/null +++ b/test/handlers/pkg-less/cjsInMjs.mjs @@ -0,0 +1,8 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +'use strict'; + +// This should fail because it's CJS syntax in a ESM context +module.exports.handler = async (_event) => { + return 'This should fail'; +}; diff --git a/test/handlers/pkg-less/cjsModule.cjs b/test/handlers/pkg-less/cjsModule.cjs new file mode 100644 index 00000000..9ffea34d --- /dev/null +++ b/test/handlers/pkg-less/cjsModule.cjs @@ -0,0 +1,7 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +'use strict'; + +module.exports.getMessage = () => { + return "Hello from CJS!"; +}; diff --git a/test/handlers/pkg-less/esmImportCjs.mjs b/test/handlers/pkg-less/esmImportCjs.mjs new file mode 100644 index 00000000..6bccc872 --- /dev/null +++ b/test/handlers/pkg-less/esmImportCjs.mjs @@ -0,0 +1,7 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +import { getMessage } from './cjsModule.cjs'; + +export const handler = async (_event) => { + return getMessage(); +}; diff --git a/test/handlers/pkg-less/esmInCjs.cjs b/test/handlers/pkg-less/esmInCjs.cjs new file mode 100644 index 00000000..57f4769b --- /dev/null +++ b/test/handlers/pkg-less/esmInCjs.cjs @@ -0,0 +1,6 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +// This should fail because it's ESM syntax in a CJS context +export const handler = async (_event) => { + return 'This should fail'; +}; diff --git a/test/handlers/pkg-less/esmModule.js b/test/handlers/pkg-less/esmModule.js new file mode 100644 index 00000000..5c6aaf24 --- /dev/null +++ b/test/handlers/pkg-less/esmModule.js @@ -0,0 +1,9 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +export const handler = async (_event) => { + return 'Hello from ESM.js'; +}; + +export const getMessage = () => { + return "Hello from ESM!"; +}; diff --git a/test/handlers/pkg-less/esmRequireCjs.mjs b/test/handlers/pkg-less/esmRequireCjs.mjs new file mode 100644 index 00000000..e7d84f1d --- /dev/null +++ b/test/handlers/pkg-less/esmRequireCjs.mjs @@ -0,0 +1,7 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +const { getMessage } = require('./cjsModule.cjs') + +export const handler = async (_event) => { + return getMessage(); +}; diff --git a/test/handlers/pkg/type-cjs/cjs b/test/handlers/pkg/type-cjs/cjs new file mode 100644 index 00000000..00b048de --- /dev/null +++ b/test/handlers/pkg/type-cjs/cjs @@ -0,0 +1,8 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +'use strict'; +// This is a CommonJS module without file extension + +module.exports.handler = async (event) => { + return "Hello from extensionless CJS"; +}; diff --git a/test/handlers/pkg/type-cjs/cjsModule.js b/test/handlers/pkg/type-cjs/cjsModule.js new file mode 100644 index 00000000..0ef96cf3 --- /dev/null +++ b/test/handlers/pkg/type-cjs/cjsModule.js @@ -0,0 +1,7 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +'use strict'; + +module.exports.handler = async (_event) => { + return 'Hello from CJS.js'; +}; diff --git a/test/handlers/pkg/type-cjs/esm b/test/handlers/pkg/type-cjs/esm new file mode 100644 index 00000000..537c57b1 --- /dev/null +++ b/test/handlers/pkg/type-cjs/esm @@ -0,0 +1,6 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +// This should fail because it's ESM syntax in a CJS context +export const handler = async (event) => { + return "This should fail"; +}; diff --git a/test/handlers/pkg/type-cjs/esmModule.js b/test/handlers/pkg/type-cjs/esmModule.js new file mode 100644 index 00000000..57f4769b --- /dev/null +++ b/test/handlers/pkg/type-cjs/esmModule.js @@ -0,0 +1,6 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +// This should fail because it's ESM syntax in a CJS context +export const handler = async (_event) => { + return 'This should fail'; +}; diff --git a/test/handlers/pkg/type-cjs/package.json b/test/handlers/pkg/type-cjs/package.json new file mode 100644 index 00000000..5bbefffb --- /dev/null +++ b/test/handlers/pkg/type-cjs/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/test/handlers/pkg/type-esm/cjs b/test/handlers/pkg/type-esm/cjs new file mode 100644 index 00000000..00b048de --- /dev/null +++ b/test/handlers/pkg/type-esm/cjs @@ -0,0 +1,8 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +'use strict'; +// This is a CommonJS module without file extension + +module.exports.handler = async (event) => { + return "Hello from extensionless CJS"; +}; diff --git a/test/handlers/pkg/type-esm/cjsModule.js b/test/handlers/pkg/type-esm/cjsModule.js new file mode 100644 index 00000000..e331a104 --- /dev/null +++ b/test/handlers/pkg/type-esm/cjsModule.js @@ -0,0 +1,8 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +'use strict'; + +// This should fail because it's CJS syntax in a ESM context +module.exports.handler = async (_event) => { + return 'This should fail'; +}; diff --git a/test/handlers/pkg/type-esm/esm b/test/handlers/pkg/type-esm/esm new file mode 100644 index 00000000..537c57b1 --- /dev/null +++ b/test/handlers/pkg/type-esm/esm @@ -0,0 +1,6 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +// This should fail because it's ESM syntax in a CJS context +export const handler = async (event) => { + return "This should fail"; +}; diff --git a/test/handlers/pkg/type-esm/esmModule.js b/test/handlers/pkg/type-esm/esmModule.js new file mode 100644 index 00000000..e0f37504 --- /dev/null +++ b/test/handlers/pkg/type-esm/esmModule.js @@ -0,0 +1,5 @@ +/** Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. */ + +export const handler = async (_event) => { + return 'Hello from ESM.js'; +}; diff --git a/test/handlers/pkg/type-esm/package.json b/test/handlers/pkg/type-esm/package.json new file mode 100644 index 00000000..3dbc1ca5 --- /dev/null +++ b/test/handlers/pkg/type-esm/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/test/unit/UserFunctionTest.js b/test/unit/UserFunctionTest.js index 6ffe4c0b..d1657fcf 100644 --- a/test/unit/UserFunctionTest.js +++ b/test/unit/UserFunctionTest.js @@ -10,6 +10,7 @@ const { HandlerNotFound, ImportModuleError, MalformedHandlerName, + UserCodeSyntaxError, } = require('lambda-runtime/Errors.js'); const UserFunction = require('lambda-runtime/UserFunction.js'); @@ -250,6 +251,166 @@ describe('UserFunction.load method', () => { response.should.be.resolvedWith('moon'); }); + + it('should successfully load a CJS handler from extensionless file (no package.json)', async () => { + const handler = await UserFunction.load( + path.join(HANDLERS_ROOT, 'extensionless'), + 'index.handler', + ); + const response = await handler('test event'); + + response.should.equal('Hello from extensionless CJS'); + }); + + it('should fail to load ESM syntax from extensionless file (no package.json)', async () => { + await UserFunction.load( + path.join(HANDLERS_ROOT, 'extensionless'), + 'esm-extensionless.handler', + ).should.be.rejectedWith(UserCodeSyntaxError); + }); + + it('should load CJS handler from extensionless file with type:commonjs', async () => { + // package.json is ignored in the case of extensionless + const handler = await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg', 'type-cjs'), + 'cjs.handler', + ); + const response = await handler('test event'); + + response.should.equal('Hello from extensionless CJS'); + }); + + it('should fail to load ESM handler from extensionless file with type:commonjs', async () => { + // package.json is ignored in the case of extensionless + await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg', 'type-cjs'), + 'esm.handler', + ).should.be.rejectedWith(UserCodeSyntaxError); + }); + + it('should load CJS handler from extensionless file with type:module', async () => { + // package.json is ignored in the case of extensionless + const handler = await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg', 'type-esm'), + 'cjs.handler', + ); + const response = await handler('test event'); + + response.should.equal('Hello from extensionless CJS'); + }); + + it('should fail to load ESM handler from extensionless file with type:module', async () => { + // package.json is ignored in the case of extensionless + await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg', 'type-esm'), + 'esm.handler', + ).should.be.rejectedWith(UserCodeSyntaxError); + }); + + it('should load CJS handler from JS file with type:commonjs', async () => { + const handler = await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg', 'type-cjs'), + 'cjsModule.handler', + ); + const response = await handler('test event'); + + response.should.equal('Hello from CJS.js'); + }); + + it('should fail to load ESM handler from JS file with type:commonjs', async () => { + await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg', 'type-cjs'), + 'esmModule.handler', + ).should.be.rejectedWith(UserCodeSyntaxError); + }); + + it('should load ESM handler from JS file with type:module', async () => { + const handler = await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg', 'type-esm'), + 'esmModule.handler', + ); + const response = await handler('test event'); + + response.should.equal('Hello from ESM.js'); + }); + + it('should fail to load CJS handler from JS file with type:module', async () => { + await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg', 'type-esm'), + 'cjsModule.handler', + ).should.be.rejectedWith( + ReferenceError, + /module is not defined in ES module scope/, + ); + }); + + it('should fail to load ESM handler from JS file without type context', async () => { + await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg-less'), + 'esmModule.handler', + ).should.be.rejectedWith(UserCodeSyntaxError); + }); + + it('should fail to load CJS handler from MJS file without type context', async () => { + await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg-less'), + 'cjsInMjs.handler', + ).should.be.rejectedWith( + ReferenceError, + /module is not defined in ES module scope/, + ); + }); + + it('should fail to load ESM handler from CJS file without type context', async () => { + await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg-less'), + 'esmInCjs.handler', + ).should.be.rejectedWith(UserCodeSyntaxError); + }); + + it('should fail to load mixed context handler from JS file without type context', async () => { + await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg-less'), + 'cjsAndMjs.handler', + ).should.be.rejectedWith(UserCodeSyntaxError); + }); + + it('should successfully load ESM handler importing from CJS', async () => { + const handler = await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg-less'), + 'esmImportCjs.handler', + ); + + const response = await handler(); + response.should.equal('Hello from CJS!'); + }); + + it('should fail when CJS tries to import from ESM using static import', async () => { + await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg-less'), + 'cjsImportESM.handler', + ).should.be.rejectedWith(UserCodeSyntaxError); + }); + + it('should successfully load CJS handler importing from CJS', async () => { + const handler = await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg-less'), + 'cjsImportCjs.handler', + ); + + const response = await handler(); + response.should.equal('Hello from CJS!'); + }); + + it('should fail when using require in .mjs', async () => { + await UserFunction.load( + path.join(HANDLERS_ROOT, 'pkg-less'), + 'esmRequireCjs.handler', + ).should.be.rejectedWith( + ReferenceError, + /require is not defined in ES module scope/, + ); + }); }); describe('type guards HandlerFunction', () => { From 2ab3fbc0d62025b6ee98d31bb71b397694d85817 Mon Sep 17 00:00:00 2001 From: Sahil Bondre Date: Wed, 12 Mar 2025 11:31:43 +0000 Subject: [PATCH 3/3] add instructions to not miss package-lock.json changes --- .github/PULL_REQUEST_TEMPLATE.md | 3 +++ README.md | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 19904207..44eb4ddb 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,4 +4,7 @@ _Description of changes:_ _Target (OCI, Managed Runtime, both):_ +## Checklist +- [ ] I have run `npm install` to generate the `package-lock.json` correctly and included it in the PR. + By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license. diff --git a/README.md b/README.md index 97d3fad5..789180cf 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,13 @@ Then, * to run integration tests: `make test-integ` * to run smoke tests: `make test-smoke` +### Raising a PR +When modifying dependencies (`package.json`), make sure to: +1. Run `npm install` to generate an updated `package-lock.json` +2. Commit both `package.json` and `package-lock.json` together + +We require package-lock.json to be checked in to ensure consistent installations across development environments. + ### Troubleshooting While running integration tests, you might encounter the Docker Hub rate limit error with the following body: