From 9b95ebf6671a674ab97ede27cf876b4364811633 Mon Sep 17 00:00:00 2001 From: Maxime David Date: Wed, 31 Jul 2024 10:21:38 +0000 Subject: [PATCH 1/7] feat: run integration tests on CI --- .github/workflows/run-integration-test.yml | 62 +++++++++++++++++++ Cargo.toml | 1 + lambda-integration-tests-ci/Cargo.toml | 31 ++++++++++ lambda-integration-tests-ci/samconfig.toml | 27 ++++++++ lambda-integration-tests-ci/src/authorizer.rs | 61 ++++++++++++++++++ lambda-integration-tests-ci/src/helloworld.rs | 34 ++++++++++ lambda-integration-tests-ci/template.yaml | 58 +++++++++++++++++ .../tests/integration_test.rs | 12 ++++ 8 files changed, 286 insertions(+) create mode 100644 .github/workflows/run-integration-test.yml create mode 100644 lambda-integration-tests-ci/Cargo.toml create mode 100644 lambda-integration-tests-ci/samconfig.toml create mode 100644 lambda-integration-tests-ci/src/authorizer.rs create mode 100644 lambda-integration-tests-ci/src/helloworld.rs create mode 100644 lambda-integration-tests-ci/template.yaml create mode 100644 lambda-integration-tests-ci/tests/integration_test.rs diff --git a/.github/workflows/run-integration-test.yml b/.github/workflows/run-integration-test.yml new file mode 100644 index 00000000..53f52e74 --- /dev/null +++ b/.github/workflows/run-integration-test.yml @@ -0,0 +1,62 @@ +name: Run integration tests + +permissions: + id-token: write + contents: read + +on: + workflow_dispatch: + push: + +jobs: + run-integration-tests: + runs-on: ubuntu-latest + steps: + - name: install Cargo Lambda + uses: jaxxstorm/action-install-gh-release@v1.9.0 + with: + repo: cargo-lambda/cargo-lambda + platform: linux + arch: x86_64 + - name: install Zig toolchain + uses: korandoru/setup-zig@v1 + with: + zig-version: 0.10.0 + - name: install SAM + uses: aws-actions/setup-sam@v2 + with: + use-installer: true + - uses: actions/checkout@v3 + - name: configure aws credentials + uses: aws-actions/configure-aws-credentials@v4.0.2 + with: + role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} + role-session-name: ${{ secrets.ROLE_SESSION_NAME }} + aws-region: ${{ secrets.AWS_REGION }} + - name: build stack + run: cd lambda-integration-tests-ci && sam build --beta-features + - name: validate stack + run: cd lambda-integration-tests-ci && sam validate --lint + - name: deploy stack + id: deploy_stack + env: + AWS_REGION: ${{ secrets.AWS_REGION }} + run: | + cd lambda-integration-tests-ci + stackName="aws-lambda-rust-integ-test-$GITHUB_RUN_ID" + echo "STACK_NAME=$stackName" >> "$GITHUB_OUTPUT" + echo "Stack name = $stackName" + sam deploy --stack-name "${stackName}" --parameter-overrides "ParameterKey=SecretToken,ParameterValue=${{ secrets.SECRET_TOKEN }}" --no-confirm-changeset --no-progressbar > disable_output + TEST_ENDPOINT=$(sam list stack-outputs --stack-name "${stackName}" --output json | jq -r '.[] | .OutputValue') + echo "TEST_ENDPOINT=$TEST_ENDPOINT" >> "$GITHUB_OUTPUT" + - name: run test + env: + SECRET_TOKEN: ${{ secrets.SECRET_TOKEN }} + TEST_ENDPOINT: ${{ steps.deploy_stack.outputs.TEST_ENDPOINT }} + run: cd lambda-integration-tests-ci && cargo test + - name: cleanup + if: always() + env: + AWS_REGION: ${{ secrets.AWS_REGION }} + STACK_NAME: ${{ steps.deploy_stack.outputs.STACK_NAME }} + run: sam delete --stack-name "${STACK_NAME}" --no-prompts diff --git a/Cargo.toml b/Cargo.toml index c55f0e60..00a2a1a5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ resolver = "2" members = [ "lambda-http", "lambda-integration-tests", + "lambda-integration-tests-ci", "lambda-runtime-api-client", "lambda-runtime", "lambda-extension", diff --git a/lambda-integration-tests-ci/Cargo.toml b/lambda-integration-tests-ci/Cargo.toml new file mode 100644 index 00000000..9812288f --- /dev/null +++ b/lambda-integration-tests-ci/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "aws_lambda_rust_integration_tests" +version = "0.1.0" +authors = ["Maxime David"] +edition = "2021" +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" + +[dependencies] +lambda_runtime = { path = "../lambda-runtime" } +aws_lambda_events = { path = "../lambda-events" } +serde_json = "1.0.121" +tokio = { version = "1", features = ["full"] } +tracing-subscriber = { version = "0.3", default-features = false, features = ["json"] } +serde = { version = "1.0.204", features = ["derive"] } + +[dev-dependencies] +reqwest = { version = "0.12.5", features = ["blocking"] } +openssl = { version = "0.10", features = ["vendored"] } + +[[bin]] +name = "helloworld" +path = "src/helloworld.rs" + +[[bin]] +name = "authorizer" +path = "src/authorizer.rs" diff --git a/lambda-integration-tests-ci/samconfig.toml b/lambda-integration-tests-ci/samconfig.toml new file mode 100644 index 00000000..8f88b383 --- /dev/null +++ b/lambda-integration-tests-ci/samconfig.toml @@ -0,0 +1,27 @@ +version = 0.1 + +[default] +[default.build.parameters] +cached = true +parallel = true + +[default.validate.parameters] +lint = true + +[default.deploy.parameters] +capabilities = "CAPABILITY_IAM" +confirm_changeset = true +resolve_s3 = true +s3_prefix = "aws-lambda-rust-integration-test" + +[default.package.parameters] +resolve_s3 = true + +[default.sync.parameters] +watch = true + +[default.local_start_api.parameters] +warm_containers = "EAGER" + +[default.local_start_lambda.parameters] +warm_containers = "EAGER" \ No newline at end of file diff --git a/lambda-integration-tests-ci/src/authorizer.rs b/lambda-integration-tests-ci/src/authorizer.rs new file mode 100644 index 00000000..7741216c --- /dev/null +++ b/lambda-integration-tests-ci/src/authorizer.rs @@ -0,0 +1,61 @@ +use std::env; + +use aws_lambda_events::{ + apigw::{ApiGatewayCustomAuthorizerPolicy, ApiGatewayCustomAuthorizerResponse}, + event::iam::IamPolicyStatement, +}; +use lambda_runtime::{service_fn, Error, LambdaEvent}; +use serde::Deserialize; +use serde_json::json; +use tracing_subscriber::EnvFilter; + +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +struct APIGatewayCustomAuthorizerRequest { + authorization_token: String, + method_arn: String, +} + +#[tokio::main] +async fn main() -> Result<(), Error> { + tracing_subscriber::fmt() + .json() + .with_env_filter(EnvFilter::from_default_env()) + .with_target(false) + .with_current_span(false) + .with_span_list(false) + .without_time() + .init(); + let func = service_fn(func); + lambda_runtime::run(func).await?; + Ok(()) +} + +async fn func( + event: LambdaEvent, +) -> Result { + let expected_token = env::var("SECRET_TOKEN").expect("could not read the secret token"); + if event.payload.authorization_token == expected_token { + return Ok(allow(&event.payload.method_arn)); + } + panic!("token is not valid"); +} + +fn allow(method_arn: &str) -> ApiGatewayCustomAuthorizerResponse { + let stmt = IamPolicyStatement { + action: vec!["execute-api:Invoke".to_string()], + resource: vec![method_arn.to_owned()], + effect: aws_lambda_events::iam::IamPolicyEffect::Allow, + condition: None, + }; + let policy = ApiGatewayCustomAuthorizerPolicy { + version: Some("2012-10-17".to_string()), + statement: vec![stmt], + }; + ApiGatewayCustomAuthorizerResponse { + principal_id: Some("user".to_owned()), + policy_document: policy, + context: json!({ "hello": "world" }), + usage_identifier_key: None, + } +} diff --git a/lambda-integration-tests-ci/src/helloworld.rs b/lambda-integration-tests-ci/src/helloworld.rs new file mode 100644 index 00000000..55e70a4d --- /dev/null +++ b/lambda-integration-tests-ci/src/helloworld.rs @@ -0,0 +1,34 @@ +use aws_lambda_events::{ + apigw::{ApiGatewayProxyRequest, ApiGatewayProxyResponse}, + http::HeaderMap, +}; +use lambda_runtime::{service_fn, Error, LambdaEvent}; +use tracing_subscriber::EnvFilter; + +#[tokio::main] +async fn main() -> Result<(), Error> { + tracing_subscriber::fmt() + .json() + .with_env_filter(EnvFilter::from_default_env()) + .with_target(false) + .with_current_span(false) + .with_span_list(false) + .without_time() + .init(); + let func = service_fn(func); + lambda_runtime::run(func).await?; + Ok(()) +} + +async fn func(_event: LambdaEvent) -> Result { + let mut headers = HeaderMap::new(); + headers.insert("content-type", "text/html".parse().unwrap()); + let resp = ApiGatewayProxyResponse { + status_code: 200, + multi_value_headers: headers.clone(), + is_base64_encoded: false, + body: Some("Hello world!".into()), + headers, + }; + Ok(resp) +} diff --git a/lambda-integration-tests-ci/template.yaml b/lambda-integration-tests-ci/template.yaml new file mode 100644 index 00000000..a5b93e72 --- /dev/null +++ b/lambda-integration-tests-ci/template.yaml @@ -0,0 +1,58 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: maxday-test + +Parameters: + SecretToken: + Type: String + +Globals: + Function: + Timeout: 3 + +Resources: + API: + Type: AWS::Serverless::Api + Properties: + StageName: integ-test + Auth: + DefaultAuthorizer: MyLambdaAuthorizer + Authorizers: + MyLambdaAuthorizer: + FunctionArn: !GetAtt AuthorizerFunction.Arn + HelloWorldFunction: + Type: AWS::Serverless::Function + Metadata: + BuildMethod: rust-cargolambda + BuildProperties: + Binary: helloworld + Properties: + CodeUri: ./ + Handler: bootstrap + Runtime: provided.al2023 + Events: + HelloWorld: + Type: Api + Properties: + RestApiId: !Ref API + Path: /hello + Method: get + + AuthorizerFunction: + Type: AWS::Serverless::Function + Metadata: + BuildMethod: rust-cargolambda + BuildProperties: + Binary: authorizer + Properties: + CodeUri: ./ + Handler: bootstrap + Runtime: provided.al2023 + Environment: + Variables: + SECRET_TOKEN: !Ref SecretToken + +Outputs: + HelloApiEndpoint: + Description: "API Gateway endpoint URL for HelloWorld" + Value: !Sub "https://${API}.execute-api.${AWS::Region}.amazonaws.com/integ-test/hello/" \ No newline at end of file diff --git a/lambda-integration-tests-ci/tests/integration_test.rs b/lambda-integration-tests-ci/tests/integration_test.rs new file mode 100644 index 00000000..557b8e0d --- /dev/null +++ b/lambda-integration-tests-ci/tests/integration_test.rs @@ -0,0 +1,12 @@ +#[test] +fn test_calling_lambda_should_return_200() { + let test_endpoint = std::env::var("TEST_ENDPOINT").expect("could not read TEST_ENDPOINT"); + let secret_token = std::env::var("SECRET_TOKEN").expect("could not read SECRET_TOKEN"); + let client = reqwest::blocking::Client::new(); + let res = client + .get(test_endpoint) + .header("Authorization", secret_token) + .send() + .expect("could not the request"); + assert_eq!(res.status(), 200); +} From 5675bb64c9fada0c292ac48f952dda1daad59dee Mon Sep 17 00:00:00 2001 From: Maxime David Date: Fri, 2 Aug 2024 16:13:02 +0000 Subject: [PATCH 2/7] feat: run integration tests on CI --- lambda-integration-tests-ci/Cargo.toml | 31 -- lambda-integration-tests-ci/template.yaml | 58 --- lambda-integration-tests/Cargo.toml | 31 +- lambda-integration-tests/python/main.py | 4 - .../samconfig.toml | 0 .../src/authorizer.rs | 0 .../src/bin/extension-fn.rs | 28 -- .../src/bin/extension-trait.rs | 88 ----- lambda-integration-tests/src/bin/http-fn.rs | 26 -- .../src/bin/http-trait.rs | 83 ----- .../src/bin/logs-trait.rs | 75 ---- .../src/bin/runtime-fn.rs | 36 -- .../src/bin/runtime-trait.rs | 92 ----- .../src/helloworld.rs | 0 lambda-integration-tests/template.yaml | 349 ++---------------- .../tests/integration_test.rs | 0 16 files changed, 61 insertions(+), 840 deletions(-) delete mode 100644 lambda-integration-tests-ci/Cargo.toml delete mode 100644 lambda-integration-tests-ci/template.yaml delete mode 100644 lambda-integration-tests/python/main.py rename {lambda-integration-tests-ci => lambda-integration-tests}/samconfig.toml (100%) rename {lambda-integration-tests-ci => lambda-integration-tests}/src/authorizer.rs (100%) delete mode 100644 lambda-integration-tests/src/bin/extension-fn.rs delete mode 100644 lambda-integration-tests/src/bin/extension-trait.rs delete mode 100644 lambda-integration-tests/src/bin/http-fn.rs delete mode 100644 lambda-integration-tests/src/bin/http-trait.rs delete mode 100644 lambda-integration-tests/src/bin/logs-trait.rs delete mode 100644 lambda-integration-tests/src/bin/runtime-fn.rs delete mode 100644 lambda-integration-tests/src/bin/runtime-trait.rs rename {lambda-integration-tests-ci => lambda-integration-tests}/src/helloworld.rs (100%) rename {lambda-integration-tests-ci => lambda-integration-tests}/tests/integration_test.rs (100%) diff --git a/lambda-integration-tests-ci/Cargo.toml b/lambda-integration-tests-ci/Cargo.toml deleted file mode 100644 index 9812288f..00000000 --- a/lambda-integration-tests-ci/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "aws_lambda_rust_integration_tests" -version = "0.1.0" -authors = ["Maxime David"] -edition = "2021" -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" - -[dependencies] -lambda_runtime = { path = "../lambda-runtime" } -aws_lambda_events = { path = "../lambda-events" } -serde_json = "1.0.121" -tokio = { version = "1", features = ["full"] } -tracing-subscriber = { version = "0.3", default-features = false, features = ["json"] } -serde = { version = "1.0.204", features = ["derive"] } - -[dev-dependencies] -reqwest = { version = "0.12.5", features = ["blocking"] } -openssl = { version = "0.10", features = ["vendored"] } - -[[bin]] -name = "helloworld" -path = "src/helloworld.rs" - -[[bin]] -name = "authorizer" -path = "src/authorizer.rs" diff --git a/lambda-integration-tests-ci/template.yaml b/lambda-integration-tests-ci/template.yaml deleted file mode 100644 index a5b93e72..00000000 --- a/lambda-integration-tests-ci/template.yaml +++ /dev/null @@ -1,58 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Transform: AWS::Serverless-2016-10-31 -Description: maxday-test - -Parameters: - SecretToken: - Type: String - -Globals: - Function: - Timeout: 3 - -Resources: - API: - Type: AWS::Serverless::Api - Properties: - StageName: integ-test - Auth: - DefaultAuthorizer: MyLambdaAuthorizer - Authorizers: - MyLambdaAuthorizer: - FunctionArn: !GetAtt AuthorizerFunction.Arn - HelloWorldFunction: - Type: AWS::Serverless::Function - Metadata: - BuildMethod: rust-cargolambda - BuildProperties: - Binary: helloworld - Properties: - CodeUri: ./ - Handler: bootstrap - Runtime: provided.al2023 - Events: - HelloWorld: - Type: Api - Properties: - RestApiId: !Ref API - Path: /hello - Method: get - - AuthorizerFunction: - Type: AWS::Serverless::Function - Metadata: - BuildMethod: rust-cargolambda - BuildProperties: - Binary: authorizer - Properties: - CodeUri: ./ - Handler: bootstrap - Runtime: provided.al2023 - Environment: - Variables: - SECRET_TOKEN: !Ref SecretToken - -Outputs: - HelloApiEndpoint: - Description: "API Gateway endpoint URL for HelloWorld" - Value: !Sub "https://${API}.execute-api.${AWS::Region}.amazonaws.com/integ-test/hello/" \ No newline at end of file diff --git a/lambda-integration-tests/Cargo.toml b/lambda-integration-tests/Cargo.toml index 1b0fc3ef..9812288f 100644 --- a/lambda-integration-tests/Cargo.toml +++ b/lambda-integration-tests/Cargo.toml @@ -1,8 +1,8 @@ [package] -name = "lambda_integration_tests" -version = "0.5.0" -authors = ["Nicolas Moutschen "] -edition = "2018" +name = "aws_lambda_rust_integration_tests" +version = "0.1.0" +authors = ["Maxime David"] +edition = "2021" description = "AWS Lambda Runtime integration tests" license = "Apache-2.0" repository = "https://github.com/awslabs/aws-lambda-rust-runtime" @@ -10,13 +10,22 @@ 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" } lambda_runtime = { path = "../lambda-runtime" } -lambda-extension = { path = "../lambda-extension" } -serde = { version = "1", features = ["derive"] } +aws_lambda_events = { path = "../lambda-events" } +serde_json = "1.0.121" tokio = { version = "1", features = ["full"] } -tracing = { version = "0.1", features = ["log"] } -tracing-subscriber = { version = "0.3", default-features = false, features = ["fmt"] } +tracing-subscriber = { version = "0.3", default-features = false, features = ["json"] } +serde = { version = "1.0.204", features = ["derive"] } + +[dev-dependencies] +reqwest = { version = "0.12.5", features = ["blocking"] } +openssl = { version = "0.10", features = ["vendored"] } + +[[bin]] +name = "helloworld" +path = "src/helloworld.rs" + +[[bin]] +name = "authorizer" +path = "src/authorizer.rs" diff --git a/lambda-integration-tests/python/main.py b/lambda-integration-tests/python/main.py deleted file mode 100644 index e7e2114b..00000000 --- a/lambda-integration-tests/python/main.py +++ /dev/null @@ -1,4 +0,0 @@ -def handler(event, context): - return { - "message": event["command"].upper() - } \ No newline at end of file diff --git a/lambda-integration-tests-ci/samconfig.toml b/lambda-integration-tests/samconfig.toml similarity index 100% rename from lambda-integration-tests-ci/samconfig.toml rename to lambda-integration-tests/samconfig.toml diff --git a/lambda-integration-tests-ci/src/authorizer.rs b/lambda-integration-tests/src/authorizer.rs similarity index 100% rename from lambda-integration-tests-ci/src/authorizer.rs rename to lambda-integration-tests/src/authorizer.rs diff --git a/lambda-integration-tests/src/bin/extension-fn.rs b/lambda-integration-tests/src/bin/extension-fn.rs deleted file mode 100644 index 5e9ec553..00000000 --- a/lambda-integration-tests/src/bin/extension-fn.rs +++ /dev/null @@ -1,28 +0,0 @@ -use lambda_extension::{service_fn, Error, LambdaEvent, NextEvent}; -use tracing::info; - -async fn my_extension(event: LambdaEvent) -> Result<(), Error> { - match event.next { - 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> { - // The runtime logging can be enabled here by initializing `tracing` with `tracing-subscriber` - // While `tracing` is used internally, `log` can be used as well if preferred. - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - lambda_extension::run(service_fn(my_extension)).await -} diff --git a/lambda-integration-tests/src/bin/extension-trait.rs b/lambda-integration-tests/src/bin/extension-trait.rs deleted file mode 100644 index e2c73fa3..00000000 --- a/lambda-integration-tests/src/bin/extension-trait.rs +++ /dev/null @@ -1,88 +0,0 @@ -use std::{ - future::{ready, Future}, - pin::Pin, - sync::atomic::{AtomicBool, Ordering}, -}; - -use lambda_extension::{Error, LambdaEvent, NextEvent, Service}; -use tracing::info; - -struct MyExtension { - invoke_count: usize, - ready: AtomicBool, -} - -impl Default for MyExtension { - fn default() -> Self { - Self { - invoke_count: usize::default(), - // New instances are not ready to be called until polled. - ready: false.into(), - } - } -} - -impl Clone for MyExtension { - fn clone(&self) -> Self { - Self { - invoke_count: self.invoke_count, - // Cloned instances may not be immediately ready to be called. - // https://docs.rs/tower/0.4.13/tower/trait.Service.html#be-careful-when-cloning-inner-services - ready: false.into(), - } - } -} - -impl Service for MyExtension { - type Error = Error; - type Future = Pin>>>; - type Response = (); - - fn poll_ready(&mut self, _cx: &mut core::task::Context<'_>) -> core::task::Poll> { - if self.ready.swap(true, Ordering::SeqCst) { - info!("[extension] Service was already ready"); - } else { - info!("[extension] Service is now ready"); - }; - - core::task::Poll::Ready(Ok(())) - } - - fn call(&mut self, event: LambdaEvent) -> Self::Future { - match event.next { - 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); - } - } - - // After being called once, the service is no longer ready until polled again. - if self.ready.swap(false, Ordering::SeqCst) { - info!("[extension] The service is ready"); - } else { - // https://docs.rs/tower/latest/tower/trait.Service.html#backpressure - // https://docs.rs/tower/latest/tower/trait.Service.html#be-careful-when-cloning-inner-services - // > Services are permitted to panic if `call` is invoked without obtaining - // > `Poll::Ready(Ok(()))` from `poll_ready`. - panic!("[extension] The service is not ready; `.poll_ready()` must be called first"); - } - - Box::pin(ready(Ok(()))) - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - // The runtime logging can be enabled here by initializing `tracing` with `tracing-subscriber` - // While `tracing` is used internally, `log` can be used as well if preferred. - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - lambda_extension::run(MyExtension::default()).await -} diff --git a/lambda-integration-tests/src/bin/http-fn.rs b/lambda-integration-tests/src/bin/http-fn.rs deleted file mode 100644 index 8107f423..00000000 --- a/lambda-integration-tests/src/bin/http-fn.rs +++ /dev/null @@ -1,26 +0,0 @@ -use lambda_http::{ext::RequestExt, service_fn, Body, Error, IntoResponse, Request, Response}; -use tracing::info; - -async fn handler(event: Request) -> Result { - let _context = event.lambda_context(); - info!("[http-fn] Received event {} {}", event.method(), event.uri().path()); - - Ok(Response::builder() - .status(200) - .body(Body::from("Hello, world!")) - .unwrap()) -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - // The runtime logging can be enabled here by initializing `tracing` with `tracing-subscriber` - // While `tracing` is used internally, `log` can be used as well if preferred. - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - let handler = service_fn(handler); - lambda_http::run(handler).await -} diff --git a/lambda-integration-tests/src/bin/http-trait.rs b/lambda-integration-tests/src/bin/http-trait.rs deleted file mode 100644 index d8e6f74f..00000000 --- a/lambda-integration-tests/src/bin/http-trait.rs +++ /dev/null @@ -1,83 +0,0 @@ -use std::{ - future::{ready, Future}, - pin::Pin, - sync::atomic::{AtomicBool, Ordering}, -}; - -use lambda_http::{ext::RequestExt, Body, Error, Request, Response, Service}; -use tracing::info; - -struct MyHandler { - invoke_count: usize, - ready: AtomicBool, -} - -impl Default for MyHandler { - fn default() -> Self { - Self { - invoke_count: usize::default(), - // New instances are not ready to be called until polled. - ready: false.into(), - } - } -} - -impl Clone for MyHandler { - fn clone(&self) -> Self { - Self { - invoke_count: self.invoke_count, - // Cloned instances may not be immediately ready to be called. - // https://docs.rs/tower/0.4.13/tower/trait.Service.html#be-careful-when-cloning-inner-services - ready: false.into(), - } - } -} - -impl Service for MyHandler { - type Error = Error; - type Future = Pin> + Send>>; - type Response = Response; - - fn poll_ready(&mut self, _cx: &mut core::task::Context<'_>) -> core::task::Poll> { - if self.ready.swap(true, Ordering::SeqCst) { - info!("[http-trait] Service was already ready"); - } else { - info!("[http-trait] Service is now ready"); - }; - - core::task::Poll::Ready(Ok(())) - } - - fn call(&mut self, request: Request) -> Self::Future { - self.invoke_count += 1; - info!("[http-trait] Received event {}: {:?}", self.invoke_count, request); - info!("[http-trait] Lambda context: {:?}", request.lambda_context()); - - // After being called once, the service is no longer ready until polled again. - if self.ready.swap(false, Ordering::SeqCst) { - info!("[http-trait] The service is ready"); - } else { - // https://docs.rs/tower/latest/tower/trait.Service.html#backpressure - // https://docs.rs/tower/latest/tower/trait.Service.html#be-careful-when-cloning-inner-services - // > Services are permitted to panic if `call` is invoked without obtaining - // > `Poll::Ready(Ok(()))` from `poll_ready`. - panic!("[http-trait] The service is not ready; `.poll_ready()` must be called first"); - } - - Box::pin(ready(Ok(Response::builder() - .status(200) - .body(Body::from("Hello, World!")) - .unwrap()))) - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - lambda_http::run(MyHandler::default()).await -} diff --git a/lambda-integration-tests/src/bin/logs-trait.rs b/lambda-integration-tests/src/bin/logs-trait.rs deleted file mode 100644 index b474bc8d..00000000 --- a/lambda-integration-tests/src/bin/logs-trait.rs +++ /dev/null @@ -1,75 +0,0 @@ -use lambda_extension::{Error, Extension, LambdaLog, LambdaLogRecord, Service, SharedService}; -use std::{ - future::{ready, Future}, - pin::Pin, - sync::{ - atomic::{AtomicUsize, Ordering::SeqCst}, - Arc, - }, - task::Poll, -}; -use tracing::info; - -/// Custom log processor that increments a counter for each log record. -/// -/// This is a simple example of a custom log processor that can be used to -/// count the number of log records that are processed. -/// -/// This needs to derive Clone (and store the counter in an Arc) as the runtime -/// could need multiple `Service`s to process the logs. -#[derive(Clone, Default)] -struct MyLogsProcessor { - counter: Arc, -} - -impl MyLogsProcessor { - pub fn new() -> Self { - Self::default() - } -} - -type MyLogsFuture = Pin> + Send>>; - -/// Implementation of the actual log processor -/// -/// This receives a `Vec` whenever there are new log entries available. -impl Service> for MyLogsProcessor { - type Response = (); - type Error = Error; - type Future = MyLogsFuture; - - fn poll_ready(&mut self, _cx: &mut core::task::Context<'_>) -> core::task::Poll> { - Poll::Ready(Ok(())) - } - - fn call(&mut self, logs: Vec) -> Self::Future { - let counter = self.counter.fetch_add(1, SeqCst); - for log in logs { - match log.record { - LambdaLogRecord::Function(record) => { - info!("[logs] {} [function] {}: {}", log.time, counter, record.trim()) - } - LambdaLogRecord::Extension(record) => { - info!("[logs] {} [extension] {}: {}", log.time, counter, record.trim()) - } - _ => (), - } - } - - Box::pin(ready(Ok(()))) - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - let logs_processor = SharedService::new(MyLogsProcessor::new()); - Extension::new().with_logs_processor(logs_processor).run().await?; - - Ok(()) -} diff --git a/lambda-integration-tests/src/bin/runtime-fn.rs b/lambda-integration-tests/src/bin/runtime-fn.rs deleted file mode 100644 index d16717aa..00000000 --- a/lambda-integration-tests/src/bin/runtime-fn.rs +++ /dev/null @@ -1,36 +0,0 @@ -use lambda_runtime::{service_fn, Error, LambdaEvent}; -use serde::{Deserialize, Serialize}; -use tracing::info; - -#[derive(Deserialize, Debug)] -struct Request { - command: String, -} - -#[derive(Serialize, Debug)] -struct Response { - message: String, -} - -async fn handler(event: LambdaEvent) -> Result { - info!("[handler-fn] Received event: {:?}", event); - - let (event, _) = event.into_parts(); - - Ok(Response { - message: event.command.to_uppercase(), - }) -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - // The runtime logging can be enabled here by initializing `tracing` with `tracing-subscriber` - // While `tracing` is used internally, `log` can be used as well if preferred. - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - lambda_runtime::run(service_fn(handler)).await -} diff --git a/lambda-integration-tests/src/bin/runtime-trait.rs b/lambda-integration-tests/src/bin/runtime-trait.rs deleted file mode 100644 index 0bf31e43..00000000 --- a/lambda-integration-tests/src/bin/runtime-trait.rs +++ /dev/null @@ -1,92 +0,0 @@ -use std::{ - future::{ready, Future}, - pin::Pin, - sync::atomic::{AtomicBool, Ordering}, -}; - -use lambda_runtime::{Error, LambdaEvent, Service}; -use serde::{Deserialize, Serialize}; -use tracing::info; - -#[derive(Deserialize, Debug)] -struct Request { - command: String, -} - -#[derive(Serialize, Debug)] -struct Response { - message: String, -} - -struct MyHandler { - invoke_count: usize, - ready: AtomicBool, -} - -impl Default for MyHandler { - fn default() -> Self { - Self { - invoke_count: usize::default(), - // New instances are not ready to be called until polled. - ready: false.into(), - } - } -} - -impl Clone for MyHandler { - fn clone(&self) -> Self { - Self { - invoke_count: self.invoke_count, - // Cloned instances may not be immediately ready to be called. - // https://docs.rs/tower/0.4.13/tower/trait.Service.html#be-careful-when-cloning-inner-services - ready: false.into(), - } - } -} - -impl Service> for MyHandler { - type Error = Error; - type Future = Pin>>>; - type Response = Response; - - fn poll_ready(&mut self, _cx: &mut core::task::Context<'_>) -> core::task::Poll> { - if self.ready.swap(true, Ordering::SeqCst) { - info!("[runtime-trait] Service was already ready"); - } else { - info!("[runtime-trait] Service is now ready"); - }; - - core::task::Poll::Ready(Ok(())) - } - - fn call(&mut self, request: LambdaEvent) -> Self::Future { - self.invoke_count += 1; - info!("[runtime-trait] Received event {}: {:?}", self.invoke_count, request); - - // After being called once, the service is no longer ready until polled again. - if self.ready.swap(false, Ordering::SeqCst) { - info!("[runtime-trait] The service is ready"); - } else { - // https://docs.rs/tower/latest/tower/trait.Service.html#backpressure - // https://docs.rs/tower/latest/tower/trait.Service.html#be-careful-when-cloning-inner-services - // > Services are permitted to panic if `call` is invoked without obtaining - // > `Poll::Ready(Ok(()))` from `poll_ready`. - panic!("[runtime-trait] The service is not ready; `.poll_ready()` must be called first"); - } - - Box::pin(ready(Ok(Response { - message: request.payload.command.to_uppercase(), - }))) - } -} - -#[tokio::main] -async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .with_max_level(tracing::Level::INFO) - // disabling time is handy because CloudWatch will add the ingestion time. - .without_time() - .init(); - - lambda_runtime::run(MyHandler::default()).await -} diff --git a/lambda-integration-tests-ci/src/helloworld.rs b/lambda-integration-tests/src/helloworld.rs similarity index 100% rename from lambda-integration-tests-ci/src/helloworld.rs rename to lambda-integration-tests/src/helloworld.rs diff --git a/lambda-integration-tests/template.yaml b/lambda-integration-tests/template.yaml index d148c264..a5b93e72 100644 --- a/lambda-integration-tests/template.yaml +++ b/lambda-integration-tests/template.yaml @@ -1,325 +1,58 @@ AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 +Description: maxday-test + +Parameters: + SecretToken: + Type: String Globals: Function: - MemorySize: 128 - Handler: bootstrap - Timeout: 5 + Timeout: 3 Resources: - # Rust function using runtime_fn running on AL2023 - RuntimeFnAl2023: - Type: AWS::Serverless::Function - Properties: - CodeUri: ../build/runtime-fn/ - Runtime: provided.al2023 - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait - - # Rust function using runtime_fn running on AL2 - RuntimeFnAl2: - Type: AWS::Serverless::Function - Properties: - CodeUri: ../build/runtime-fn/ - Runtime: provided.al2 - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait - - # Rust function using runtime_fn running on AL1 - RuntimeFn: - Type: AWS::Serverless::Function - Properties: - CodeUri: ../build/runtime-fn/ - Runtime: provided - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait - - # Rust function using a Service implementation running on AL2023 - RuntimeTraitAl2023: - Type: AWS::Serverless::Function - Properties: - CodeUri: ../build/runtime-trait/ - Runtime: provided.al2023 - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait - - # Rust function using a Service implementation running on AL2 - RuntimeTraitAl2: - Type: AWS::Serverless::Function - Properties: - CodeUri: ../build/runtime-trait/ - Runtime: provided.al2 - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait - - # Rust function using a Service implementation running on AL1 - RuntimeTrait: - Type: AWS::Serverless::Function - Properties: - CodeUri: ../build/runtime-trait/ - Runtime: provided - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait - - # Rust function using lambda_http::service_fn running on AL2023 - HttpFnAl2023: - Type: AWS::Serverless::Function - Properties: - CodeUri: ../build/http-fn/ + API: + Type: AWS::Serverless::Api + Properties: + StageName: integ-test + Auth: + DefaultAuthorizer: MyLambdaAuthorizer + Authorizers: + MyLambdaAuthorizer: + FunctionArn: !GetAtt AuthorizerFunction.Arn + HelloWorldFunction: + Type: AWS::Serverless::Function + Metadata: + BuildMethod: rust-cargolambda + BuildProperties: + Binary: helloworld + Properties: + CodeUri: ./ + Handler: bootstrap Runtime: provided.al2023 Events: - ApiGet: + HelloWorld: Type: Api Properties: - Method: GET - Path: /al2/get - ApiPost: - Type: Api - Properties: - Method: POST - Path: /al2/post - ApiV2Get: - Type: HttpApi - Properties: - Method: GET - Path: /al2/get - ApiV2Post: - Type: HttpApi - Properties: - Method: POST - Path: /al2/post - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait + RestApiId: !Ref API + Path: /hello + Method: get - # Rust function using lambda_http::service_fn running on AL2 - HttpFnAl2: - Type: AWS::Serverless::Function - Properties: - CodeUri: ../build/http-fn/ - Runtime: provided.al2 - Events: - ApiGet: - Type: Api - Properties: - Method: GET - Path: /al2/get - ApiPost: - Type: Api - Properties: - Method: POST - Path: /al2/post - ApiV2Get: - Type: HttpApi - Properties: - Method: GET - Path: /al2/get - ApiV2Post: - Type: HttpApi - Properties: - Method: POST - Path: /al2/post - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait - - # Rust function using lambda_http with Service running on AL2023 - HttpTraitAl2023: + AuthorizerFunction: Type: AWS::Serverless::Function + Metadata: + BuildMethod: rust-cargolambda + BuildProperties: + Binary: authorizer Properties: - CodeUri: ../build/http-trait/ + CodeUri: ./ + Handler: bootstrap Runtime: provided.al2023 - Events: - ApiGet: - Type: Api - Properties: - Method: GET - Path: /al2-trait/get - ApiPost: - Type: Api - Properties: - Method: POST - Path: /al2-trait/post - ApiV2Get: - Type: HttpApi - Properties: - Method: GET - Path: /al2-trait/get - ApiV2Post: - Type: HttpApi - Properties: - Method: POST - Path: /al2-trait/post - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait - - # Rust function using lambda_http with Service running on AL2 - HttpTraitAl2: - Type: AWS::Serverless::Function - Properties: - CodeUri: ../build/http-trait/ - Runtime: provided.al2 - Events: - ApiGet: - Type: Api - Properties: - Method: GET - Path: /al2-trait/get - ApiPost: - Type: Api - Properties: - Method: POST - Path: /al2-trait/post - ApiV2Get: - Type: HttpApi - Properties: - Method: GET - Path: /al2-trait/get - ApiV2Post: - Type: HttpApi - Properties: - Method: POST - Path: /al2-trait/post - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait - - # Rust function using lambda_http::service_fn running on AL1 - HttpFn: - Type: AWS::Serverless::Function - Properties: - CodeUri: ../build/http-fn/ - Runtime: provided - Events: - ApiGet: - Type: Api - Properties: - Method: GET - Path: /get - ApiPost: - Type: Api - Properties: - Method: POST - Path: /post - ApiV2Get: - Type: HttpApi - Properties: - Method: GET - Path: /get - ApiV2Post: - Type: HttpApi - Properties: - Method: POST - Path: /post - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait - - # Rust function using lambda_http with Service running on AL1 - HttpTrait: - Type: AWS::Serverless::Function - Properties: - CodeUri: ../build/http-trait/ - Runtime: provided - Events: - ApiGet: - Type: Api - Properties: - Method: GET - Path: /trait/get - ApiPost: - Type: Api - Properties: - Method: POST - Path: /trait/post - ApiV2Get: - Type: HttpApi - Properties: - Method: GET - Path: /trait/get - ApiV2Post: - Type: HttpApi - Properties: - Method: POST - Path: /trait/post - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait - - # Python function running on AL2 - PythonAl2: - Type: AWS::Serverless::Function - Properties: - CodeUri: ./python/ - Handler: main.handler - Runtime: python3.9 - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait - - # Python function running on AL1 - Python: - Type: AWS::Serverless::Function - Properties: - CodeUri: ./python/ - Handler: main.handler - Runtime: python3.7 - Layers: - - !Ref LogsTrait - - !Ref ExtensionFn - - !Ref ExtensionTrait - - LogsTrait: - Type: AWS::Serverless::LayerVersion - Properties: - ContentUri: ../build/logs-trait/ - - ExtensionFn: - Type: AWS::Serverless::LayerVersion - Properties: - ContentUri: ../build/extension-fn/ - - ExtensionTrait: - Type: AWS::Serverless::LayerVersion - Properties: - ContentUri: ../build/extension-trait/ + Environment: + Variables: + SECRET_TOKEN: !Ref SecretToken Outputs: - RuntimeFnAl2: - Value: !GetAtt RuntimeFnAl2.Arn - RuntimeFn: - Value: !GetAtt RuntimeFn.Arn - RuntimeTraitAl2: - Value: !GetAtt RuntimeTraitAl2.Arn - RuntimeTrait: - Value: !GetAtt RuntimeTrait.Arn - PythonAl2: - Value: !GetAtt PythonAl2.Arn - Python: - Value: !GetAtt Python.Arn - - RestApiUrl: - Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod" - HttpApiUrl: - Value: !Sub "https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com" \ No newline at end of file + HelloApiEndpoint: + Description: "API Gateway endpoint URL for HelloWorld" + Value: !Sub "https://${API}.execute-api.${AWS::Region}.amazonaws.com/integ-test/hello/" \ No newline at end of file diff --git a/lambda-integration-tests-ci/tests/integration_test.rs b/lambda-integration-tests/tests/integration_test.rs similarity index 100% rename from lambda-integration-tests-ci/tests/integration_test.rs rename to lambda-integration-tests/tests/integration_test.rs From 3fad9b30da3879c96aa981a2d0e5f1868bc8c727 Mon Sep 17 00:00:00 2001 From: Maxime David Date: Fri, 2 Aug 2024 16:16:25 +0000 Subject: [PATCH 3/7] feat: run integration tests on CI --- lambda-integration-tests/Cargo.toml | 1 - lambda-integration-tests/src/authorizer.rs | 12 ++---------- lambda-integration-tests/src/helloworld.rs | 12 ++---------- 3 files changed, 4 insertions(+), 21 deletions(-) diff --git a/lambda-integration-tests/Cargo.toml b/lambda-integration-tests/Cargo.toml index 9812288f..ee44a969 100644 --- a/lambda-integration-tests/Cargo.toml +++ b/lambda-integration-tests/Cargo.toml @@ -15,7 +15,6 @@ lambda_runtime = { path = "../lambda-runtime" } aws_lambda_events = { path = "../lambda-events" } serde_json = "1.0.121" tokio = { version = "1", features = ["full"] } -tracing-subscriber = { version = "0.3", default-features = false, features = ["json"] } serde = { version = "1.0.204", features = ["derive"] } [dev-dependencies] diff --git a/lambda-integration-tests/src/authorizer.rs b/lambda-integration-tests/src/authorizer.rs index 7741216c..41ddd2d8 100644 --- a/lambda-integration-tests/src/authorizer.rs +++ b/lambda-integration-tests/src/authorizer.rs @@ -4,10 +4,9 @@ use aws_lambda_events::{ apigw::{ApiGatewayCustomAuthorizerPolicy, ApiGatewayCustomAuthorizerResponse}, event::iam::IamPolicyStatement, }; -use lambda_runtime::{service_fn, Error, LambdaEvent}; +use lambda_runtime::{service_fn, tracing, Error, LambdaEvent}; use serde::Deserialize; use serde_json::json; -use tracing_subscriber::EnvFilter; #[derive(Deserialize)] #[serde(rename_all = "camelCase")] @@ -18,14 +17,7 @@ struct APIGatewayCustomAuthorizerRequest { #[tokio::main] async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .json() - .with_env_filter(EnvFilter::from_default_env()) - .with_target(false) - .with_current_span(false) - .with_span_list(false) - .without_time() - .init(); + tracing::init_default_subscriber(); let func = service_fn(func); lambda_runtime::run(func).await?; Ok(()) diff --git a/lambda-integration-tests/src/helloworld.rs b/lambda-integration-tests/src/helloworld.rs index 55e70a4d..9989da43 100644 --- a/lambda-integration-tests/src/helloworld.rs +++ b/lambda-integration-tests/src/helloworld.rs @@ -2,19 +2,11 @@ use aws_lambda_events::{ apigw::{ApiGatewayProxyRequest, ApiGatewayProxyResponse}, http::HeaderMap, }; -use lambda_runtime::{service_fn, Error, LambdaEvent}; -use tracing_subscriber::EnvFilter; +use lambda_runtime::{service_fn, tracing, Error, LambdaEvent}; #[tokio::main] async fn main() -> Result<(), Error> { - tracing_subscriber::fmt() - .json() - .with_env_filter(EnvFilter::from_default_env()) - .with_target(false) - .with_current_span(false) - .with_span_list(false) - .without_time() - .init(); + tracing::init_default_subscriber(); let func = service_fn(func); lambda_runtime::run(func).await?; Ok(()) From 737844023e2f8c5f228f8058230555b05119f709 Mon Sep 17 00:00:00 2001 From: Maxime David Date: Fri, 2 Aug 2024 16:18:06 +0000 Subject: [PATCH 4/7] feat: run integration tests on CI --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 00a2a1a5..c55f0e60 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,6 @@ resolver = "2" members = [ "lambda-http", "lambda-integration-tests", - "lambda-integration-tests-ci", "lambda-runtime-api-client", "lambda-runtime", "lambda-extension", From 32a708f62047084ae4ec378f1e7d49fcfe2dfe6f Mon Sep 17 00:00:00 2001 From: Maxime David Date: Fri, 2 Aug 2024 16:29:08 +0000 Subject: [PATCH 5/7] feat: run integration tests on CI --- .github/workflows/run-integration-test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/run-integration-test.yml b/.github/workflows/run-integration-test.yml index 53f52e74..b8546ed2 100644 --- a/.github/workflows/run-integration-test.yml +++ b/.github/workflows/run-integration-test.yml @@ -34,15 +34,15 @@ jobs: role-session-name: ${{ secrets.ROLE_SESSION_NAME }} aws-region: ${{ secrets.AWS_REGION }} - name: build stack - run: cd lambda-integration-tests-ci && sam build --beta-features + run: cd lambda-integration-tests && sam build --beta-features - name: validate stack - run: cd lambda-integration-tests-ci && sam validate --lint + run: cd lambda-integration-tests && sam validate --lint - name: deploy stack id: deploy_stack env: AWS_REGION: ${{ secrets.AWS_REGION }} run: | - cd lambda-integration-tests-ci + cd lambda-integration-tests stackName="aws-lambda-rust-integ-test-$GITHUB_RUN_ID" echo "STACK_NAME=$stackName" >> "$GITHUB_OUTPUT" echo "Stack name = $stackName" @@ -53,7 +53,7 @@ jobs: env: SECRET_TOKEN: ${{ secrets.SECRET_TOKEN }} TEST_ENDPOINT: ${{ steps.deploy_stack.outputs.TEST_ENDPOINT }} - run: cd lambda-integration-tests-ci && cargo test + run: cd lambda-integration-tests && cargo test - name: cleanup if: always() env: From 92846c8ecfdf1db389eb05d346f9b7c4fdfcc71e Mon Sep 17 00:00:00 2001 From: Maxime David Date: Mon, 12 Aug 2024 10:35:52 +0000 Subject: [PATCH 6/7] feat: run integration tests on CI --- lambda-integration-tests/samconfig.toml | 6 +----- lambda-integration-tests/template.yaml | 4 ++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lambda-integration-tests/samconfig.toml b/lambda-integration-tests/samconfig.toml index 8f88b383..0212b62a 100644 --- a/lambda-integration-tests/samconfig.toml +++ b/lambda-integration-tests/samconfig.toml @@ -11,11 +11,7 @@ lint = true [default.deploy.parameters] capabilities = "CAPABILITY_IAM" confirm_changeset = true -resolve_s3 = true -s3_prefix = "aws-lambda-rust-integration-test" - -[default.package.parameters] -resolve_s3 = true +s3_bucket = "aws-lambda-rust-runtime-integration-testing" [default.sync.parameters] watch = true diff --git a/lambda-integration-tests/template.yaml b/lambda-integration-tests/template.yaml index a5b93e72..1aa69fc8 100644 --- a/lambda-integration-tests/template.yaml +++ b/lambda-integration-tests/template.yaml @@ -3,6 +3,8 @@ Transform: AWS::Serverless-2016-10-31 Description: maxday-test Parameters: + LambdaRole: + Type: String SecretToken: Type: String @@ -30,6 +32,7 @@ Resources: CodeUri: ./ Handler: bootstrap Runtime: provided.al2023 + Role: !Ref LambdaRole Events: HelloWorld: Type: Api @@ -48,6 +51,7 @@ Resources: CodeUri: ./ Handler: bootstrap Runtime: provided.al2023 + Role: !Ref LambdaRole Environment: Variables: SECRET_TOKEN: !Ref SecretToken From 10b363399c0eded15dcfd6ae98f9cd92964c1d03 Mon Sep 17 00:00:00 2001 From: Maxime David Date: Mon, 12 Aug 2024 19:42:05 +0000 Subject: [PATCH 7/7] feat: run integration tests on CI --- .github/workflows/run-integration-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/run-integration-test.yml b/.github/workflows/run-integration-test.yml index b8546ed2..f1e30d09 100644 --- a/.github/workflows/run-integration-test.yml +++ b/.github/workflows/run-integration-test.yml @@ -46,7 +46,7 @@ jobs: stackName="aws-lambda-rust-integ-test-$GITHUB_RUN_ID" echo "STACK_NAME=$stackName" >> "$GITHUB_OUTPUT" echo "Stack name = $stackName" - sam deploy --stack-name "${stackName}" --parameter-overrides "ParameterKey=SecretToken,ParameterValue=${{ secrets.SECRET_TOKEN }}" --no-confirm-changeset --no-progressbar > disable_output + sam deploy --stack-name "${stackName}" --parameter-overrides "ParameterKey=SecretToken,ParameterValue=${{ secrets.SECRET_TOKEN }}" "ParameterKey=LambdaRole,ParameterValue=${{ secrets.AWS_LAMBDA_ROLE }}" --no-confirm-changeset --no-progressbar > disable_output TEST_ENDPOINT=$(sam list stack-outputs --stack-name "${stackName}" --output json | jq -r '.[] | .OutputValue') echo "TEST_ENDPOINT=$TEST_ENDPOINT" >> "$GITHUB_OUTPUT" - name: run test