From c39b0b33f80e6bab2cbe47a666062ac400c15365 Mon Sep 17 00:00:00 2001 From: Ian Hou <45278651+iankhou@users.noreply.github.com> Date: Thu, 6 Feb 2025 13:28:43 -0500 Subject: [PATCH 1/6] do not skip bundling for stacks during CDK Import, otherwise fails --- packages/aws-cdk/lib/cli/user-configuration.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/aws-cdk/lib/cli/user-configuration.ts b/packages/aws-cdk/lib/cli/user-configuration.ts index caf865bc4107a..b4e40c94a6194 100644 --- a/packages/aws-cdk/lib/cli/user-configuration.ts +++ b/packages/aws-cdk/lib/cli/user-configuration.ts @@ -41,6 +41,7 @@ const BUNDLING_COMMANDS = [ Command.SYNTH, Command.SYNTHESIZE, Command.WATCH, + Command.IMPORT, ]; export type Arguments = { From 2becfd2df73eac636c1bdb7b5ff728bfd504f813 Mon Sep 17 00:00:00 2001 From: Ian Hou <45278651+iankhou@users.noreply.github.com> Date: Thu, 6 Feb 2025 15:56:23 -0500 Subject: [PATCH 2/6] integration test ensures that NodeJSFunction lambda is bundled --- .../test/integ.nodejs.build.images.ts | 52 +++++++++++++++++-- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts index 87e6168c831fc..c50bcba9cd96c 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts @@ -1,7 +1,9 @@ import * as path from 'path'; -import { App, Stack, StackProps } from 'aws-cdk-lib'; +import * as fs from 'fs'; +import { App, Stack, StackProps, ValidationError } from 'aws-cdk-lib'; import { Construct } from 'constructs'; -import * as lambda from 'aws-cdk-lib/aws-lambda-nodejs'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as lambdaNodeJs from 'aws-cdk-lib/aws-lambda-nodejs'; import { ExpectedResult, IntegTest } from '@aws-cdk/integ-tests-alpha'; import { IFunction, Runtime } from 'aws-cdk-lib/aws-lambda'; @@ -18,13 +20,13 @@ class TestStack extends Stack { const uniqueRuntimes: Runtime[] = runtimes.filter((value, index, array) => array.findIndex(value1 => value1.runtimeEquals(value)) === index); uniqueRuntimes.forEach((runtime) => { - this.lambdaFunctions.push(new lambda.NodejsFunction(this, `func-${runtime.name}`, { + this.lambdaFunctions.push(new lambdaNodeJs.NodejsFunction(this, `func-${runtime.name}`, { entry: path.join(__dirname, 'integ-handlers/dependencies.ts'), runtime: runtime, bundling: { minify: true, sourceMap: true, - sourceMapMode: lambda.SourceMapMode.BOTH, + sourceMapMode: lambdaNodeJs.SourceMapMode.BOTH, }, })); }); @@ -49,3 +51,45 @@ stack.lambdaFunctions.forEach(func=> { ExecutedVersion: '$LATEST', })); }); + +// Ensure that the code is bundled +const assembly = app.synth(); + +stack.lambdaFunctions.forEach((func) => { + // Find the S3 bucket and key from the stack's template + const template = assembly.getStackArtifact(stack.artifactId).template; + const resourceName = stack.getLogicalId(func.node.defaultChild as lambda.CfnFunction); + const resource = template.Resources[resourceName]; + + if (!resource || resource.Type !== 'AWS::Lambda::Function') { + throw new ValidationError(`Could not find Lambda function resource for ${func.functionName}`, stack); + } + + const s3Bucket = resource.Properties.Code.S3Bucket; + const s3Key = resource.Properties.Code.S3Key; + + if (!s3Bucket || !s3Key) { + throw new ValidationError(`Could not find S3 location for function ${func.functionName}`, stack); + } + + const assetId = s3Key.split('.')[1]; // The format is "asset..zip" + const fullAssetPath = path.join(assembly.directory, `asset.${assetId}`); + + if (!fs.existsSync(fullAssetPath)) { + throw new ValidationError(`Asset file does not exist for function ${func.functionName}`, stack); + } + + const bundledContent = fs.readFileSync(fullAssetPath, 'utf-8'); + + if (!bundledContent.includes('exports.handler =')) { + throw new ValidationError(`Bundled content does not contain expected handler export for function ${func.functionName}`, stack); + } + + if (bundledContent.includes('import ')) { + throw new ValidationError(`Bundled content contains unexpected import statement for function ${func.functionName}`, stack); + } + + if (!bundledContent.includes('//# sourceMappingURL=')) { + throw new ValidationError(`Bundled content does not contain source map for function ${func.functionName}`, stack); + } +}); From 1dfd99a731e8d5ddfdc855ce2d98b7c770e4e8ff Mon Sep 17 00:00:00 2001 From: Ian Hou <45278651+iankhou@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:26:34 -0500 Subject: [PATCH 3/6] corrected some bad logic in integ test --- .../test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts index c50bcba9cd96c..c196c84162586 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts @@ -72,7 +72,7 @@ stack.lambdaFunctions.forEach((func) => { throw new ValidationError(`Could not find S3 location for function ${func.functionName}`, stack); } - const assetId = s3Key.split('.')[1]; // The format is "asset..zip" + const assetId = s3Key.split('.')[0]; // The format is ".zip" const fullAssetPath = path.join(assembly.directory, `asset.${assetId}`); if (!fs.existsSync(fullAssetPath)) { From 26761db4039887905120c09391a1a34e46e40b31 Mon Sep 17 00:00:00 2001 From: Ian Hou <45278651+iankhou@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:56:44 -0500 Subject: [PATCH 4/6] check for dir instead of file --- .../test/integ.nodejs.build.images.ts | 42 +++++++++++++------ 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts index c196c84162586..a1982a2b9aba1 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts @@ -56,40 +56,56 @@ stack.lambdaFunctions.forEach(func=> { const assembly = app.synth(); stack.lambdaFunctions.forEach((func) => { - // Find the S3 bucket and key from the stack's template const template = assembly.getStackArtifact(stack.artifactId).template; const resourceName = stack.getLogicalId(func.node.defaultChild as lambda.CfnFunction); const resource = template.Resources[resourceName]; - + if (!resource || resource.Type !== 'AWS::Lambda::Function') { - throw new ValidationError(`Could not find Lambda function resource for ${func.functionName}`, stack); + throw new Error(`Could not find Lambda function resource for ${func.functionName}`); } const s3Bucket = resource.Properties.Code.S3Bucket; const s3Key = resource.Properties.Code.S3Key; if (!s3Bucket || !s3Key) { - throw new ValidationError(`Could not find S3 location for function ${func.functionName}`, stack); + throw new Error(`Could not find S3 location for function ${func.functionName}`); } - const assetId = s3Key.split('.')[0]; // The format is ".zip" - const fullAssetPath = path.join(assembly.directory, `asset.${assetId}`); + const assetId = s3Key.split('.')[0]; // S3Key format is .zip" + const assetDir = path.join(assembly.directory, `asset.${assetId}`); + + try { + if (!fs.existsSync(assetDir) || !fs.statSync(assetDir).isDirectory()) { + throw new Error(`Asset directory does not exist for function ${func.functionName}: ${assetDir}`); + } + + const indexPath = path.join(assetDir, 'index.js'); + if (!fs.existsSync(indexPath)) { + throw new Error(`index.js not found in asset directory for function ${func.functionName}`); + } + + verifyBundledContent(indexPath, func.functionName); - if (!fs.existsSync(fullAssetPath)) { - throw new ValidationError(`Asset file does not exist for function ${func.functionName}`, stack); + console.log(`Bundling verification passed for function ${func.functionName}`); + } catch (error) { + console.error(`Error verifying bundled content for function ${func.functionName}:`, error); + throw error; } +}); + - const bundledContent = fs.readFileSync(fullAssetPath, 'utf-8'); +function verifyBundledContent(filePath: string, functionName: string) { + const bundledContent = fs.readFileSync(filePath, 'utf-8'); if (!bundledContent.includes('exports.handler =')) { - throw new ValidationError(`Bundled content does not contain expected handler export for function ${func.functionName}`, stack); + throw new Error(`Bundled content does not contain expected handler export for function ${functionName}`); } if (bundledContent.includes('import ')) { - throw new ValidationError(`Bundled content contains unexpected import statement for function ${func.functionName}`, stack); + throw new Error(`Bundled content contains unexpected import statement for function ${functionName}`); } if (!bundledContent.includes('//# sourceMappingURL=')) { - throw new ValidationError(`Bundled content does not contain source map for function ${func.functionName}`, stack); + throw new Error(`Bundled content does not contain source map for function ${functionName}`); } -}); +} \ No newline at end of file From c82db0ab1c22d0891caa045d6c4facf484819329 Mon Sep 17 00:00:00 2001 From: Ian Hou <45278651+iankhou@users.noreply.github.com> Date: Thu, 6 Feb 2025 16:58:57 -0500 Subject: [PATCH 5/6] ValidationError --- .../test/integ.nodejs.build.images.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts index a1982a2b9aba1..20bd6255a2155 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts @@ -61,14 +61,14 @@ stack.lambdaFunctions.forEach((func) => { const resource = template.Resources[resourceName]; if (!resource || resource.Type !== 'AWS::Lambda::Function') { - throw new Error(`Could not find Lambda function resource for ${func.functionName}`); + throw new ValidationError(`Could not find Lambda function resource for ${func.functionName}`, stack); } const s3Bucket = resource.Properties.Code.S3Bucket; const s3Key = resource.Properties.Code.S3Key; if (!s3Bucket || !s3Key) { - throw new Error(`Could not find S3 location for function ${func.functionName}`); + throw new ValidationError(`Could not find S3 location for function ${func.functionName}`, stack); } const assetId = s3Key.split('.')[0]; // S3Key format is .zip" @@ -76,15 +76,15 @@ stack.lambdaFunctions.forEach((func) => { try { if (!fs.existsSync(assetDir) || !fs.statSync(assetDir).isDirectory()) { - throw new Error(`Asset directory does not exist for function ${func.functionName}: ${assetDir}`); + throw new ValidationError(`Asset directory does not exist for function ${func.functionName}: ${assetDir}`, stack); } const indexPath = path.join(assetDir, 'index.js'); if (!fs.existsSync(indexPath)) { - throw new Error(`index.js not found in asset directory for function ${func.functionName}`); + throw new ValidationError(`index.js not found in asset directory for function ${func.functionName}`, stack); } - verifyBundledContent(indexPath, func.functionName); + verifyBundledContent(stack, indexPath, func.functionName); console.log(`Bundling verification passed for function ${func.functionName}`); } catch (error) { @@ -94,18 +94,18 @@ stack.lambdaFunctions.forEach((func) => { }); -function verifyBundledContent(filePath: string, functionName: string) { +function verifyBundledContent(scope: Construct, filePath: string, functionName: string) { const bundledContent = fs.readFileSync(filePath, 'utf-8'); if (!bundledContent.includes('exports.handler =')) { - throw new Error(`Bundled content does not contain expected handler export for function ${functionName}`); + throw new ValidationError(`Bundled content does not contain expected handler export for function ${functionName}`, scope); } if (bundledContent.includes('import ')) { - throw new Error(`Bundled content contains unexpected import statement for function ${functionName}`); + throw new ValidationError(`Bundled content contains unexpected import statement for function ${functionName}`, scope); } if (!bundledContent.includes('//# sourceMappingURL=')) { - throw new Error(`Bundled content does not contain source map for function ${functionName}`); + throw new ValidationError(`Bundled content does not contain source map for function ${functionName}`, scope); } } \ No newline at end of file From 08fe459acd3916e417d189c70be095fad55367aa Mon Sep 17 00:00:00 2001 From: Ian Hou <45278651+iankhou@users.noreply.github.com> Date: Thu, 6 Feb 2025 17:08:49 -0500 Subject: [PATCH 6/6] lint and remove unnecessary checks --- .../test/integ.nodejs.build.images.ts | 24 +------------------ 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts index 20bd6255a2155..af8c2eec75827 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda-nodejs/test/integ.nodejs.build.images.ts @@ -59,7 +59,7 @@ stack.lambdaFunctions.forEach((func) => { const template = assembly.getStackArtifact(stack.artifactId).template; const resourceName = stack.getLogicalId(func.node.defaultChild as lambda.CfnFunction); const resource = template.Resources[resourceName]; - + if (!resource || resource.Type !== 'AWS::Lambda::Function') { throw new ValidationError(`Could not find Lambda function resource for ${func.functionName}`, stack); } @@ -83,29 +83,7 @@ stack.lambdaFunctions.forEach((func) => { if (!fs.existsSync(indexPath)) { throw new ValidationError(`index.js not found in asset directory for function ${func.functionName}`, stack); } - - verifyBundledContent(stack, indexPath, func.functionName); - - console.log(`Bundling verification passed for function ${func.functionName}`); } catch (error) { - console.error(`Error verifying bundled content for function ${func.functionName}:`, error); throw error; } }); - - -function verifyBundledContent(scope: Construct, filePath: string, functionName: string) { - const bundledContent = fs.readFileSync(filePath, 'utf-8'); - - if (!bundledContent.includes('exports.handler =')) { - throw new ValidationError(`Bundled content does not contain expected handler export for function ${functionName}`, scope); - } - - if (bundledContent.includes('import ')) { - throw new ValidationError(`Bundled content contains unexpected import statement for function ${functionName}`, scope); - } - - if (!bundledContent.includes('//# sourceMappingURL=')) { - throw new ValidationError(`Bundled content does not contain source map for function ${functionName}`, scope); - } -} \ No newline at end of file