Skip to content

feat: add integration tests stack #379

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
/target
/.cargo
lambda-runtime/libtest.rmeta
lambda-integration-tests/target
Cargo.lock

# Built AWS Lambda zipfile
lambda.zip

# output.json from example docs
output.json

.aws-sam
build
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = [
"lambda-http",
"lambda-integration-tests",
"lambda-runtime-api-client",
"lambda-runtime",
"lambda-extension"
Expand Down
48 changes: 48 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
INTEG_STACK_NAME ?= rust-lambda-integration-tests
INTEG_FUNCTIONS_BUILD := runtime-fn runtime-trait http-fn
INTEG_FUNCTIONS_INVOKE := RuntimeFn RuntimeFnAl2 RuntimeTrait RuntimeTraitAl2 Python PythonAl2
INTEG_API_INVOKE := RestApiUrl HttpApiUrl
INTEG_EXTENSIONS := extension-fn extension-trait
# Using musl to run extensions on both AL1 and AL2
INTEG_ARCH := x86_64-unknown-linux-musl

integration-tests:
# Build Integration functions
cross build --release --target $(INTEG_ARCH) -p lambda_integration_tests
rm -rf ./build
mkdir -p ./build
${MAKE} ${MAKEOPTS} $(foreach function,${INTEG_FUNCTIONS_BUILD}, build-integration-function-${function})
${MAKE} ${MAKEOPTS} $(foreach extension,${INTEG_EXTENSIONS}, build-integration-extension-${extension})
# Deploy to AWS
sam deploy \
--template lambda-integration-tests/template.yaml \
--stack-name ${INTEG_STACK_NAME} \
--capabilities CAPABILITY_IAM \
--resolve-s3 \
--no-fail-on-empty-changeset
# Invoke functions
${MAKE} ${MAKEOPTS} $(foreach function,${INTEG_FUNCTIONS_INVOKE}, invoke-integration-function-${function})
${MAKE} ${MAKEOPTS} $(foreach api,${INTEG_API_INVOKE}, invoke-integration-api-${api})

build-integration-function-%:
mkdir -p ./build/$*
cp -v ./target/$(INTEG_ARCH)/release/$* ./build/$*/bootstrap

build-integration-extension-%:
mkdir -p ./build/$*/extensions
cp -v ./target/$(INTEG_ARCH)/release/$* ./build/$*/extensions/$*

invoke-integration-function-%:
aws lambda invoke --function-name $$(aws cloudformation describe-stacks --stack-name $(INTEG_STACK_NAME) \
--query 'Stacks[0].Outputs[?OutputKey==`$*`].OutputValue' \
--output text) --payload '{"command": "hello"}' --cli-binary-format raw-in-base64-out /dev/stdout

invoke-integration-api-%:
$(eval API_URL := $(shell aws cloudformation describe-stacks --stack-name $(INTEG_STACK_NAME) \
--query 'Stacks[0].Outputs[?OutputKey==`$*`].OutputValue' \
--output text))
curl $(API_URL)/get
curl $(API_URL)/al2/get
curl -X POST -d '{"command": "hello"}' $(API_URL)/post
curl -X POST -d '{"command": "hello"}' $(API_URL)/al2/post

4 changes: 2 additions & 2 deletions lambda-extension/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![deny(clippy::all, clippy::cargo)]
#![allow(clippy::multiple_crate_versions)]
#![warn(missing_docs, nonstandard_style, rust_2018_idioms)]

//! This module includes utilities to create Lambda Runtime Extensions.
Expand All @@ -8,8 +9,7 @@
use hyper::client::{connect::Connection, HttpConnector};
use lambda_runtime_api_client::Client;
use serde::Deserialize;
use std::future::Future;
use std::path::PathBuf;
use std::{future::Future, path::PathBuf};
use tokio::io::{AsyncRead, AsyncWrite};
use tokio_stream::StreamExt;
use tower_service::Service;
Expand Down
21 changes: 21 additions & 0 deletions lambda-integration-tests/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "lambda_integration_tests"
version = "0.4.1"
edition = "2018"
description = "AWS Lambda Runtime integration tests"
license = "Apache-2.0"
repository = "https://github.com/awslabs/aws-lambda-rust-runtime"
categories = ["web-programming::http-server"]
keywords = ["AWS", "Lambda", "API"]
readme = "../README.md"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
lambda_http = { path = "../lambda-http", version = "0.4.1" }
lambda_runtime = { path = "../lambda-runtime", version = "0.4.1" }
lambda_extension = { path = "../lambda-extension", version = "0.1.0" }
log = "0.4"
serde = { version = "1", features = ["derive"] }
simple_logger = { version = "1.15", default-features = false }
tokio = { version = "1", features = ["full"] }
4 changes: 4 additions & 0 deletions lambda-integration-tests/python/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
def handler(event, context):
return {
"message": event["command"].upper()
}
23 changes: 23 additions & 0 deletions lambda-integration-tests/src/bin/extension-fn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
use lambda_extension::{extension_fn, Error, NextEvent};
use log::{info, LevelFilter};
use simple_logger::SimpleLogger;

async fn my_extension(event: NextEvent) -> Result<(), Error> {
match event {
NextEvent::Shutdown(e) => {
info!("[extension-fn] Shutdown event received: {:?}", e);
}
NextEvent::Invoke(e) => {
info!("[extension-fn] Request event received: {:?}", e);
}
}

Ok(())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
SimpleLogger::new().with_level(LevelFilter::Info).init().unwrap();

lambda_extension::run(extension_fn(my_extension)).await
}
37 changes: 37 additions & 0 deletions lambda-integration-tests/src/bin/extension-trait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use lambda_extension::{Error, Extension, NextEvent};
use log::{info, LevelFilter};
use simple_logger::SimpleLogger;
use std::{
future::{ready, Future},
pin::Pin,
};

#[derive(Default)]
struct MyExtension {
invoke_count: usize,
}

impl Extension for MyExtension {
type Fut = Pin<Box<dyn Future<Output = Result<(), Error>>>>;

fn call(&mut self, event: NextEvent) -> Self::Fut {
match event {
NextEvent::Shutdown(e) => {
info!("[extension] Shutdown event received: {:?}", e);
}
NextEvent::Invoke(e) => {
self.invoke_count += 1;
info!("[extension] Request event {} received: {:?}", self.invoke_count, e);
}
}

Box::pin(ready(Ok(())))
}
}

#[tokio::main]
async fn main() -> Result<(), Error> {
SimpleLogger::new().with_level(LevelFilter::Info).init().unwrap();

lambda_extension::run(MyExtension::default()).await
}
19 changes: 19 additions & 0 deletions lambda-integration-tests/src/bin/http-fn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use lambda_http::{
lambda_runtime::{self, Context, Error},
IntoResponse, Request, Response,
};
use log::{info, LevelFilter};
use simple_logger::SimpleLogger;

async fn handler(event: Request, _context: Context) -> Result<impl IntoResponse, Error> {
info!("[http-fn] Received event {} {}", event.method(), event.uri().path());

Ok(Response::builder().status(200).body("Hello, world!").unwrap())
}

#[tokio::main]
async fn main() -> Result<(), Error> {
SimpleLogger::new().with_level(LevelFilter::Info).init().unwrap();

lambda_runtime::run(lambda_http::handler(handler)).await
}
29 changes: 29 additions & 0 deletions lambda-integration-tests/src/bin/runtime-fn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use lambda_runtime::{handler_fn, Context, Error};
use log::{info, LevelFilter};
use serde::{Deserialize, Serialize};
use simple_logger::SimpleLogger;

#[derive(Deserialize, Debug)]
struct Request {
command: String,
}

#[derive(Serialize, Debug)]
struct Response {
message: String,
}

async fn handler(event: Request, _context: Context) -> Result<Response, Error> {
info!("[handler-fn] Received event: {:?}", event);

Ok(Response {
message: event.command.to_uppercase(),
})
}

#[tokio::main]
async fn main() -> Result<(), Error> {
SimpleLogger::new().with_level(LevelFilter::Info).init().unwrap();

lambda_runtime::run(handler_fn(handler)).await
}
43 changes: 43 additions & 0 deletions lambda-integration-tests/src/bin/runtime-trait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use lambda_runtime::{Context, Error, Handler};
use log::{info, LevelFilter};
use serde::{Deserialize, Serialize};
use simple_logger::SimpleLogger;
use std::{
future::{ready, Future},
pin::Pin,
};

#[derive(Deserialize, Debug)]
struct Request {
command: String,
}

#[derive(Serialize, Debug)]
struct Response {
message: String,
}

#[derive(Default)]
struct MyHandler {
invoke_count: usize,
}

impl Handler<Request, Response> for MyHandler {
type Error = Error;
type Fut = Pin<Box<dyn Future<Output = Result<Response, Error>>>>;

fn call(&mut self, event: Request, _context: Context) -> Self::Fut {
self.invoke_count += 1;
info!("[handler] Received event {}: {:?}", self.invoke_count, event);
Box::pin(ready(Ok(Response {
message: event.command.to_uppercase(),
})))
}
}

#[tokio::main]
async fn main() -> Result<(), Error> {
SimpleLogger::new().with_level(LevelFilter::Info).init().unwrap();

lambda_runtime::run(MyHandler::default()).await
}
Loading