amplify-cli icon indicating copy to clipboard operation
amplify-cli copied to clipboard

Support for Mocking functions with layers and Docker

Open ErickWendel opened this issue 4 years ago • 16 comments

Note: If your feature-request is regarding the AWS Amplify Console service, please log it in the official AWS Amplify Console forum

Is your feature request related to a problem? Please describe. When I try to test layers locally I've seen errors which shows that it's not implemented yet. It would be nice if we could install yumda packages using Docker.

Unable to mock function. Mocking a function with layers is not supported. To test in the cloud: run "amplify push" to deploy your function to the cloud and then run "amplify console function" to test your function in the Lambda console.

Describe the solution you'd like Use Docker to install yumda packages and test it locally, maybe with a flag --docker

Describe alternatives you've considered Test locally using common mocks

ErickWendel avatar Jul 14 '20 00:07 ErickWendel

I have the same problem...

abraira85 avatar Jul 21 '20 04:07 abraira85

Same problem here...

arturocanalda avatar Sep 30 '20 11:09 arturocanalda

Same, amplify should support testing all the features with Docker, like Sam does at least

MontoyaAndres avatar Dec 12 '20 12:12 MontoyaAndres

Any updates on it ?

nathanagez avatar Jul 25 '21 21:07 nathanagez

same problem i am facing while running this command amplify mock function storageTrigger

Unable to mock storageTrigger. Mocking a function with layers is not supported. To test in the cloud: run "amplify push" to deploy your function to the cloud and then run "amplify console function" to test your function in the Lambda console.

babaralishah avatar Sep 08 '21 09:09 babaralishah

I wonder what's the challenge with enabling mocks for functions with layers? From what I saw, we just need to setup the correct NODE_PATH to the layer modules during runtime in order to make require work.

ivadenis avatar Jan 13 '22 09:01 ivadenis

I've noticed this only seems to be a soft limitation of Amplify, since by temporarily removing the associated layer from the function's dependsOn array within amplify-meta.json, I'm still able to mock these functions as long as the assets for the layer are otherwise provided.

I've been working around this limitation using this method for a while now and haven't found any drawbacks of it as long as the dev env and build process are set up properly, so is there any chance this could be made toggleable with a switch on the mock command or a feature flag?

mewtlu avatar Jun 24 '22 13:06 mewtlu

Any progress on the topic?

tb102122 avatar Feb 24 '23 12:02 tb102122

@mewtlu Thanks for sharing your solution.

Could please share some code examples? with all the things you tweaked.

Some more context of my case:

I use the Appsync graphql layer (const API = require('@aws-amplify/api').default;) inside a lambda function.

That lambda function is used to handle one route of the API Gateway.

estebanmunchjones2019 avatar Apr 14 '23 15:04 estebanmunchjones2019

@mewtlu Thanks for sharing your solution.

Could please share some code examples? with all the things you tweaked.

Some more context of my case:

I use the Appsync graphql layer (const API = require('@aws-amplify/api').default;) inside a lambda function.

That lambda function is used to handle one route of the API Gateway.

I'm not sure if there are any further issues related to the specifics of your situation, but to be able to mock any function that has a Lambda layer all that is required is manually editing your local amplify/backend/amplify-meta.json file to remove the Lambda Layer from the dependsOn array within that function's block in the Resource object.

I run the following bash script using jq whilst in in amplify/backend/ to do this automatically for me: cat amplify-meta.json | jq \". * { function: .function | map_values(if .dependsOn then del(.dependsOn[] | select(.resourceName == \\\"MyLambdaLayerName\\\")) else . end) }\" > amplify-meta.n.json
(replacing MyLambdaLayerName with the name of your Lambda Layer)

Hope this helps.

mewtlu avatar Apr 14 '23 17:04 mewtlu

@mewtlu how does your solution gets the related code stored in the lambda layer folders?

tb102122 avatar Apr 14 '23 22:04 tb102122

@mewtlu how does your solution gets the related code stored in the lambda layer folders?

