From e56e7370b5cea4e07896664c8a67028b8f753fcf Mon Sep 17 00:00:00 2001 From: Roger Zhang Date: Thu, 20 Nov 2025 20:06:02 -0800 Subject: [PATCH 1/3] remote debugging & lambda new runtime support --- .../core/src/eventSchemas/models/schemaCodeLangs.ts | 1 + packages/core/src/lambda/models/samLambdaRuntime.ts | 11 +++++++---- packages/core/src/lambda/remoteDebugging/ldkLayers.ts | 2 +- .../core/src/lambda/vue/remoteInvoke/remoteInvoke.vue | 8 ++++++-- packages/core/src/shared/sam/debugger/javaSamDebug.ts | 4 ++-- .../core/src/shared/sam/debugger/pythonSamDebug.ts | 11 ++--------- .../src/test/lambda/models/samLambdaRuntime.test.ts | 10 ++++++++++ .../core/src/test/lambda/models/samTemplates.test.ts | 1 + .../Feature-9fc33290-87eb-47f6-93a9-1fe4ec246e3f.json | 4 ++++ 9 files changed, 34 insertions(+), 18 deletions(-) create mode 100644 packages/toolkit/.changes/next-release/Feature-9fc33290-87eb-47f6-93a9-1fe4ec246e3f.json diff --git a/packages/core/src/eventSchemas/models/schemaCodeLangs.ts b/packages/core/src/eventSchemas/models/schemaCodeLangs.ts index fe83459251a..81814a34cc7 100644 --- a/packages/core/src/eventSchemas/models/schemaCodeLangs.ts +++ b/packages/core/src/eventSchemas/models/schemaCodeLangs.ts @@ -62,6 +62,7 @@ export function supportsEventBridgeTemplates(runtime: Runtime): boolean { 'python3.11', 'python3.12', 'python3.13', + 'python3.14', 'go1.x', ].includes(runtime) } diff --git a/packages/core/src/lambda/models/samLambdaRuntime.ts b/packages/core/src/lambda/models/samLambdaRuntime.ts index 985e947afc9..4c7ea9be596 100644 --- a/packages/core/src/lambda/models/samLambdaRuntime.ts +++ b/packages/core/src/lambda/models/samLambdaRuntime.ts @@ -30,6 +30,7 @@ export type RuntimePackageType = 'Image' | 'Zip' // TODO: Consolidate all of the runtime constructs into a single > map // We should be able to eliminate a fair amount of redundancy with that. export const nodeJsRuntimes: ImmutableSet = ImmutableSet([ + 'nodejs24.x' as Runtime, 'nodejs22.x' as Runtime, 'nodejs20.x', 'nodejs18.x', @@ -51,6 +52,7 @@ export function getNodeMajorVersion(version?: string): number | undefined { } export const pythonRuntimes: ImmutableSet = ImmutableSet([ + 'python3.14' as Runtime, 'python3.13' as Runtime, 'python3.12', 'python3.11', @@ -66,6 +68,7 @@ export const javaRuntimes: ImmutableSet = ImmutableSet([ 'java8', 'java8.al2', 'java21', + 'java25' as Runtime, ]) export const dotNetRuntimes: ImmutableSet = ImmutableSet(['dotnet6', 'dotnet8']) export const rubyRuntimes: ImmutableSet = ImmutableSet(['ruby3.2', 'ruby3.3', 'ruby3.4' as Runtime]) @@ -94,12 +97,12 @@ export const deprecatedRuntimes: ImmutableSet = ImmutableSet([ 'ruby2.7', ]) const defaultRuntimes = ImmutableMap([ - [RuntimeFamily.NodeJS, 'nodejs22.x' as Runtime], - [RuntimeFamily.Python, 'python3.13' as Runtime], + [RuntimeFamily.NodeJS, 'nodejs24.x' as Runtime], + [RuntimeFamily.Python, 'python3.14' as Runtime], [RuntimeFamily.DotNet, 'dotnet8'], [RuntimeFamily.Go, 'go1.x'], - [RuntimeFamily.Java, 'java21'], - [RuntimeFamily.Ruby, 'ruby3.3'], + [RuntimeFamily.Java, 'java25' as Runtime], + [RuntimeFamily.Ruby, 'ruby3.4' as Runtime], ]) export const mapFamilyToDebugType = ImmutableMap([ diff --git a/packages/core/src/lambda/remoteDebugging/ldkLayers.ts b/packages/core/src/lambda/remoteDebugging/ldkLayers.ts index f0c5dff2c02..cf955a6c019 100644 --- a/packages/core/src/lambda/remoteDebugging/ldkLayers.ts +++ b/packages/core/src/lambda/remoteDebugging/ldkLayers.ts @@ -31,7 +31,7 @@ export const regionToAccount: RegionAccountMapping = { } // Global layer version -const globalLayerVersion = 2 +const globalLayerVersion = 3 export function getRemoteDebugLayerForArch(region: string, arch: string): string | undefined { const account = regionToAccount[region] diff --git a/packages/core/src/lambda/vue/remoteInvoke/remoteInvoke.vue b/packages/core/src/lambda/vue/remoteInvoke/remoteInvoke.vue index eab8d48fe51..11c07afbf89 100644 --- a/packages/core/src/lambda/vue/remoteInvoke/remoteInvoke.vue +++ b/packages/core/src/lambda/vue/remoteInvoke/remoteInvoke.vue @@ -57,7 +57,8 @@ :disabled=" !initialData.runtimeSupportsRemoteDebug || !initialData.remoteDebugLayer || - !initialData.LambdaFunctionNode?.configuration.SnapStart + (!initialData.LambdaFunctionNode?.configuration.SnapStart && + initialData.LambdaFunctionNode?.configuration.State !== 'Active') " class="remote-debug-checkbox" /> @@ -94,7 +95,10 @@ Region {{ initialData.FunctionRegion }} doesn't support remote debugging yet Doesn't support remote debugging yet diff --git a/packages/core/src/shared/sam/debugger/javaSamDebug.ts b/packages/core/src/shared/sam/debugger/javaSamDebug.ts index 26ebad889d6..9078c9e2a03 100644 --- a/packages/core/src/shared/sam/debugger/javaSamDebug.ts +++ b/packages/core/src/shared/sam/debugger/javaSamDebug.ts @@ -3,6 +3,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +import { Runtime } from '@aws-sdk/client-lambda' import { getCodeRoot, isImageLambdaConfig } from '../../../lambda/local/debugConfiguration' import { RuntimeFamily } from '../../../lambda/models/samLambdaRuntime' import { ExtContext } from '../../extensions' @@ -55,9 +56,8 @@ function getJavaOptionsEnvVar(config: SamLaunchRequestArgs): string { // https://github.com/aws/aws-sam-cli/blob/86f88cbd7df365960f7015c5d086b0db7aedd9d5/samcli/local/docker/lambda_debug_settings.py#L53 return `-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,quiet=y,address=*:${config.debugPort} -XX:MaxHeapSize=2834432k -XX:MaxMetaspaceSize=163840k -XX:ReservedCodeCacheSize=81920k -XX:+UseSerialGC -XX:-TieredCompilation -Djava.net.preferIPv4Stack=true` case 'java17': - // https://github.com/aws/aws-sam-cli/blob/90aa5cf11e1c5cbfbe66aea2e2de10d478d48231/samcli/local/docker/lambda_debug_settings.py#L86 - return `-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,quiet=y,address=*:${config.debugPort} -XX:MaxHeapSize=2834432k -XX:+UseSerialGC -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Djava.net.preferIPv4Stack=true` case 'java21': + case 'java25' as Runtime: // https://github.com/aws/aws-sam-cli/blob/90aa5cf11e1c5cbfbe66aea2e2de10d478d48231/samcli/local/docker/lambda_debug_settings.py#L96 return `-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,quiet=y,address=*:${config.debugPort} -XX:MaxHeapSize=2834432k -XX:+UseSerialGC -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Djava.net.preferIPv4Stack=true` default: diff --git a/packages/core/src/shared/sam/debugger/pythonSamDebug.ts b/packages/core/src/shared/sam/debugger/pythonSamDebug.ts index 902dc85003d..12f25d79810 100644 --- a/packages/core/src/shared/sam/debugger/pythonSamDebug.ts +++ b/packages/core/src/shared/sam/debugger/pythonSamDebug.ts @@ -154,20 +154,13 @@ function getPythonExeAndBootstrap(runtime: Runtime) { // unfortunately new 'Image'-base images did not standardize the paths // https://github.com/aws/aws-sam-cli/blob/7d5101a8edeb575b6925f9adecf28f47793c403c/samcli/local/docker/lambda_debug_settings.py switch (runtime) { - case 'python3.7': - return { python: '/var/lang/bin/python3.7', bootstrap: '/var/runtime/bootstrap' } - case 'python3.8': - return { python: '/var/lang/bin/python3.8', bootstrap: '/var/runtime/bootstrap.py' } case 'python3.9': - return { python: '/var/lang/bin/python3.9', bootstrap: '/var/runtime/bootstrap.py' } case 'python3.10': - return { python: '/var/lang/bin/python3.10', bootstrap: '/var/runtime/bootstrap.py' } case 'python3.11': - return { python: '/var/lang/bin/python3.11', bootstrap: '/var/runtime/bootstrap.py' } case 'python3.12': - return { python: '/var/lang/bin/python3.12', bootstrap: '/var/runtime/bootstrap.py' } case 'python3.13' as Runtime: - return { python: '/var/lang/bin/python3.13', bootstrap: '/var/runtime/bootstrap.py' } + case 'python3.14' as Runtime: + return { python: `/var/lang/bin/${runtime}`, bootstrap: '/var/runtime/bootstrap.py' } default: throw new Error(`Python SAM debug logic ran for invalid Python runtime: ${runtime}`) } diff --git a/packages/core/src/test/lambda/models/samLambdaRuntime.test.ts b/packages/core/src/test/lambda/models/samLambdaRuntime.test.ts index 566c465a0dd..dc872530415 100644 --- a/packages/core/src/test/lambda/models/samLambdaRuntime.test.ts +++ b/packages/core/src/test/lambda/models/samLambdaRuntime.test.ts @@ -74,10 +74,12 @@ describe('runtimes', function () { 'nodejs18.x', 'nodejs20.x', 'nodejs22.x', + 'nodejs24.x', 'python3.10', 'python3.11', 'python3.12', 'python3.13', + 'python3.14', 'python3.7', 'python3.8', 'python3.9', @@ -88,10 +90,12 @@ describe('runtimes', function () { 'nodejs18.x', 'nodejs20.x', 'nodejs22.x', + 'nodejs24.x', 'python3.10', 'python3.11', 'python3.12', 'python3.13', + 'python3.14', 'python3.7', 'python3.8', 'python3.9', @@ -105,6 +109,7 @@ describe('runtimes', function () { 'java11', 'java17', 'java21', + 'java25', 'java8', 'java8.al2', 'nodejs14.x', @@ -112,10 +117,12 @@ describe('runtimes', function () { 'nodejs18.x', 'nodejs20.x', 'nodejs22.x', + 'nodejs24.x', 'python3.10', 'python3.11', 'python3.12', 'python3.13', + 'python3.14', 'python3.7', 'python3.8', 'python3.9', @@ -128,6 +135,7 @@ describe('runtimes', function () { 'java11', 'java17', 'java21', + 'java25', 'java8', 'java8.al2', 'nodejs14.x', @@ -135,10 +143,12 @@ describe('runtimes', function () { 'nodejs18.x', 'nodejs20.x', 'nodejs22.x', + 'nodejs24.x', 'python3.10', 'python3.11', 'python3.12', 'python3.13', + 'python3.14', 'python3.7', 'python3.8', 'python3.9', diff --git a/packages/core/src/test/lambda/models/samTemplates.test.ts b/packages/core/src/test/lambda/models/samTemplates.test.ts index 7fe78e630c8..32d2f3caa7b 100644 --- a/packages/core/src/test/lambda/models/samTemplates.test.ts +++ b/packages/core/src/test/lambda/models/samTemplates.test.ts @@ -68,6 +68,7 @@ describe('getSamTemplateWizardOption', function () { case 'python3.11': case 'python3.12': case 'python3.13' as Runtime: + case 'python3.14' as Runtime: assert.deepStrictEqual( result, validPythonTemplateOptions, diff --git a/packages/toolkit/.changes/next-release/Feature-9fc33290-87eb-47f6-93a9-1fe4ec246e3f.json b/packages/toolkit/.changes/next-release/Feature-9fc33290-87eb-47f6-93a9-1fe4ec246e3f.json new file mode 100644 index 00000000000..80d4af43ae5 --- /dev/null +++ b/packages/toolkit/.changes/next-release/Feature-9fc33290-87eb-47f6-93a9-1fe4ec246e3f.json @@ -0,0 +1,4 @@ +{ + "type": "Feature", + "description": "Remote debugging now supports nodejs24.x, python3.14, java25" +} From 970f18e09061116dab7be585ee3acaf883ff006a Mon Sep 17 00:00:00 2001 From: Roger Zhang Date: Thu, 20 Nov 2025 21:24:11 -0800 Subject: [PATCH 2/3] outdated tests --- .../model/schemaCodeLangs.test.ts | 1 + .../debugger/samDebugConfigProvider.test.ts | 63 ++++++++-------- .../hello_world/Dockerfile | 8 ++ .../hello_world/__init__.py | 0 .../hello_world/app.py | 44 +++++++++++ .../hello_world/requirements.txt | 1 + .../python3.14-image-sam-app/template.yaml | 30 ++++++++ .../events/event.json | 62 ++++++++++++++++ .../hello_world/__init__.py | 0 .../hello_world/app.py | 65 +++++++++++++++++ .../hello_world/requirements.txt | 1 + .../python3.14-plain-sam-app/template.yaml | 61 ++++++++++++++++ .../tests/unit/__init__.py | 0 .../tests/unit/test_handler.py | 73 +++++++++++++++++++ 14 files changed, 378 insertions(+), 31 deletions(-) create mode 100644 packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/Dockerfile create mode 100644 packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/__init__.py create mode 100644 packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/app.py create mode 100644 packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/requirements.txt create mode 100644 packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/template.yaml create mode 100644 packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/events/event.json create mode 100644 packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/hello_world/__init__.py create mode 100644 packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/hello_world/app.py create mode 100644 packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/hello_world/requirements.txt create mode 100644 packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/template.yaml create mode 100644 packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/tests/unit/__init__.py create mode 100644 packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/tests/unit/test_handler.py diff --git a/packages/core/src/test/eventSchemas/model/schemaCodeLangs.test.ts b/packages/core/src/test/eventSchemas/model/schemaCodeLangs.test.ts index 6c023a52676..cce239a1cb1 100644 --- a/packages/core/src/test/eventSchemas/model/schemaCodeLangs.test.ts +++ b/packages/core/src/test/eventSchemas/model/schemaCodeLangs.test.ts @@ -34,6 +34,7 @@ describe('getApiValueForSchemasDownload', function () { case 'python3.11': case 'python3.12': case 'python3.13' as Runtime: + case 'python3.14' as Runtime: case 'python3.10': { const result = getApiValueForSchemasDownload(runtime) assert.strictEqual(result, 'Python36', 'Api value used by schemas api') diff --git a/packages/core/src/test/shared/sam/debugger/samDebugConfigProvider.test.ts b/packages/core/src/test/shared/sam/debugger/samDebugConfigProvider.test.ts index ccdf113b580..d00273f6426 100644 --- a/packages/core/src/test/shared/sam/debugger/samDebugConfigProvider.test.ts +++ b/packages/core/src/test/shared/sam/debugger/samDebugConfigProvider.test.ts @@ -47,6 +47,7 @@ import { CredentialsProvider } from '../../../../auth/providers/credentials' import globals from '../../../../shared/extensionGlobals' import { isCI } from '../../../../shared/vscode/env' import { fs } from '../../../../shared' +import { Runtime } from '@aws-sdk/client-lambda' /** * Asserts the contents of a "launch config" (the result of `makeConfig()` or @@ -2090,9 +2091,9 @@ describe('SamDebugConfigurationProvider', async function () { assertEqualLaunchConfigs(actualNoDebug, expectedNoDebug) }) - it('target=code: python 3.7', async function () { + it('target=code: python 3.14', async function () { const appDir = pathutil.normalize( - path.join(testutil.getProjectDir(), 'testFixtures/workspaceFolder/python3.7-plain-sam-app') + path.join(testutil.getProjectDir(), 'testFixtures/workspaceFolder/python3.14-plain-sam-app') ) const relPayloadPath = `events/event.json` const absPayloadPath = `${appDir}/${relPayloadPath}` @@ -2107,7 +2108,7 @@ describe('SamDebugConfigurationProvider', async function () { projectRoot: 'hello_world', }, lambda: { - runtime: 'python3.7', + runtime: 'python3.14', payload: { path: relPayloadPath, }, @@ -2120,7 +2121,7 @@ describe('SamDebugConfigurationProvider', async function () { const expected: SamLaunchRequestArgs = { awsCredentials: fakeCredentials, request: 'attach', // Input "direct-invoke", output "attach". - runtime: 'python3.7', + runtime: 'python3.14' as Runtime, runtimeFamily: lambdaModel.RuntimeFamily.Python, type: AWS_SAM_DEBUG_TYPE, handlerName: 'app.lambda_handler', @@ -2187,7 +2188,7 @@ describe('SamDebugConfigurationProvider', async function () { Handler: ${expected.handlerName} CodeUri: >- ${expected.codeRoot} - Runtime: python3.7 + Runtime: python3.14 ` ) @@ -2243,21 +2244,21 @@ describe('SamDebugConfigurationProvider', async function () { assertEqualLaunchConfigs(actualNoDebug, expectedNoDebug) }) - it('target=template: python 3.7 (deep project tree)', async function () { + it('target=template: python 3.14 (deep project tree)', async function () { // To test a deeper tree, use "testFixtures/workspaceFolder/" as the root. const appDir = pathutil.normalize(path.join(testutil.getProjectDir(), 'testFixtures/workspaceFolder/')) const folder = testutil.getWorkspaceFolder(appDir) const input = { type: AWS_SAM_DEBUG_TYPE, - name: 'test-py37-template', + name: 'test-py314-template', request: DIRECT_INVOKE_TYPE, invokeTarget: { target: TEMPLATE_TARGET_TYPE, - templatePath: 'python3.7-plain-sam-app/template.yaml', + templatePath: 'python3.14-plain-sam-app/template.yaml', logicalId: 'HelloWorldFunction', }, } - const templatePath = vscode.Uri.file(path.join(appDir, 'python3.7-plain-sam-app/template.yaml')) + const templatePath = vscode.Uri.file(path.join(appDir, 'python3.14-plain-sam-app/template.yaml')) // Invoke with noDebug=false (the default). const actual = (await debugConfigProvider.makeConfig(folder, input))! @@ -2265,7 +2266,7 @@ describe('SamDebugConfigurationProvider', async function () { const expected: SamLaunchRequestArgs = { awsCredentials: fakeCredentials, request: 'attach', // Input "direct-invoke", output "attach". - runtime: 'python3.7', + runtime: 'python3.14' as Runtime, runtimeFamily: lambdaModel.RuntimeFamily.Python, type: AWS_SAM_DEBUG_TYPE, handlerName: 'app.lambda_handler', @@ -2277,7 +2278,7 @@ describe('SamDebugConfigurationProvider', async function () { baseBuildDir: actual.baseBuildDir, // Random, sanity-checked by assertEqualLaunchConfigs(). envFile: undefined, eventPayloadFile: undefined, - codeRoot: pathutil.normalize(path.join(appDir, 'python3.7-plain-sam-app/hello_world')), + codeRoot: pathutil.normalize(path.join(appDir, 'python3.14-plain-sam-app/hello_world')), debugArgs: [ `/tmp/lambci_debug_files/py_debug_wrapper.py --listen 0.0.0.0:${actual.debugPort} --wait-for-client --log-to-stderr --debug`, ], @@ -2304,7 +2305,7 @@ describe('SamDebugConfigurationProvider', async function () { host: 'localhost', pathMappings: [ { - localRoot: pathutil.normalize(path.join(appDir, 'python3.7-plain-sam-app/hello_world')), + localRoot: pathutil.normalize(path.join(appDir, 'python3.14-plain-sam-app/hello_world')), remoteRoot: '/var/task', }, ], @@ -2359,18 +2360,18 @@ describe('SamDebugConfigurationProvider', async function () { await assertEqualNoDebugTemplateTarget(input, expected, folder, debugConfigProvider, true) }) - it('target=api: python 3.7 (deep project tree)', async function () { + it('target=api: python 3.14 (deep project tree)', async function () { // Use "testFixtures/workspaceFolder/" as the project root to test // a deeper tree. const appDir = pathutil.normalize(path.join(testutil.getProjectDir(), 'testFixtures/workspaceFolder/')) const folder = testutil.getWorkspaceFolder(appDir) const input: AwsSamDebuggerConfiguration = { type: AWS_SAM_DEBUG_TYPE, - name: 'test-py37-api', + name: 'test-py314-api', request: DIRECT_INVOKE_TYPE, invokeTarget: { target: API_TARGET_TYPE, - templatePath: 'python3.7-plain-sam-app/template.yaml', + templatePath: 'python3.14-plain-sam-app/template.yaml', logicalId: 'HelloWorldFunction', }, api: { @@ -2382,7 +2383,7 @@ describe('SamDebugConfigurationProvider', async function () { querystring: 'name1=value1&foo&bar', }, } - const templatePath = vscode.Uri.file(path.join(appDir, 'python3.7-plain-sam-app/template.yaml')) + const templatePath = vscode.Uri.file(path.join(appDir, 'python3.14-plain-sam-app/template.yaml')) // Invoke with noDebug=false (the default). const actual = (await debugConfigProvider.makeConfig(folder, input))! @@ -2390,7 +2391,7 @@ describe('SamDebugConfigurationProvider', async function () { const expected: SamLaunchRequestArgs = { awsCredentials: fakeCredentials, request: 'attach', // Input "direct-invoke", output "attach". - runtime: 'python3.7', + runtime: 'python3.14' as Runtime, runtimeFamily: lambdaModel.RuntimeFamily.Python, type: AWS_SAM_DEBUG_TYPE, handlerName: 'app.lambda_handler', @@ -2402,7 +2403,7 @@ describe('SamDebugConfigurationProvider', async function () { baseBuildDir: actual.baseBuildDir, // Random, sanity-checked by assertEqualLaunchConfigs(). envFile: undefined, eventPayloadFile: undefined, - codeRoot: pathutil.normalize(path.join(appDir, 'python3.7-plain-sam-app/hello_world')), + codeRoot: pathutil.normalize(path.join(appDir, 'python3.14-plain-sam-app/hello_world')), debugArgs: [ `/tmp/lambci_debug_files/py_debug_wrapper.py --listen 0.0.0.0:${actual.debugPort} --wait-for-client --log-to-stderr --debug`, ], @@ -2431,7 +2432,7 @@ describe('SamDebugConfigurationProvider', async function () { host: 'localhost', pathMappings: [ { - localRoot: pathutil.normalize(path.join(appDir, 'python3.7-plain-sam-app/hello_world')), + localRoot: pathutil.normalize(path.join(appDir, 'python3.14-plain-sam-app/hello_world')), remoteRoot: '/var/task', }, ], @@ -2455,25 +2456,25 @@ describe('SamDebugConfigurationProvider', async function () { await assertEqualNoDebugTemplateTarget(input, expected, folder, debugConfigProvider, true) }) - it('target=template: Image python 3.7', async function () { + it('target=template: Image python 3.14', async function () { // Use "testFixtures/workspaceFolder/" as the project root to test // a deeper tree. const appDir = pathutil.normalize(path.join(testutil.getProjectDir(), 'testFixtures/workspaceFolder/')) const folder = testutil.getWorkspaceFolder(appDir) const input = { type: AWS_SAM_DEBUG_TYPE, - name: 'test-py37-image-template', + name: 'test-py314-image-template', request: DIRECT_INVOKE_TYPE, invokeTarget: { target: TEMPLATE_TARGET_TYPE, - templatePath: 'python3.7-image-sam-app/template.yaml', + templatePath: 'python3.14-image-sam-app/template.yaml', logicalId: 'HelloWorldFunction', }, lambda: { - runtime: 'python3.7', + runtime: 'python3.14', }, } - const templatePath = vscode.Uri.file(path.join(appDir, 'python3.7-image-sam-app/template.yaml')) + const templatePath = vscode.Uri.file(path.join(appDir, 'python3.14-image-sam-app/template.yaml')) // Invoke with noDebug=false (the default). const actual = (await debugConfigProvider.makeConfig(folder, input))! @@ -2481,7 +2482,7 @@ describe('SamDebugConfigurationProvider', async function () { const expected: SamLaunchRequestArgs = { awsCredentials: fakeCredentials, request: 'attach', // Input "direct-invoke", output "attach". - runtime: 'python3.7', + runtime: 'python3.14' as Runtime, runtimeFamily: lambdaModel.RuntimeFamily.Python, type: AWS_SAM_DEBUG_TYPE, handlerName: 'HelloWorldFunction', @@ -2493,9 +2494,9 @@ describe('SamDebugConfigurationProvider', async function () { baseBuildDir: actual.baseBuildDir, // Random, sanity-checked by assertEqualLaunchConfigs(). envFile: undefined, eventPayloadFile: undefined, - codeRoot: pathutil.normalize(path.join(appDir, 'python3.7-image-sam-app/hello_world')), + codeRoot: pathutil.normalize(path.join(appDir, 'python3.14-image-sam-app/hello_world')), debugArgs: [ - `/var/lang/bin/python3.7 /tmp/lambci_debug_files/py_debug_wrapper.py --listen 0.0.0.0:${actual.debugPort} --wait-for-client --log-to-stderr /var/runtime/bootstrap --debug`, + `/var/lang/bin/python3.14 /tmp/lambci_debug_files/py_debug_wrapper.py --listen 0.0.0.0:${actual.debugPort} --wait-for-client --log-to-stderr /var/runtime/bootstrap.py --debug`, ], apiPort: undefined, debugPort: actual.debugPort, @@ -2505,7 +2506,7 @@ describe('SamDebugConfigurationProvider', async function () { environmentVariables: {}, memoryMb: undefined, timeoutSec: 3, - runtime: 'python3.7', + runtime: 'python3.14', }, name: input.name, templatePath: pathutil.normalize(path.join(path.dirname(templatePath.fsPath), 'template.yaml')), @@ -2520,7 +2521,7 @@ describe('SamDebugConfigurationProvider', async function () { host: 'localhost', pathMappings: [ { - localRoot: pathutil.normalize(path.join(appDir, 'python3.7-image-sam-app/hello_world')), + localRoot: pathutil.normalize(path.join(appDir, 'python3.14-image-sam-app/hello_world')), remoteRoot: '/var/task', }, ], @@ -2592,7 +2593,7 @@ describe('SamDebugConfigurationProvider', async function () { it('verify python debug option not set for non-debug log level', async function () { const appDir = pathutil.normalize( - path.join(testutil.getProjectDir(), 'testFixtures/workspaceFolder/python3.7-plain-sam-app') + path.join(testutil.getProjectDir(), 'testFixtures/workspaceFolder/python3.14-plain-sam-app') ) const relPayloadPath = `events/event.json` const folder = testutil.getWorkspaceFolder(appDir) @@ -2606,7 +2607,7 @@ describe('SamDebugConfigurationProvider', async function () { projectRoot: 'hello_world', }, lambda: { - runtime: 'python3.7', // Arbitrary choice of runtime for this test + runtime: 'python3.14', // Arbitrary choice of runtime for this test payload: { path: relPayloadPath, }, diff --git a/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/Dockerfile b/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/Dockerfile new file mode 100644 index 00000000000..988d3bcfde5 --- /dev/null +++ b/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/Dockerfile @@ -0,0 +1,8 @@ +FROM public.ecr.aws/lambda/python:3.7 + +COPY app.py requirements.txt ./ + +RUN python3.7 -m pip install -r requirements.txt + +# Command can be overwritten by providing a different command in the template directly. +CMD ["app.lambda_handler"] \ No newline at end of file diff --git a/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/__init__.py b/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/app.py b/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/app.py new file mode 100644 index 00000000000..139af7d44e2 --- /dev/null +++ b/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/app.py @@ -0,0 +1,44 @@ +import json + +# import requests + + +def lambda_handler(event, context): + """Sample pure Lambda function + + Parameters + ---------- + event: dict, required + API Gateway Lambda Proxy Input Format + + Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format + + context: object, required + Lambda Context runtime methods and attributes + + Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html + + Returns + ------ + API Gateway Lambda Proxy Output Format: dict + + Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html + """ + + # try: + # ip = requests.get("http://checkip.amazonaws.com/") + # except requests.RequestException as e: + # # Send some context about this error to Lambda Logs + # print(e) + + # raise e + + return { + "statusCode": 200, + "body": json.dumps( + { + "message": "hello world", + # "location": ip.text.replace("\n", "") + } + ), + } diff --git a/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/requirements.txt b/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/requirements.txt new file mode 100644 index 00000000000..663bd1f6a2a --- /dev/null +++ b/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/requirements.txt @@ -0,0 +1 @@ +requests \ No newline at end of file diff --git a/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/template.yaml b/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/template.yaml new file mode 100644 index 00000000000..ff108b4ce9b --- /dev/null +++ b/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/template.yaml @@ -0,0 +1,30 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + python3.14-image-sam-app + + Sample SAM Template for python3.14-image-sam-app + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 3 + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Properties: + PackageType: Image + # ImageConfig: + # Uncomment this to override command here from the Dockerfile + # Command: ["app.lambda_handler"] + Events: + HelloWorld: + Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api + Properties: + Path: /hello + Method: get + Metadata: + DockerTag: python3.14-v1 + DockerContext: ./hello_world + Dockerfile: Dockerfile diff --git a/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/events/event.json b/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/events/event.json new file mode 100644 index 00000000000..9fbdd9ac098 --- /dev/null +++ b/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/events/event.json @@ -0,0 +1,62 @@ +{ + "body": "{\"message\": \"hello world\"}", + "resource": "/{proxy+}", + "path": "/path/to/resource", + "httpMethod": "POST", + "isBase64Encoded": false, + "queryStringParameters": { + "foo": "bar" + }, + "pathParameters": { + "proxy": "/path/to/resource" + }, + "stageVariables": { + "baz": "qux" + }, + "headers": { + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Accept-Encoding": "gzip, deflate, sdch", + "Accept-Language": "en-US,en;q=0.8", + "Cache-Control": "max-age=0", + "CloudFront-Forwarded-Proto": "https", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-Mobile-Viewer": "false", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Tablet-Viewer": "false", + "CloudFront-Viewer-Country": "US", + "Host": "1234567890.execute-api.us-east-1.amazonaws.com", + "Upgrade-Insecure-Requests": "1", + "User-Agent": "Custom User Agent String", + "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", + "X-Amz-Cf-Id": "cDehVQoZnx43VYQb9j2-nvCh-9z396Uhbp027Y2JvkCPNLmGJHqlaA==", + "X-Forwarded-For": "127.0.0.1, 127.0.0.2", + "X-Forwarded-Port": "443", + "X-Forwarded-Proto": "https" + }, + "requestContext": { + "accountId": "123456789012", + "resourceId": "123456", + "stage": "prod", + "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", + "requestTime": "09/Apr/2015:12:34:56 +0000", + "requestTimeEpoch": 1428582896000, + "identity": { + "cognitoIdentityPoolId": null, + "accountId": null, + "cognitoIdentityId": null, + "caller": null, + "accessKey": null, + "sourceIp": "127.0.0.1", + "cognitoAuthenticationType": null, + "cognitoAuthenticationProvider": null, + "userArn": null, + "userAgent": "Custom User Agent String", + "user": null + }, + "path": "/prod/path/to/resource", + "resourcePath": "/{proxy+}", + "httpMethod": "POST", + "apiId": "1234567890", + "protocol": "HTTP/1.1" + } +} diff --git a/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/hello_world/__init__.py b/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/hello_world/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/hello_world/app.py b/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/hello_world/app.py new file mode 100644 index 00000000000..2da567d9afc --- /dev/null +++ b/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/hello_world/app.py @@ -0,0 +1,65 @@ +import json + +# Comment is intentional to simulate real-world code. +# import requests + + +def lambda_handler(event, context): + """Sample pure Lambda function + + Parameters + ---------- + event: dict, required + API Gateway Lambda Proxy Input Format + + Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format + + context: object, required + Lambda Context runtime methods and attributes + + Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html + + Returns + ------ + API Gateway Lambda Proxy Output Format: dict + + Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html + """ + + # Comment is intentional to simulate real-world code. + # try: + # ip = requests.get("http://checkip.amazonaws.com/") + # except requests.RequestException as e: + # # Send some context about this error to Lambda Logs + # print(e) + + # raise e + + return { + "statusCode": 200, + "body": json.dumps({ + "message": "hello world", + # Comment is intentional to simulate real-world code. + # "location": ip.text.replace("\n", "") + }), + } + +def lambda_handler_2(event, context): + return { + "statusCode": 200, + "body": json.dumps({ + "message": "hello from handler 2", + # Comment is intentional to simulate real-world code. + # "location": ip.text.replace("\n", "") + }), + } + +def lambda_handler_3(event, context): + return { + "statusCode": 200, + "body": json.dumps({ + "message": "hello from handler 3", + # Comment is intentional to simulate real-world code. + # "location": ip.text.replace("\n", "") + }), + } diff --git a/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/hello_world/requirements.txt b/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/hello_world/requirements.txt new file mode 100644 index 00000000000..663bd1f6a2a --- /dev/null +++ b/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/hello_world/requirements.txt @@ -0,0 +1 @@ +requests \ No newline at end of file diff --git a/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/template.yaml b/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/template.yaml new file mode 100644 index 00000000000..4566c0f7ab9 --- /dev/null +++ b/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/template.yaml @@ -0,0 +1,61 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + python3.14-plain-sam-app + + Sample SAM Template for python3.14-plain-sam-app + +# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst +Globals: + Function: + Timeout: 3 + +Resources: + HelloWorldFunction: + Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction + Properties: + CodeUri: hello_world/ + Handler: app.lambda_handler + Runtime: python3.14 + Events: + HelloWorld: + Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api + Properties: + Path: /hello + Method: get + Function2NotInLaunchJson: # Not in workspace's launch.json. + Type: AWS::Serverless::Function + Properties: + CodeUri: hello_world/ + Handler: app.lambda_handler_2 + Runtime: python3.14 + Function3NotInLaunchJson: # Not in workspace's launch.json. + Type: AWS::Serverless::Function + Properties: + CodeUri: hello_world/ + Handler: app.lambda_handler_3 + Runtime: python3.14 + Events: + HelloWorld: + Type: Api + Properties: + Path: /apipath1 + Method: get + ServerlessApi: + Type: AWS::Serverless::Api + Properties: + Name: ResourceName + +Outputs: + # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function + # Find out more about other implicit resources you can reference within SAM + # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api + HelloWorldApi: + Description: 'API Gateway endpoint URL for Prod stage for Hello World function' + Value: !Sub 'https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/' + HelloWorldFunction: + Description: 'Hello World Lambda Function ARN' + Value: !GetAtt HelloWorldFunction.Arn + HelloWorldFunctionIamRole: + Description: 'Implicit IAM Role created for Hello World function' + Value: !GetAtt HelloWorldFunctionRole.Arn diff --git a/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/tests/unit/__init__.py b/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/tests/unit/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/tests/unit/test_handler.py b/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/tests/unit/test_handler.py new file mode 100644 index 00000000000..09588d3778e --- /dev/null +++ b/packages/core/src/testFixtures/workspaceFolder/python3.14-plain-sam-app/tests/unit/test_handler.py @@ -0,0 +1,73 @@ +import json + +import pytest + +from hello_world import app + + +@pytest.fixture() +def apigw_event(): + """ Generates API GW Event""" + + return { + "body": '{ "test": "body"}', + "resource": "/{proxy+}", + "requestContext": { + "resourceId": "123456", + "apiId": "1234567890", + "resourcePath": "/{proxy+}", + "httpMethod": "POST", + "requestId": "c6af9ac6-7b61-11e6-9a41-93e8deadbeef", + "accountId": "123456789012", + "identity": { + "apiKey": "", + "userArn": "", + "cognitoAuthenticationType": "", + "caller": "", + "userAgent": "Custom User Agent String", + "user": "", + "cognitoIdentityPoolId": "", + "cognitoIdentityId": "", + "cognitoAuthenticationProvider": "", + "sourceIp": "127.0.0.1", + "accountId": "", + }, + "stage": "prod", + }, + "queryStringParameters": {"foo": "bar"}, + "headers": { + "Via": "1.1 08f323deadbeefa7af34d5feb414ce27.cloudfront.net (CloudFront)", + "Accept-Language": "en-US,en;q=0.8", + "CloudFront-Is-Desktop-Viewer": "true", + "CloudFront-Is-SmartTV-Viewer": "false", + "CloudFront-Is-Mobile-Viewer": "false", + "X-Forwarded-For": "127.0.0.1, 127.0.0.2", + "CloudFront-Viewer-Country": "US", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8", + "Upgrade-Insecure-Requests": "1", + "X-Forwarded-Port": "443", + "Host": "1234567890.execute-api.us-east-1.amazonaws.com", + "X-Forwarded-Proto": "https", + "X-Amz-Cf-Id": "aaaaaaaaaae3VYQb9jd-nvCd-de396Uhbp027Y2JvkCPNLmGJHqlaA==", + "CloudFront-Is-Tablet-Viewer": "false", + "Cache-Control": "max-age=0", + "User-Agent": "Custom User Agent String", + "CloudFront-Forwarded-Proto": "https", + "Accept-Encoding": "gzip, deflate, sdch", + }, + "pathParameters": {"proxy": "/examplepath"}, + "httpMethod": "POST", + "stageVariables": {"baz": "qux"}, + "path": "/examplepath", + } + + +def test_lambda_handler(apigw_event, mocker): + + ret = app.lambda_handler(apigw_event, "") + data = json.loads(ret["body"]) + + assert ret["statusCode"] == 200 + assert "message" in ret["body"] + assert data["message"] == "hello world" + # assert "location" in data.dict_keys() From 01ea80fbecbf21a3d7bd6cfa003845398f83efc7 Mon Sep 17 00:00:00 2001 From: Roger Zhang Date: Thu, 20 Nov 2025 22:08:57 -0800 Subject: [PATCH 3/3] nit --- .../python3.14-image-sam-app/hello_world/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/Dockerfile b/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/Dockerfile index 988d3bcfde5..63816e8fb4d 100644 --- a/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/Dockerfile +++ b/packages/core/src/testFixtures/workspaceFolder/python3.14-image-sam-app/hello_world/Dockerfile @@ -1,8 +1,8 @@ -FROM public.ecr.aws/lambda/python:3.7 +FROM public.ecr.aws/lambda/python:3.14 COPY app.py requirements.txt ./ -RUN python3.7 -m pip install -r requirements.txt +RUN python3.14 -m pip install -r requirements.txt # Command can be overwritten by providing a different command in the template directly. CMD ["app.lambda_handler"] \ No newline at end of file