Skip to content

Commit 83fa77d

Browse files
committed
feat: media types api testing setup
we can use this new api gateway with the aws cli to change its configured contentHandling value between each verfications
1 parent d58a1bc commit 83fa77d

File tree

4 files changed

+202
-11
lines changed

4 files changed

+202
-11
lines changed

Makefile

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
INTEG_STACK_NAME ?= rust-lambda-integration-tests
2-
INTEG_FUNCTIONS_BUILD := runtime-fn runtime-trait http-fn http-trait
2+
INTEG_FUNCTIONS_BUILD := runtime-fn runtime-trait http-fn http-trait text-fn binary-fn
33
INTEG_FUNCTIONS_INVOKE := RuntimeFn RuntimeFnAl2 RuntimeTrait RuntimeTraitAl2 Python PythonAl2
44
INTEG_API_INVOKE := RestApiUrl HttpApiUrl
5+
INTEG_RESOURCES := BinaryFnResource TextFnResource
56
INTEG_EXTENSIONS := extension-fn extension-trait logs-trait
67
# Using musl to run extensions on both AL1 and AL2
78
INTEG_ARCH := x86_64-unknown-linux-musl
@@ -17,20 +18,26 @@ pr-check:
1718
cargo +1.54.0 test
1819
cargo +stable test
1920

