Merge pull request #717 from sjanel/feature/access-log-config-flush-t… #2297
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [ main ] | |
| pull_request: | |
| branches: [ main ] | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| build-test: | |
| name: ubuntu x86_64 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { compiler: gcc-13, features: OFF, build: Debug } | |
| - { compiler: gcc-13, features: ON, build: Debug } | |
| - { compiler: clang-21, features: OFF, build: Debug } | |
| - { compiler: clang-21, features: ON, build: Debug } | |
| # Release gets a single smoke leg here: Debug+ASAN is where bugs actually get | |
| # caught (Release's -DNDEBUG strips assert()-based invariants), and Release is | |
| # already exercised independently by the arm/macos/windows/packaging jobs. | |
| - { compiler: gcc-13, features: ON, build: Release } | |
| runs-on: ubuntu-latest | |
| env: | |
| CMAKE_BUILD_TYPE: ${{ matrix.build }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Install Release dependencies | |
| if: ${{ matrix.build == 'Release' }} | |
| run: | | |
| sudo apt update | |
| sudo apt install -y libjsoncpp-dev uuid-dev | |
| - name: Install all dependencies with features | |
| if: ${{ matrix.features == 'ON' }} | |
| run: | | |
| sudo apt update | |
| sudo apt install -y libssl-dev libcurl4-openssl-dev libprotobuf-dev protobuf-compiler | |
| - name: Install GCC toolchain | |
| if: ${{ startsWith(matrix.compiler, 'gcc') }} | |
| run: | | |
| sudo apt update | |
| sudo apt install -y ${{ matrix.compiler }} | |
| - name: Install Clang/LLVM toolchain | |
| if: ${{ startsWith(matrix.compiler, 'clang') }} | |
| run: | | |
| wget --retry-connrefused --waitretry=5 --tries=5 https://apt.llvm.org/llvm.sh | |
| chmod +x llvm.sh | |
| compiler="${{ matrix.compiler }}" | |
| version="${compiler##*-}" | |
| echo "Detected clang version: $version" | |
| sudo ./llvm.sh "$version" | |
| sudo apt-get install -y "clang-tidy-$version" "lld-$version" | |
| - name: Derive CC/CXX environment | |
| run: | | |
| compiler="${{ matrix.compiler }}" | |
| echo "CC=$compiler" >> $GITHUB_ENV | |
| ver="${compiler##*-}" | |
| if [[ "$compiler" == gcc-* ]]; then | |
| echo "CXX=g++-$ver" >> $GITHUB_ENV | |
| else | |
| echo "CXX=clang++-$ver" >> $GITHUB_ENV | |
| fi | |
| echo "Derived compilers: CC=$compiler CXX set for version $ver" | |
| - name: Show compiler version | |
| run: | | |
| $CXX --version | |
| - name: Configure (CMake) | |
| run: | | |
| ./scripts/retry.sh cmake -S . -B build -G Ninja \ | |
| -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ | |
| -DAERONET_BUILD_TESTS=ON \ | |
| -DAERONET_ENABLE_TEST_HOOKS=ON \ | |
| -DAERONET_BUILD_EXAMPLES=OFF \ | |
| -DAERONET_BUILD_BENCHMARKS=OFF \ | |
| ${{ startsWith(matrix.compiler, 'clang') && '-DAERONET_ENABLE_CLANG_TIDY=OFF' || '' }} \ | |
| -DAERONET_ENABLE_ASAN=ON \ | |
| -DAERONET_ENABLE_ADDITIONAL_MEMORY_CHECKS=ON \ | |
| -DAERONET_ENABLE_ASYNC_HANDLERS=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_GLAZE=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_HTTP2=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_BROTLI=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_ZLIB=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_ZSTD=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_OPENSSL=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_OPENTELEMETRY=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_SPDLOG=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_WEBSOCKET=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_HTTP_CLIENT=${{ matrix.features }} | |
| - name: Build | |
| run: | | |
| cmake --build build --parallel | |
| - name: Run unit tests | |
| run: | | |
| ctest --test-dir build --repeat until-fail:3 --output-on-failure --timeout 60 -j | |
| - name: Summary | |
| run: | | |
| echo "Compiler: $CXX" >> $GITHUB_STEP_SUMMARY | |
| echo "features: ${{ matrix.features }}" >> $GITHUB_STEP_SUMMARY | |
| echo "Commit: $GITHUB_SHA" >> $GITHUB_STEP_SUMMARY | |
| echo "Tests executed:" >> $GITHUB_STEP_SUMMARY | |
| ctest --test-dir build -N | sed 's/^/ /' >> $GITHUB_STEP_SUMMARY | |
| - name: Install artifact (optional) | |
| run: | | |
| cmake --install build --prefix install || true | |
| - name: Upload install dir artifact | |
| if: success() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| # NOTE: Artifact names must be globally unique within a single workflow run. | |
| # The previous name omitted the build type, so Debug and Release matrix legs | |
| # attempted to create the same artifact name, yielding HTTP 409 Conflict. | |
| # Adding the build axis (and keeping compiler + features toggle) makes each | |
| # matrix combination distinct. If you ever re-run a failed job (run_attempt > 1) | |
| # and want full uniqueness across attempts, you could append `-ra${{ github.run_attempt }}`. | |
| name: aeronet-${{ matrix.compiler }}-features-${{ matrix.features }}-build-${{ matrix.build }} | |
| path: install | |
| if-no-files-found: ignore | |
| retention-days: 7 | |
| arm: | |
| name: ubuntu arm | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| features: [ON] | |
| build: [Debug, Release] | |
| runs-on: ubuntu-24.04-arm | |
| env: | |
| CMAKE_BUILD_TYPE: ${{ matrix.build }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Install Release dependencies | |
| if: ${{ matrix.build == 'Release' }} | |
| run: | | |
| sudo apt update | |
| sudo apt install -y libjsoncpp-dev uuid-dev | |
| - name: Install all dependencies with features | |
| if: ${{ matrix.features == 'ON' }} | |
| run: | | |
| sudo apt update | |
| sudo apt install -y libssl-dev libcurl4-openssl-dev libprotobuf-dev protobuf-compiler | |
| - name: Configure (CMake) | |
| run: | | |
| ./scripts/retry.sh cmake -S . -B build -G Ninja \ | |
| -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ | |
| -DAERONET_BUILD_TESTS=ON \ | |
| -DAERONET_ENABLE_TEST_HOOKS=ON \ | |
| -DAERONET_BUILD_EXAMPLES=OFF \ | |
| -DAERONET_BUILD_BENCHMARKS=OFF \ | |
| -DAERONET_ENABLE_ASAN=OFF \ | |
| -DAERONET_ENABLE_ADDITIONAL_MEMORY_CHECKS=OFF \ | |
| -DAERONET_ENABLE_ASYNC_HANDLERS=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_GLAZE=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_HTTP2=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_BROTLI=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_ZLIB=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_ZSTD=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_OPENTELEMETRY=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_OPENSSL=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_SPDLOG=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_WEBSOCKET=${{ matrix.features }} \ | |
| -DAERONET_ENABLE_HTTP_CLIENT=${{ matrix.features }} | |
| - name: Build | |
| run: | | |
| cmake --build build --parallel | |
| - name: Run unit tests | |
| run: | | |
| ctest --test-dir build --repeat until-fail:3 --output-on-failure --timeout 60 -j | |
| - name: Summary | |
| run: | | |
| echo "Compiler: $CXX" >> $GITHUB_STEP_SUMMARY | |
| echo "features: ${{ matrix.features }}" >> $GITHUB_STEP_SUMMARY | |
| echo "Commit: $GITHUB_SHA" >> $GITHUB_STEP_SUMMARY | |
| echo "Tests executed:" >> $GITHUB_STEP_SUMMARY | |
| ctest --test-dir build -N | sed 's/^/ /' >> $GITHUB_STEP_SUMMARY | |
| coverage: | |
| name: Coverage | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| env: | |
| BUILD_DIR: build-coverage | |
| CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Install coverage toolchain and dependencies (LLVM) | |
| run: | | |
| sudo apt update | |
| sudo apt install -y ninja-build build-essential python3-pip \ | |
| libjsoncpp-dev uuid-dev libssl-dev libcurl4-openssl-dev \ | |
| libprotobuf-dev protobuf-compiler wget | |
| # Install a recent LLVM toolchain (required for llvm-profdata/llvm-cov) | |
| wget --retry-connrefused --waitretry=5 --tries=5 https://apt.llvm.org/llvm.sh | |
| chmod +x llvm.sh | |
| sudo ./llvm.sh 21 | |
| sudo apt install -y clang-21 lldb-21 lld-21 llvm-21 llvm-21-tools | |
| - name: Configure with Clang source-based coverage flags | |
| run: | | |
| ./scripts/retry.sh cmake -S . -B ${BUILD_DIR} -G Ninja \ | |
| -DCMAKE_BUILD_TYPE=Debug \ | |
| -DAERONET_BUILD_TESTS=ON \ | |
| -DAERONET_ENABLE_TEST_HOOKS=ON \ | |
| -DAERONET_BUILD_EXAMPLES=OFF \ | |
| -DAERONET_BUILD_BENCHMARKS=OFF \ | |
| -DAERONET_ENABLE_ASAN=OFF \ | |
| -DAERONET_ENABLE_ADDITIONAL_MEMORY_CHECKS=OFF \ | |
| -DAERONET_ENABLE_CLANG_TIDY=OFF \ | |
| -DAERONET_ENABLE_GLAZE=ON \ | |
| -DAERONET_ENABLE_HTTP2=ON \ | |
| -DAERONET_ENABLE_BROTLI=ON \ | |
| -DAERONET_ENABLE_ZLIB=ON \ | |
| -DAERONET_ENABLE_ZSTD=ON \ | |
| -DAERONET_ENABLE_OPENTELEMETRY=ON \ | |
| -DAERONET_ENABLE_OPENSSL=ON \ | |
| -DAERONET_ENABLE_SPDLOG=ON \ | |
| -DAERONET_ENABLE_WEBSOCKET=ON \ | |
| -DAERONET_ENABLE_HTTP_CLIENT=ON \ | |
| -DAERONET_ENABLE_ASYNC_HANDLERS=ON \ | |
| -DCMAKE_C_COMPILER=clang-21 \ | |
| -DCMAKE_CXX_COMPILER=clang++-21 \ | |
| -DCMAKE_C_FLAGS="-DNDEBUG -fprofile-instr-generate -fcoverage-mapping -O0 -fno-omit-frame-pointer" \ | |
| -DCMAKE_CXX_FLAGS="-DNDEBUG -fprofile-instr-generate -fcoverage-mapping -O0 -fno-omit-frame-pointer" \ | |
| -DCMAKE_EXE_LINKER_FLAGS="-fprofile-instr-generate" | |
| - name: Build (coverage) | |
| run: cmake --build ${BUILD_DIR} --parallel | |
| - name: Run unit tests (coverage) | |
| run: | | |
| # Use LLVM profile file per-process. Pattern will create one .profraw per test process | |
| export LLVM_PROFILE_FILE="${{ github.workspace }}/coverage-%p.profraw" | |
| ctest --test-dir ${BUILD_DIR} --timeout 60 -j --output-on-failure | |
| - name: Merge profile data and generate coverage reports | |
| run: | | |
| set -euo pipefail | |
| cd ${BUILD_DIR} | |
| # Merge all profraw files into a single profdata | |
| llvm-profdata-21 merge -sparse ../coverage-*.profraw -o coverage.profdata | |
| # llvm-cov only reports source files for binaries passed on the command line, | |
| # so include every executed *_test binary from both tests/ and aeronet/. | |
| mapfile -t COVERAGE_BINARIES < <(find tests aeronet -type f -executable -name "*_test" | sort) | |
| if [[ ${#COVERAGE_BINARIES[@]} -eq 0 ]]; then | |
| echo "No coverage test binaries found" >&2 | |
| exit 1 | |
| fi | |
| MAIN_BINARY=${COVERAGE_BINARIES[0]} | |
| OBJECT_ARGS=() | |
| for ((i = 1; i < ${#COVERAGE_BINARIES[@]}; ++i)); do | |
| OBJECT_ARGS+=( -object "${COVERAGE_BINARIES[i]}" ) | |
| done | |
| # Ignore patterns: test files, test_support, CompilerId, _deps, and generated protobuf | |
| IGNORE='(_test\.cpp$|test_support|CompilerId|_deps|generated/|static-string-view-helpers.hpp|internal/city_impl.hpp|internal/flat_hash_map.hpp|internal/bytell_hash_map.hpp|internal/city.hpp)' | |
| # Generate lcov report for Codecov | |
| llvm-cov-21 export --format=lcov \ | |
| --instr-profile=coverage.profdata \ | |
| --ignore-filename-regex="$IGNORE" \ | |
| "$MAIN_BINARY" "${OBJECT_ARGS[@]}" > coverage.lcov | |
| # Generate HTML report | |
| llvm-cov-21 show --format=html \ | |
| --instr-profile=coverage.profdata \ | |
| --ignore-filename-regex="$IGNORE" \ | |
| --show-branches=count \ | |
| --output-dir=coverage-report \ | |
| "$MAIN_BINARY" "${OBJECT_ARGS[@]}" | |
| - name: Upload coverage to Codecov | |
| if: env.CODECOV_TOKEN != '' && github.actor != 'dependabot[bot]' && github.actor != 'renovate[bot]' | |
| uses: codecov/codecov-action@v7 | |
| with: | |
| token: ${{ env.CODECOV_TOKEN }} | |
| files: build-coverage/coverage.lcov | |
| flags: unittests | |
| name: aeronet-unit-tests | |
| fail_ci_if_error: true | |
| disable_search: true | |
| verbose: true | |
| - name: Skip Codecov upload (bot PR or missing token) | |
| if: env.CODECOV_TOKEN == '' || github.actor == 'dependabot[bot]' || github.actor == 'renovate[bot]' | |
| run: | | |
| echo "Codecov upload skipped for actor '${{ github.actor }}' or missing CODECOV_TOKEN." >> $GITHUB_STEP_SUMMARY | |
| echo "Coverage artifacts are still uploaded via actions/upload-artifact." >> $GITHUB_STEP_SUMMARY | |
| - name: Upload coverage artifact (HTML + lcov) | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: coverage-report | |
| path: | | |
| build-coverage/coverage.lcov | |
| build-coverage/coverage-report | |
| examples-smoke: | |
| name: Examples and Docs | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| compiler: [clang-21] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| env: | |
| BUILD_DIR: build-examples | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Install example dependencies | |
| run: | | |
| sudo apt update | |
| sudo apt install -y ninja-build libjsoncpp-dev uuid-dev \ | |
| libssl-dev libcurl4-openssl-dev libprotobuf-dev protobuf-compiler | |
| - name: Install GCC toolchain | |
| if: ${{ startsWith(matrix.compiler, 'gcc') }} | |
| run: | | |
| sudo apt update | |
| sudo apt install -y ${{ matrix.compiler }} | |
| - name: Install Clang/LLVM toolchain | |
| if: ${{ startsWith(matrix.compiler, 'clang') }} | |
| run: | | |
| wget --retry-connrefused --waitretry=5 --tries=5 https://apt.llvm.org/llvm.sh | |
| chmod +x llvm.sh | |
| compiler="${{ matrix.compiler }}" | |
| version="${compiler##*-}" | |
| echo "Detected clang version: $version" | |
| sudo ./llvm.sh "$version" | |
| sudo apt-get install -y "clang-tidy-$version" "lld-$version" | |
| - name: Derive CC/CXX environment | |
| run: | | |
| compiler="${{ matrix.compiler }}" | |
| echo "CC=$compiler" >> $GITHUB_ENV | |
| ver="${compiler##*-}" | |
| if [[ "$compiler" == gcc-* ]]; then | |
| echo "CXX=g++-$ver" >> $GITHUB_ENV | |
| else | |
| echo "CXX=clang++-$ver" >> $GITHUB_ENV | |
| fi | |
| echo "Derived compilers: CC=$compiler CXX set for version $ver" | |
| - name: Show compiler version | |
| run: | | |
| $CXX --version | |
| - name: Configure examples build | |
| run: | | |
| ./scripts/retry.sh cmake -S . -B ${BUILD_DIR} -G Ninja \ | |
| -DCMAKE_BUILD_TYPE=Debug \ | |
| -DAERONET_BUILD_EXAMPLES=ON \ | |
| -DAERONET_BUILD_TESTS=OFF \ | |
| -DAERONET_BUILD_BENCHMARKS=OFF \ | |
| -DAERONET_BUILD_MODULES=ON \ | |
| -DAERONET_ENABLE_ASAN=OFF \ | |
| -DAERONET_ENABLE_ASYNC_HANDLERS=ON \ | |
| -DAERONET_ENABLE_HTTP2=ON \ | |
| -DAERONET_ENABLE_BROTLI=ON \ | |
| -DAERONET_ENABLE_GLAZE=ON \ | |
| -DAERONET_ENABLE_ZLIB=ON \ | |
| -DAERONET_ENABLE_ZSTD=ON \ | |
| -DAERONET_ENABLE_OPENTELEMETRY=ON \ | |
| -DAERONET_ENABLE_OPENSSL=ON \ | |
| -DAERONET_ENABLE_SPDLOG=ON \ | |
| -DAERONET_ENABLE_WEBSOCKET=ON \ | |
| -DAERONET_ENABLE_HTTP_CLIENT=ON \ | |
| ${{ startsWith(matrix.compiler, 'clang') && '-DAERONET_ENABLE_CLANG_TIDY=OFF' || '' }} | |
| - name: Build examples | |
| run: | | |
| cmake --build ${BUILD_DIR} --parallel --target \ | |
| aeronet_client \ | |
| aeronet_server \ | |
| aeronet-async-handlers \ | |
| aeronet-http2 \ | |
| aeronet-server-minimal \ | |
| aeronet-multi \ | |
| aeronet-sendfile \ | |
| aeronet-static-example \ | |
| aeronet-static-file-http2 \ | |
| aeronet-tls-ktls \ | |
| aeronet-tls-session-tickets \ | |
| aeronet-websocket-echo | |
| - name: Generate TLS certificate for ktls example | |
| run: | | |
| mkdir -p ${BUILD_DIR}/certs | |
| openssl req -x509 -nodes -newkey rsa:2048 \ | |
| -keyout ${BUILD_DIR}/certs/server.key \ | |
| -out ${BUILD_DIR}/certs/server.crt \ | |
| -days 1 -subj "/CN=localhost" | |
| - name: Smoke test examples | |
| env: | |
| EXAMPLE_DIR: ${{ env.BUILD_DIR }}/examples | |
| run: | | |
| set -euo pipefail | |
| run_server_and_curl() { | |
| local label="$1"; shift | |
| local url="$1"; shift | |
| local curl_opts=() | |
| while [[ $# -gt 0 ]]; do | |
| if [[ "$1" == "--" ]]; then | |
| shift | |
| break | |
| fi | |
| curl_opts+=("$1") | |
| shift | |
| done | |
| local logfile="${BUILD_DIR}/${label}.log" | |
| local cmd=("$@") | |
| echo "::group::example-${label}" | |
| "${cmd[@]}" >"$logfile" 2>&1 & | |
| local pid=$! | |
| local success=0 | |
| for attempt in {1..30}; do | |
| if curl -fsS "${curl_opts[@]}" "$url" >/tmp/aeronet-${label}.out; then | |
| cat /tmp/aeronet-${label}.out | |
| success=1 | |
| break | |
| fi | |
| if ! kill -0 "$pid" 2>/dev/null; then | |
| echo "${label} exited before responding" >&2 | |
| break | |
| fi | |
| sleep 0.5 | |
| done | |
| kill -INT "$pid" 2>/dev/null || true | |
| wait "$pid" || true | |
| if [[ $success -ne 1 ]]; then | |
| echo "--- ${label} logs ---" >&2 | |
| cat "$logfile" >&2 || true | |
| exit 1 | |
| fi | |
| echo "Logs stored in $logfile" | |
| echo "::endgroup::" | |
| } | |
| run_server_and_curl async-handlers "http://127.0.0.1:18081/async" -- \ | |
| "${EXAMPLE_DIR}/aeronet-async-handlers" 18081 | |
| run_server_and_curl http2 "https://127.0.0.1:19443/" -k -- \ | |
| "${EXAMPLE_DIR}/aeronet-http2" ${BUILD_DIR}/certs/server.crt ${BUILD_DIR}/certs/server.key 19443 | |
| run_server_and_curl minimal "http://127.0.0.1:18082/hello" -- \ | |
| "${EXAMPLE_DIR}/aeronet-server-minimal" 18082 | |
| run_server_and_curl multi "http://127.0.0.1:18083/test" -- \ | |
| "${EXAMPLE_DIR}/aeronet-multi" 18083 2 | |
| tmp_file="${BUILD_DIR}/sendfile.txt" | |
| echo "Hello sendfile example" >"${tmp_file}" | |
| run_server_and_curl sendfile "http://127.0.0.1:18084/static" -- \ | |
| "${EXAMPLE_DIR}/aeronet-sendfile" 18084 "${tmp_file}" | |
| run_server_and_curl static "http://127.0.0.1:18085/" -- \ | |
| "${EXAMPLE_DIR}/aeronet-static-example" 18085 . | |
| run_server_and_curl static-file-http2 "https://127.0.0.1:18445/" -k -- \ | |
| "${EXAMPLE_DIR}/aeronet-static-file-http2" ${BUILD_DIR}/certs/server.crt ${BUILD_DIR}/certs/server.key 18445 --tls . | |
| run_server_and_curl tls "https://127.0.0.1:18443/" -k -- \ | |
| "${EXAMPLE_DIR}/aeronet-tls-ktls" ${BUILD_DIR}/certs/server.crt ${BUILD_DIR}/certs/server.key 18443 | |
| run_server_and_curl tls-session-tickets "https://127.0.0.1:18444/" -k -- \ | |
| "${EXAMPLE_DIR}/aeronet-tls-session-tickets" ${BUILD_DIR}/certs/server.crt ${BUILD_DIR}/certs/server.key 18444 | |
| run_server_and_curl websocket-echo "http://127.0.0.1:18086/" -- \ | |
| "${EXAMPLE_DIR}/aeronet-websocket-echo" 18086 | |
| - name: Verify markdown C/C++ examples (compile & link) | |
| run: | | |
| set -euo pipefail | |
| echo "Running markdown examples verifier against README.md, FEATURES.md, and the getting-started guide" | |
| NUM_PROC=$(nproc) | |
| # Use half the CPUs for parallelism, but at least 1 | |
| JOBS=$(( ((NUM_PROC + 1) / 2) )) | |
| scripts/verify-md-code.py -j ${JOBS} --link --build-dir ${BUILD_DIR} README.md docs/FEATURES.md docs/getting-started/first-server.md | |
| echo "Verifying MkDocs guide, protocol, operation, and configuration examples" | |
| scripts/verify-md-code.py -j ${JOBS} --link --build-dir ${BUILD_DIR} --include aeronet/main/include \ | |
| docs/guides/production-configuration.md \ | |
| docs/guides/routing.md \ | |
| docs/guides/middleware-and-responses.md \ | |
| docs/guides/bodies-streaming-and-files.md \ | |
| docs/protocols/tls-and-http2.md \ | |
| docs/protocols/client-and-jwt.md \ | |
| docs/operations/observability.md \ | |
| docs/reference/server-configuration.md \ | |
| docs/reference/client-configuration.md | |
| - name: Build MkDocs site | |
| run: | | |
| set -euo pipefail | |
| python3 -m pip install --disable-pip-version-check --quiet --requirement requirements-docs.txt | |
| python3 -m mkdocs build --strict --site-dir /tmp/aeronet-docs-site | |
| macos: | |
| name: macOS | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| build: [Debug, Release] | |
| runs-on: macos-26 | |
| env: | |
| CMAKE_BUILD_TYPE: ${{ matrix.build }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Verify preinstalled tools | |
| run: | | |
| command -v ninja | |
| ninja --version | |
| - name: Select Xcode 26.2 SDK | |
| run: | | |
| echo "DEVELOPER_DIR=/Applications/Xcode_26.2.app/Contents/Developer" >> $GITHUB_ENV | |
| echo "SDK_NAME=macosx26.2" >> $GITHUB_ENV | |
| - name: Set compiler environment | |
| run: | | |
| echo "CC=gcc-15" >> $GITHUB_ENV | |
| echo "CXX=g++-15" >> $GITHUB_ENV | |
| echo "SDKROOT=$(DEVELOPER_DIR=${DEVELOPER_DIR} xcrun --sdk ${SDK_NAME} --show-sdk-path)" >> $GITHUB_ENV | |
| - name: Show selected toolchain | |
| run: | | |
| xcodebuild -version | |
| xcrun --sdk ${SDK_NAME} --show-sdk-path | |
| $CC --version | |
| $CXX --version | |
| - name: Configure (CMake) | |
| run: | | |
| ./scripts/retry.sh cmake -S . -B build -G Ninja \ | |
| -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} \ | |
| -DCMAKE_C_COMPILER=${CC} \ | |
| -DCMAKE_CXX_COMPILER=${CXX} \ | |
| -DCMAKE_OSX_SYSROOT=${SDKROOT} \ | |
| -DAERONET_BUILD_TESTS=ON \ | |
| -DAERONET_ENABLE_TEST_HOOKS=ON \ | |
| -DAERONET_BUILD_EXAMPLES=ON \ | |
| -DAERONET_BUILD_BENCHMARKS=OFF \ | |
| -DAERONET_ENABLE_ASAN=OFF \ | |
| -DAERONET_ENABLE_ADDITIONAL_MEMORY_CHECKS=OFF \ | |
| -DAERONET_ENABLE_CLANG_TIDY=OFF \ | |
| -DAERONET_ENABLE_ASYNC_HANDLERS=ON \ | |
| -DAERONET_ENABLE_GLAZE=ON \ | |
| -DAERONET_ENABLE_HTTP2=ON \ | |
| -DAERONET_ENABLE_BROTLI=ON \ | |
| -DAERONET_ENABLE_ZLIB=ON \ | |
| -DAERONET_ENABLE_ZSTD=ON \ | |
| -DAERONET_ENABLE_OPENSSL=ON \ | |
| -DAERONET_ENABLE_OPENTELEMETRY=OFF \ | |
| -DAERONET_ENABLE_SPDLOG=ON \ | |
| -DAERONET_ENABLE_WEBSOCKET=ON \ | |
| -DAERONET_ENABLE_HTTP_CLIENT=ON | |
| - name: Build | |
| run: | | |
| cmake --build build --parallel | |
| - name: Run unit tests | |
| run: | | |
| ctest --test-dir build --repeat until-fail:3 --output-on-failure --timeout 60 -j | |
| - name: Summary | |
| run: | | |
| echo "Build type: ${CMAKE_BUILD_TYPE}" >> $GITHUB_STEP_SUMMARY | |
| echo "Commit: $GITHUB_SHA" >> $GITHUB_STEP_SUMMARY | |
| echo "Tests executed:" >> $GITHUB_STEP_SUMMARY | |
| ctest --test-dir build -N | sed 's/^/ /' >> $GITHUB_STEP_SUMMARY | |
| windows: | |
| name: Windows | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| build: [Debug, Release] | |
| runs-on: windows-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Configure (CMake) | |
| run: | | |
| cmake -S . -B build -A x64 ` | |
| -DCMAKE_BUILD_TYPE=${{ matrix.build }} ` | |
| -DAERONET_BUILD_TESTS=ON ` | |
| -DAERONET_ENABLE_TEST_HOOKS=ON ` | |
| -DAERONET_BUILD_EXAMPLES=ON ` | |
| -DAERONET_BUILD_BENCHMARKS=OFF ` | |
| -DAERONET_ENABLE_ASAN=OFF ` | |
| -DAERONET_ENABLE_ADDITIONAL_MEMORY_CHECKS=ON ` | |
| -DAERONET_ENABLE_CLANG_TIDY=OFF ` | |
| -DAERONET_ENABLE_ASYNC_HANDLERS=ON ` | |
| -DAERONET_ENABLE_GLAZE=ON ` | |
| -DAERONET_ENABLE_HTTP2=ON ` | |
| -DAERONET_ENABLE_BROTLI=ON ` | |
| -DAERONET_ENABLE_ZLIB=ON ` | |
| -DAERONET_ENABLE_ZSTD=ON ` | |
| -DAERONET_ENABLE_OPENSSL=ON ` | |
| -DOPENSSL_ROOT_DIR="$env:OPENSSL_ROOT_DIR" ` | |
| -DAERONET_ENABLE_OPENTELEMETRY=OFF ` | |
| -DAERONET_ENABLE_SPDLOG=ON ` | |
| -DAERONET_ENABLE_WEBSOCKET=ON ` | |
| -DAERONET_ENABLE_HTTP_CLIENT=ON | |
| shell: pwsh | |
| - name: Build | |
| run: | | |
| cmake --build build --config ${{ matrix.build }} --parallel | |
| - name: Run unit tests | |
| run: | | |
| ctest --test-dir build --build-config ${{ matrix.build }} --output-on-failure --timeout 60 -j | |
| shell: pwsh | |
| - name: Summary | |
| run: | | |
| echo "Compiler: MSVC" >> $env:GITHUB_STEP_SUMMARY | |
| echo "Build type: ${{ matrix.build }}" >> $env:GITHUB_STEP_SUMMARY | |
| echo "Commit: $env:GITHUB_SHA" >> $env:GITHUB_STEP_SUMMARY | |
| echo "Tests executed:" >> $env:GITHUB_STEP_SUMMARY | |
| ctest --test-dir build --build-config ${{ matrix.build }} -N | ForEach-Object { " $_" } >> $env:GITHUB_STEP_SUMMARY | |
| shell: pwsh | |
| alpine-musl-debug: | |
| name: Alpine (musl) Debug build | |
| runs-on: ubuntu-latest | |
| container: | |
| image: alpine:3.24 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v7 | |
| - name: Install dependencies | |
| run: | | |
| set -eu | |
| cat /etc/alpine-release | |
| apk add --no-cache build-base cmake ninja git bash python3 linux-headers \ | |
| openssl-dev curl-dev protobuf-dev musl-dev | |
| - name: Configure with cmake | |
| run: | | |
| ./scripts/retry.sh cmake -S . -B build-alpine -G Ninja \ | |
| -DCMAKE_BUILD_TYPE=Debug \ | |
| -DAERONET_BUILD_TESTS=ON \ | |
| -DAERONET_ENABLE_TEST_HOOKS=ON \ | |
| -DAERONET_BUILD_EXAMPLES=OFF \ | |
| -DAERONET_BUILD_BENCHMARKS=OFF \ | |
| -DAERONET_ENABLE_ASAN=OFF \ | |
| -DAERONET_ENABLE_ADDITIONAL_MEMORY_CHECKS=ON \ | |
| -DAERONET_ENABLE_ASYNC_HANDLERS=ON \ | |
| -DAERONET_ENABLE_GLAZE=ON \ | |
| -DAERONET_ENABLE_HTTP2=ON \ | |
| -DAERONET_ENABLE_BROTLI=ON \ | |
| -DAERONET_ENABLE_ZLIB=ON \ | |
| -DAERONET_ENABLE_ZSTD=ON \ | |
| -DAERONET_ENABLE_ZLIBNG=OFF \ | |
| -DAERONET_ENABLE_OPENTELEMETRY=ON \ | |
| -DAERONET_ENABLE_OPENSSL=ON \ | |
| -DAERONET_ENABLE_SPDLOG=ON \ | |
| -DAERONET_ENABLE_WEBSOCKET=ON \ | |
| -DAERONET_ENABLE_HTTP_CLIENT=ON | |
| - name: Build | |
| run: | | |
| cmake --build build-alpine --parallel | |
| - name: Run unit tests | |
| run: | | |
| ctest --test-dir build-alpine --output-on-failure --repeat until-fail:3 --timeout 60 -j |