From 934d2547fd573ece89ccbdaad2161a7e4d46fd1e Mon Sep 17 00:00:00 2001 From: Marco Magdy Date: Thu, 16 Nov 2023 09:31:17 -0800 Subject: [PATCH 1/4] Use the Lambda executable as the bootstrap when glibc is not required (#191) * Use the Lambda executable as the bootstrap when glibc is not required * Fix integration tests --------- Co-authored-by: Marco Magdy --- packaging/packager | 13 ++----------- tests/resources/lambda_function.cpp | 9 +++------ 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/packaging/packager b/packaging/packager index 0c4e749..c050696 100755 --- a/packaging/packager +++ b/packaging/packager @@ -171,20 +171,11 @@ exec \$LAMBDA_TASK_ROOT/lib/$PKG_LD --library-path \$LAMBDA_TASK_ROOT/lib \$LAMB EOF ) -bootstrap_script_no_libc=$(cat < "$PKG_DIR/bootstrap" else - echo -e "$bootstrap_script_no_libc" > "$PKG_DIR/bootstrap" + cp "$PKG_BIN_PATH" "$PKG_DIR/bootstrap" fi chmod +x "$PKG_DIR/bootstrap" # some shenanigans to create the right layout in the zip file without extraneous directories diff --git a/tests/resources/lambda_function.cpp b/tests/resources/lambda_function.cpp index b0228d3..bf12fc0 100644 --- a/tests/resources/lambda_function.cpp +++ b/tests/resources/lambda_function.cpp @@ -41,12 +41,9 @@ int main(int argc, char* argv[]) handlers.emplace("binary_response", binary_response); handlers.emplace("crash_backtrace", crash_backtrace); - if (argc < 2) { - aws::logging::log_error("lambda_fun", "Missing handler argument. Exiting."); - return -1; - } - - auto it = handlers.find(argv[1]); + // Read the handler from the environment variable + const char* handler_name = std::getenv("_HANDLER"); + auto it = handlers.find(handler_name == nullptr ? "" : handler_name); if (it == handlers.end()) { aws::logging::log_error("lambda_fun", "Handler %s not found. Exiting.", argv[1]); return -2; From 074d122b34da828fca25a5050a9935dfe85c6c80 Mon Sep 17 00:00:00 2001 From: Christian Ulbrich Date: Tue, 29 Apr 2025 12:52:35 +0200 Subject: [PATCH 2/4] Bugfix/fix minor documentation issues (#203) * Fix docs for current AWS CLI and current AWS Lambda runtimes * provided has to be either provided.al2023 or provided.al2 * AWS CLI2 has changed the param format * add docs about building on arm64 * minor docs update * use proper JSON in example * add hint on how to update example Lambda --- README.md | 18 +++++++++++++----- examples/demo/main.cpp | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 74e60af..f702470 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ static invocation_response my_handler(invocation_request const& req) "error type here" /*error_type*/); } - return invocation_response::success("json payload here" /*payload*/, + return invocation_response::success("{\"message:\":\"I fail if body length is bigger than 42!\"}" /*payload*/, "application/json" /*MIME type*/); } @@ -130,13 +130,19 @@ And finally, create the Lambda function: ``` $ aws lambda create-function --function-name demo \ --role \ ---runtime provided --timeout 15 --memory-size 128 \ +--runtime provided.al2023 --timeout 15 --memory-size 128 \ --handler demo --zip-file fileb://demo.zip ``` +> **N.B.** If you are building on `arm64`, you have to explicitly add the param `--architectures arm64`, so that you are setting up the proper architecture on AWS to run your supplied Lambda function. And to invoke the function: ```bash -$ aws lambda invoke --function-name demo --payload '{"answer":42}' output.txt +$ aws lambda invoke --function-name demo --cli-binary-format raw-in-base64-out --payload '{"answer":42}' output.txt +``` + +You can update your supplied function: +```bash +$ aws lambda update-function-code --function-name demo --zip-file fileb://demo.zip ``` ## Using the C++ SDK for AWS with this runtime @@ -150,7 +156,7 @@ Any *fully* compliant C++11 compiler targeting GNU/Linux x86-64 should work. Ple - Use Clang v3.3 or above ## Packaging, ABI, GNU C Library, Oh My! -Lambda runs your code on some version of Amazon Linux. It would be a less than ideal customer experience if you are forced to build your application on that platform and that platform only. +Lambda runs your code on some version of Amazon Linux. It would be a less than ideal customer experience if you are forced to build your application on that platform and that platform only. However, the freedom to build on any linux distro brings a challenge. The GNU C Library ABI. There is no guarantee the platform used to build the Lambda function has the same GLIBC version as the one used by AWS Lambda. In fact, you might not even be using GNU's implementation. For example you could build a C++ Lambda function using musl libc. @@ -196,10 +202,12 @@ curl_easy_setopt(curl_handle, CURLOPT_CAINFO, "/etc/pki/tls/certs/ca-bundle.crt" ```bash $ aws lambda create-function --function-name demo \ --role \ - --runtime provided --timeout 15 --memory-size 128 \ + --runtime provided.al2023 --timeout 15 --memory-size 128 \ --handler demo --code "S3Bucket=mys3bucket,S3Key=demo.zip" ``` +> **N.B.** See hint above if you are building on `arm64`. + 1. **My code is crashing, how can I debug it?** - Starting with [v0.2.0](https://github.com/awslabs/aws-lambda-cpp/releases/tag/v0.2.0) you should see a stack-trace of the crash site in the logs (which are typically stored in CloudWatch). diff --git a/examples/demo/main.cpp b/examples/demo/main.cpp index 358efe0..5381311 100644 --- a/examples/demo/main.cpp +++ b/examples/demo/main.cpp @@ -9,7 +9,7 @@ static invocation_response my_handler(invocation_request const& req) "error type here" /*error_type*/); } - return invocation_response::success("json payload here" /*payload*/, + return invocation_response::success("{\"message:\":\"I fail if body length is bigger than 42!\"}" /*payload*/, "application/json" /*MIME type*/); } From 0e99247d90dbec53f68c4f7ffafab321e582e1d4 Mon Sep 17 00:00:00 2001 From: koki watanabe <56009584+math-hiyoko@users.noreply.github.com> Date: Tue, 29 Apr 2025 21:33:10 +0900 Subject: [PATCH 3/4] delete extra space (#198) --- src/runtime.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/runtime.cpp b/src/runtime.cpp index 2ae91e2..1013a19 100644 --- a/src/runtime.cpp +++ b/src/runtime.cpp @@ -527,7 +527,7 @@ invocation_response invocation_response::failure(std::string const& error_messag r.m_success = false; r.m_content_type = "application/json"; r.m_payload = R"({"errorMessage":")" + json_escape(error_message) + R"(","errorType":")" + json_escape(error_type) + - R"(", "stackTrace":[]})"; + R"(","stackTrace":[]})"; return r; } From d89a26aa818cf4c61fa442287e2ed548ae63c42f Mon Sep 17 00:00:00 2001 From: Maxime David Date: Wed, 30 Apr 2025 13:35:38 +0100 Subject: [PATCH 4/4] feat: add unit tests in ci (#201) --- .clang-tidy | 1 + .github/workflows/workflow.yml | 35 ++++----------- README.md | 17 ++++++++ tests/CMakeLists.txt | 53 ++++++++++++++++++----- tests/{ => integration}/main.cpp | 2 +- tests/{ => integration}/runtime_tests.cpp | 2 +- tests/{ => integration}/version_tests.cpp | 2 +- tests/unit/no_op_test.cpp | 6 +++ 8 files changed, 78 insertions(+), 40 deletions(-) rename tests/{ => integration}/main.cpp (97%) rename tests/{ => integration}/runtime_tests.cpp (99%) rename tests/{ => integration}/version_tests.cpp (93%) create mode 100644 tests/unit/no_op_test.cpp diff --git a/.clang-tidy b/.clang-tidy index d42139e..616d471 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,6 +4,7 @@ Checks: -modernize-use-trailing-return-type,-bugprone-easily-swappable-parameters,-readability-identifier-length' WarningsAsErrors: '*' HeaderFilterRegex: 'include/aws/.*\.h$' +ExcludeHeaderFilter: 'build/_deps/gtest-src.*' FormatStyle: 'none' CheckOptions: - key: modernize-pass-by-value.ValuesOnly diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 526b38a..7da0628 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -12,39 +12,24 @@ env: jobs: build: - # The CMake configure and build commands are platform agnostic and should work equally - # well on Windows or Mac. You can convert this to a matrix build if you need - # cross-platform coverage. - # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix - runs-on: ubuntu-latest + strategy: + matrix: + arch: [ubuntu-latest, ubuntu-24.04-arm] + runs-on: ${{ matrix.arch }} steps: - uses: actions/checkout@v3 - - name: Install Dependencies run: sudo apt-get update && sudo apt-get install -y clang-tidy libcurl4-openssl-dev - name: Configure CMake - # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. - # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_CXX_CLANG_TIDY=clang-tidy + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_CXX_CLANG_TIDY=clang-tidy -DENABLE_TESTS=ON - name: Build It - # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - build-on-arm-too: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - uses: uraimo/run-on-arch-action@v2 - with: - arch: aarch64 - distro: ubuntu20.04 - run: | - apt-get update && apt-get install -y cmake g++ clang-tidy libcurl4-openssl-dev - cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_CXX_CLANG_TIDY=clang-tidy - cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} + - name: Test It + run: cd build && make && ctest build-demo: runs-on: ubuntu-latest @@ -68,15 +53,11 @@ jobs: cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=~/lambda-install make make aws-lambda-package-demo - - + format: runs-on: ubuntu-latest - steps: - uses: actions/checkout@v3 - name: Check Formatting run: ./ci/codebuild/format-check.sh - - diff --git a/README.md b/README.md index f702470..0f58b28 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,23 @@ $ cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=~/lambda-install $ make && make install ``` +### Running Unit Tests Locally + +To run the unit tests locally, follow these steps to build: + +```bash +$ cd aws-lambda-cpp +$ mkdir build +$ cd build +$ cmake .. -DCMAKE_BUILD_TYPE=Debug -DENABLE_TESTS=ON +$ make +``` + +Run unit tests: +```bash +$ ctest +``` + To consume this library in a project that is also using CMake, you would do: ```cmake diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 06bf89a..7406096 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,17 +1,50 @@ +cmake_minimum_required(VERSION 3.11) project(aws-lambda-runtime-tests LANGUAGES CXX) -find_package(AWSSDK COMPONENTS lambda iam) +if(DEFINED ENV{GITHUB_ACTIONS}) + # Fetch Google Test for unit tests + include(FetchContent) + FetchContent_Declare(gtest + URL https://github.com/google/googletest/archive/v1.12.0.tar.gz + DOWNLOAD_EXTRACT_TIMESTAMP TRUE + ) + # Configure build of googletest + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) + set(INSTALL_GTEST OFF) + FetchContent_MakeAvailable(gtest) -add_executable(${PROJECT_NAME} - main.cpp - runtime_tests.cpp - version_tests.cpp - gtest/gtest-all.cc) + add_executable(unit_tests + unit/no_op_test.cpp) + target_link_libraries(unit_tests PRIVATE gtest_main aws-lambda-runtime) -target_link_libraries(${PROJECT_NAME} PRIVATE ${AWSSDK_LINK_LIBRARIES} aws-lambda-runtime) + # Register unit tests + include(GoogleTest) + gtest_discover_tests(unit_tests + PROPERTIES + LABELS "unit" + DISCOVERY_TIMEOUT 10) +else() + message(STATUS "Unit tests skipped: Not in GitHub Actions environment") +endif() -include(GoogleTest) -gtest_discover_tests(${PROJECT_NAME} EXTRA_ARGS "--aws_prefix=${TEST_RESOURCE_PREFIX}") # requires CMake 3.10 or later -add_subdirectory(resources) +find_package(AWSSDK COMPONENTS lambda iam QUIET) + +if(AWSSDK_FOUND) + add_executable(${PROJECT_NAME} + integration/main.cpp + integration/runtime_tests.cpp + integration/version_tests.cpp + gtest/gtest-all.cc) + + target_link_libraries(${PROJECT_NAME} PRIVATE ${AWSSDK_LINK_LIBRARIES} aws-lambda-runtime) + + include(GoogleTest) + gtest_discover_tests(${PROJECT_NAME} EXTRA_ARGS "--aws_prefix=${TEST_RESOURCE_PREFIX}") + + add_subdirectory(resources) +else() + message(STATUS "Integration tests skipped: AWS SDK not found or not in GitHub Actions environment") +endif() diff --git a/tests/main.cpp b/tests/integration/main.cpp similarity index 97% rename from tests/main.cpp rename to tests/integration/main.cpp index d7700e8..2a112d3 100644 --- a/tests/main.cpp +++ b/tests/integration/main.cpp @@ -1,6 +1,6 @@ #include #include -#include "gtest/gtest.h" +#include "../gtest/gtest.h" std::function()> get_console_logger_factory() { diff --git a/tests/runtime_tests.cpp b/tests/integration/runtime_tests.cpp similarity index 99% rename from tests/runtime_tests.cpp rename to tests/integration/runtime_tests.cpp index f118dab..843f815 100644 --- a/tests/runtime_tests.cpp +++ b/tests/integration/runtime_tests.cpp @@ -13,7 +13,7 @@ #include #include #include -#include "gtest/gtest.h" +#include "../gtest/gtest.h" #include #include #include diff --git a/tests/version_tests.cpp b/tests/integration/version_tests.cpp similarity index 93% rename from tests/version_tests.cpp rename to tests/integration/version_tests.cpp index 070b6dd..a0f546e 100644 --- a/tests/version_tests.cpp +++ b/tests/integration/version_tests.cpp @@ -1,5 +1,5 @@ #include -#include "gtest/gtest.h" +#include "../gtest/gtest.h" using namespace aws::lambda_runtime; diff --git a/tests/unit/no_op_test.cpp b/tests/unit/no_op_test.cpp new file mode 100644 index 0000000..c9a3b7d --- /dev/null +++ b/tests/unit/no_op_test.cpp @@ -0,0 +1,6 @@ +#include + +TEST(noop, dummy_test) +{ + ASSERT_EQ(0, 0); +}