If you're asking how we provide the code in the layer to the functions within the dev environment I simply use local npm dependencies, within my frontend application's package.json I have an npm dependency on the package within the monorepo which contains the code used for the Lambda Layer such as: "@org/shared": "../lib/shared" and the backend functions have a dependency on the same local package such as: "@org/shared": "../../../../lib/shared"

As the Lambda layer contains TypeScript code/types we also use TS project references to support this which nicely links up in a similar manner using relative paths within the monorepo, then we simply have a deployment step that builds and copies the code from lib/shared into amplify/backend/functions/MyLambdaLayerName/lib/nodejs ready for Amplify to use for deployment.

mewtlu avatar Apr 15 '23 00:04 mewtlu

@mewtlu So you manually remove these local dependencies before you run amplify push/publish?

tb102122 avatar Apr 16 '23 23:04 tb102122

Ah no, these changes are only ever made to the amplify-meta file which I believe should always be overwritten automatically before any deploys (with the built contents of the backend-config file).

This change is only made to affect the amplify mock command which appears to begin with a local check on the amplify-meta.json to see if the function depends on any layers, meaning that if the specified change has been made this check will pass and we are able to mock the function, without actually affecting the function/layer in any way.

mewtlu avatar Apr 17 '23 07:04 mewtlu

@mewtlu Thanks for sharing your solution. Could please share some code examples? with all the things you tweaked. Some more context of my case: I use the Appsync graphql layer (const API = require('@aws-amplify/api').default;) inside a lambda function. That lambda function is used to handle one route of the API Gateway.

I'm not sure if there are any further issues related to the specifics of your situation, but to be able to mock any function that has a Lambda layer all that is required is manually editing your local amplify/backend/amplify-meta.json file to remove the Lambda Layer from the dependsOn array within that function's block in the Resource object.

I run the following bash script using jq whilst in in amplify/backend/ to do this automatically for me: cat amplify-meta.json | jq \". * { function: .function | map_values(if .dependsOn then del(.dependsOn[] | select(.resourceName == \\\"MyLambdaLayerName\\\")) else . end) }\" > amplify-meta.n.json (replacing MyLambdaLayerName with the name of your Lambda Layer)

Hope this helps.

Thanks a lot @mewtlu . I'll give it a shot.

estebanmunchjones2019 avatar Apr 18 '23 09:04 estebanmunchjones2019

@mewtlu how does your solution gets the related code stored in the lambda layer folders?

If you're asking how we provide the code in the layer to the functions within the dev environment I simply use local npm dependencies, within my frontend application's package.json I have an npm dependency on the package within the monorepo which contains the code used for the Lambda Layer such as: "@org/shared": "../lib/shared" and the backend functions have a dependency on the same local package such as: "@org/shared": "../../../../lib/shared"

As the Lambda layer contains TypeScript code/types we also use TS project references to support this which nicely links up in a similar manner using relative paths within the monorepo, then we simply have a deployment step that builds and copies the code from lib/shared into amplify/backend/functions/MyLambdaLayerName/lib/nodejs ready for Amplify to use for deployment.

How do you handle the layer paths within the lambda function? Ex: /opt/folder/file.js ? Could you share your whole solution step by step?

Man... not being able to test locally is doing my head. I not only have to deploy my whole application in order to test, i often get an error because of the number of layers it get created

Name: LambdaLayerPermissionAwsAccounts533367446078faf35141Legacy155 (AWS::Lambda::LayerVersionPermission), Event Type: create, Reason: Resource handler returned message: "1 validation error detected: Value '533367446078faf35141' at 'principal' failed to satisfy constraint: Member must satisfy regular expression pattern: \d{12}|\*|arn:(aws[a-zA-Z-]*):iam::\d{12}:root (Service: AWSLambdaInternal; Status Code: 400; Error Code: ValidationException; Request ID: eef4dc1a-035b-4405-ad3b-4a7d4f3bf196; Proxy: null)" (RequestToken: 226e2302-7f1d-e1b4-e21b-f8a3b271113b, HandlerErrorCode: GeneralServiceException), IsCustomResource: false

rafaelfaria avatar Mar 30 '24 10:03 rafaelfaria