I was writing a Lambda function with the AWS Serverless Application Model to do a maintenance task. I’d written my code, my unit tests and all was good. I had a problem, though. Invoking the Lambda for a local end-to-end test was failing. It couldn’t read some resource files despite the paths being correct.
I hadn’t had my coffee, so it took longer that I’d care to admit to twig that the Lambda was running in a container. It couldn’t actually access those files! Now I had a new problem to solve: How do I get my test data into the SAM environment so I could perform an end-to-end test?
After a lot of fruitless searching around I looked closer into using Lambda layers to make the data available. Layers pull extra code and content into the Lambda runtime environment. Given this was the medium I had intended to use in production it made sense to use it for local testing too. There were a couple of obstacles this approach, which is why I had ignored it up to this point:
I still needed to be able to run an end-to-end test so I scoured the SAM and layers documentation. I hoped for some magical configuration that would allow me to pre-copy the data. It’s not there, but after a while of staring at this and this I had a thought: Could I fake it?
I was reading the “Working with layers” document the description of how SAM caches layers. I wondered if I could “pre-cache” my test data as a layer in the cache so SAM would’t try fetching it from anywhere. The cache directory name format is documented as LayerName-Version-<first 10 characters of sha256 of ARN>
. I should be able to configure a layer and work out the cached directory name.
I gave my fake layer the ARN arn:aws:lambda:ap-southeast-2:000000000000:layer:testdata:1
. According to the docs I would need to create a directory in the cache named testdata-1-29450a214e
. By default SAM caches layers in ~/.aws-sam/layers-pkg
. I didn’t want to go copying folders around if I could help it. Luckily the SAM CLI has the parameter -layer-cache-basedir
, which allows you to tell it where to look for layer caches. Well, there is no directory like the present (working directory). Sorry.
I already had a directory named testdata
so I renamed it to the expected cache directory. When I next ran sam local invoke
I pointed it at my test template YAML file and added the parameter -layer-cache-basedir .
. An image was created with the cached “layer” and my end-to-end test ran.
Let me summarise that in a step-by-step process:
arn:aws:lambda:${Region}:000000000000:layer:${LayerName}:${Version}
.template.yaml
add a parameter named LayerArn
for the layer. In the configuration section for the Lambda add a Layers
section with an item referencing LayerArn
. You can give LayerArn
the default value of the ARN or pass it in as a parameter, described below.sam local invoke
using your testing template and with layer-cache-basedir
set as one level above your cache directory. If that is the root of the project then it would be .
. If you have not added the fake layer ARN as the default value of LayerArn
you will need to pass it in here too. The parameter would be --parameter-overrides ParameterKey=LayerArn,ParameterValue=arn:aws:lambda:ap-southeast-2:000000000000:layer:testdata:1
. Substitute that ARN for the one you came up with.And that’s all there was to it. I could now show the Lambda running with local test data imported as a layer. You do not need Localstack to achieve this. I happen to use it for testing.
Did this help you out? Do you have a better solution? I’d love it if you dropped me a note to let me know.
Banner image by Troy Squillaci