20-
integration-tests:
21-
# Build Integration functions
21+
build-all:
2222
cargo zigbuild --release --target $(INTEG_ARCH) -p lambda_integration_tests
2323
rm -rf ./build
2424
mkdir -p ./build
2525
${MAKE} ${MAKEOPTS} $(foreach function,${INTEG_FUNCTIONS_BUILD}, build-integration-function-${function})
2626
${MAKE} ${MAKEOPTS} $(foreach extension,${INTEG_EXTENSIONS}, build-integration-extension-${extension})
27-
# Deploy to AWS
27+
28+
deploy:
2829
sam deploy \
2930
--template lambda-integration-tests/template.yaml \
3031
--stack-name ${INTEG_STACK_NAME} \
3132
--capabilities CAPABILITY_IAM \
3233
--resolve-s3 \
3334
--no-fail-on-empty-changeset
35+
36+
integration-tests:
37+
# Build Integration functions
38+
${MAKE} build-all
39+
# Deploy to AWS
40+
${MAKE} deploy
3441
# Invoke functions
3542
${MAKE} ${MAKEOPTS} $(foreach function,${INTEG_FUNCTIONS_INVOKE}, invoke-integration-function-${function})
3643
${MAKE} ${MAKEOPTS} $(foreach api,${INTEG_API_INVOKE}, invoke-integration-api-${api})
@@ -60,3 +67,37 @@ invoke-integration-api-%:
6067
curl -X POST -d '{"command": "hello"}' $(API_URL)/trait/post
6168
curl -X POST -d '{"command": "hello"}' $(API_URL)/al2/post
6269
curl -X POST -d '{"command": "hello"}' $(API_URL)/al2-trait/post
70+
71+
verify-all:
72+
${MAKE} ${MAKEOPTS} $(foreach resource,${INTEG_RESOURCES}, verify-media-type-responses-${resource})
73+
74+
verify-media-type-responses-%:
75+
$(eval RESOURCE_ID := $(shell aws cloudformation describe-stacks --stack-name $(INTEG_STACK_NAME) \
76+
--query 'Stacks[0].Outputs[?OutputKey==`$*`].OutputValue' \
77+
--output text))
78+
$(eval API_ID := $(shell aws cloudformation describe-stacks --stack-name $(INTEG_STACK_NAME) \
79+
--query 'Stacks[0].Outputs[?OutputKey==`MediaTypesApi`].OutputValue' \
80+
--output text))
81+
$(eval API_URL := $(shell aws cloudformation describe-stacks --stack-name $(INTEG_STACK_NAME) \
82+
--query 'Stacks[0].Outputs[?OutputKey==`MediaTypesApiUrl`].OutputValue' \
83+
--output text))
84+
# configure with CONVERT_TO_BINARY
85+
aws apigateway update-integration --rest-api-id $(API_ID) --resource-id $(RESOURCE_ID) --http-method GET \
86+
--patch-operations op=replace,path=/contentHandling,value=CONVERT_TO_BINARY
87+
88+
# verify responses
89+
aws apigateway test-invoke-method --rest-api-id $(API_ID) --resource-id $(RESOURCE_ID) --http-method GET
90+
91+
# configure with CONVERT_TO_TEXT
92+
aws apigateway update-integration --rest-api-id $(API_ID) --resource-id $(RESOURCE_ID) --http-method GET \
93+
--patch-operations op=replace,path=/contentHandling,value=CONVERT_TO_TEXT
94+
95+
# verify responses
96+
aws apigateway test-invoke-method --rest-api-id $(API_ID) --resource-id $(RESOURCE_ID) --http-method GET
97+
98+
# remove contentHandling configuration
99+
aws apigateway update-integration --rest-api-id $(API_ID) --resource-id $(RESOURCE_ID) --http-method GET \
100+
--patch-operations op=replace,path=/contentHandling,value=
101+
102+
# verify responses
103+
aws apigateway test-invoke-method --rest-api-id $(API_ID) --resource-id $(RESOURCE_ID) --http-method GET
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use lambda_http::{service_fn, Body, Error, IntoResponse, Request, Response};
2+
use tracing::info;
3+
4+
async fn handler(event: Request) -> Result<impl IntoResponse, Error> {
5+
let path = event.uri().path();
6+
info!("[binary-fn] path {}", path);
7+
8+
Ok(Response::builder()
9+
.status(200)
10+
.body(Body::from("binary data".as_bytes()))
11+
.unwrap())
12+
}
13+
14+
#[tokio::main]
15+
async fn main() -> Result<(), Error> {
16+
// The runtime logging can be enabled here by initializing `tracing` with `tracing-subscriber`
17+
// While `tracing` is used internally, `log` can be used as well if preferred.
18+
tracing_subscriber::fmt()
19+
.with_max_level(tracing::Level::INFO)
20+
// this needs to be set to false, otherwise ANSI color codes will
21+
// show up in a confusing manner in CloudWatch logs.
22+
.with_ansi(false)
23+
// disabling time is handy because CloudWatch will add the ingestion time.
24+
.without_time()
25+
.init();
26+
27+
let handler = service_fn(handler);
28+
lambda_http::run(handler).await
29+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use lambda_http::{service_fn, Body, Error, IntoResponse, Request, Response};
2+
use tracing::info;
3+
4+
async fn handler(event: Request) -> Result<impl IntoResponse, Error> {
5+
let path = event.uri().path();
6+
info!("[text-fn] path {}", path);
7+
8+
Ok(Response::builder().status(200).body(Body::from("text data")).unwrap())
9+
}
10+
11+
#[tokio::main]
12+
async fn main() -> Result<(), Error> {
13+
// The runtime logging can be enabled here by initializing `tracing` with `tracing-subscriber`
14+
// While `tracing` is used internally, `log` can be used as well if preferred.
15+
tracing_subscriber::fmt()
16+
.with_max_level(tracing::Level::INFO)
17+
// this needs to be set to false, otherwise ANSI color codes will
18+
// show up in a confusing manner in CloudWatch logs.
19+
.with_ansi(false)
20+
// disabling time is handy because CloudWatch will add the ingestion time.
21+
.without_time()
22+
.init();
23+
24+
let handler = service_fn(handler);
25+
lambda_http::run(handler).await
26+
}

lambda-integration-tests/template.yaml

Lines changed: 102 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
AWSTemplateFormatVersion: '2010-09-09'
1+
AWSTemplateFormatVersion: "2010-09-09"
22
Transform: AWS::Serverless-2016-10-31
33

44
Globals:
@@ -18,7 +18,7 @@ Resources:
1818
- !Ref LogsTrait
1919
- !Ref ExtensionFn
2020
- !Ref ExtensionTrait
21-
21+
2222
# Rust function using runtime_fn running on AL1
2323
RuntimeFn:
2424
Type: AWS::Serverless::Function
@@ -40,7 +40,7 @@ Resources:
4040
- !Ref LogsTrait
4141
- !Ref ExtensionFn
4242
- !Ref ExtensionTrait
43-
43+
4444
# Rust function using a Service implementation running on AL1
4545
RuntimeTrait:
4646
Type: AWS::Serverless::Function
@@ -51,7 +51,7 @@ Resources:
5151
- !Ref LogsTrait
5252
- !Ref ExtensionFn
5353
- !Ref ExtensionTrait
54-
54+
5555
# Rust function using lambda_http::service_fn running on AL2
5656
HttpFnAl2:
5757
Type: AWS::Serverless::Function
@@ -83,7 +83,7 @@ Resources:
8383
- !Ref LogsTrait
8484
- !Ref ExtensionFn
8585
- !Ref ExtensionTrait
86-
86+
8787
# Rust function using lambda_http with Service running on AL2
8888
HttpTraitAl2:
8989
Type: AWS::Serverless::Function
@@ -204,6 +204,93 @@ Resources:
204204
- !Ref ExtensionFn
205205
- !Ref ExtensionTrait
206206

207+
# Api GW with a binary media type configured
208+
MediaTypesApi:
209+
Type: AWS::ApiGateway::RestApi
210+
Properties:
211+
Name: !Sub ${AWS::StackName}-responses
212+
BinaryMediaTypes:
213+
- "application~1octet-stream"
214+
215+
MediaTypesApiDeployment:
216+
Type: AWS::ApiGateway::Deployment
217+
DependsOn:
218+
- TextResourceGet
219+
- BinaryResourceGet
220+
Properties:
221+
RestApiId: !Ref MediaTypesApi
222+
StageName: Prod
223+
224+
TextResource:
225+
Type: AWS::ApiGateway::Resource
226+
Properties:
227+
RestApiId: !Ref MediaTypesApi
228+
ParentId: !GetAtt ["MediaTypesApi", "RootResourceId"]
229+
PathPart: text
230+
231+
TextResourceGet:
232+
Type: "AWS::ApiGateway::Method"
233+
Properties:
234+
RestApiId: !Ref MediaTypesApi
235+
ResourceId: !Ref TextResource
236+
HttpMethod: GET
237+
AuthorizationType: NONE
238+
Integration:
239+
Type: AWS
240+
IntegrationHttpMethod: POST
241+
Uri: !Sub >-
242+
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${TextFn.Arn}/invocations
243+
244+
BinaryResource:
245+
Type: AWS::ApiGateway::Resource
246+
Properties:
247+
RestApiId: !Ref MediaTypesApi
248+
ParentId: !GetAtt ["MediaTypesApi", "RootResourceId"]
249+
PathPart: binary
250+
251+
BinaryResourceGet:
252+
Type: "AWS::ApiGateway::Method"
253+
Properties:
254+
RestApiId: !Ref MediaTypesApi
255+
ResourceId: !Ref BinaryResource
256+
HttpMethod: GET
257+
AuthorizationType: NONE
258+
Integration:
259+
Type: AWS
260+
IntegrationHttpMethod: POST
261+
Uri: !Sub >-
262+
arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${BinaryFn.Arn}/invocations
263+
264+
# Rust function using lambda_http with Service testing text responses
265+
TextFn:
266+
Type: AWS::Serverless::Function
267+
Properties:
268+
CodeUri: ../build/text-fn/
269+
Runtime: provided
270+
271+
TextFnInvokePermission:
272+
Type: AWS::Lambda::Permission
273+
Properties:
274+
FunctionName: !Ref TextFn
275+
Action: lambda:InvokeFunction
276+
Principal: apigateway.amazonaws.com
277+
SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${MediaTypesApi}/*/GET/text
278+
279+
# Rust function using lambda_http with Service testing binary responses
280+
BinaryFn:
281+
Type: AWS::Serverless::Function
282+
Properties:
283+
CodeUri: ../build/binary-fn/
284+
Runtime: provided
285+
286+
BinaryFnInvokePermission:
287+
Type: AWS::Lambda::Permission
288+
Properties:
289+
FunctionName: !Ref BinaryFn
290+
Action: lambda:InvokeFunction
291+
Principal: apigateway.amazonaws.com
292+
SourceArn: !Sub arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${MediaTypesApi}/*/GET/binary
293+
207294
LogsTrait:
208295
Type: AWS::Serverless::LayerVersion
209296
Properties:
@@ -213,7 +300,7 @@ Resources:
213300
Type: AWS::Serverless::LayerVersion
214301
Properties:
215302
ContentUri: ../build/extension-fn/
216-
303+
217304
ExtensionTrait:
218305
Type: AWS::Serverless::LayerVersion
219306
Properties:
@@ -236,4 +323,12 @@ Outputs:
236323
RestApiUrl:
237324
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod"
238325
HttpApiUrl:
239-
Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com"
326+
Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com"
327+
MediaTypesApiUrl:
328+
Value: !Sub "https://${MediaTypesApi}.execute-api.${AWS::Region}.amazonaws.com"
329+
MediaTypesApi:
330+
Value: !Ref MediaTypesApi
331+
TextFnResource:
332+
Value: !GetAtt ["TextResource", "ResourceId"]
333+
BinaryFnResource:
334+
Value: !GetAtt ["BinaryResource", "ResourceId"]

0 commit comments

Comments
 (0)