From 316246ad6df2724cd4095e267db52e111edecdb1 Mon Sep 17 00:00:00 2001 From: Prachya Saechua Date: Thu, 19 Feb 2026 17:10:57 +0700 Subject: [PATCH 01/25] Add macOS and Windows Clang presets for improved cross-platform support - Introduced a new `macos.json` preset file with configurations for x64 and arm64 architectures, including debug, release, and test options. - Added hidden presets for vcpkg integration on macOS. - Updated `windows.json` to include Clang support with new presets for x86 and x64 architectures, maintaining compatibility with existing configurations. - Renamed existing Windows presets to reflect Clang usage and added corresponding build, test, and workflow presets. Signed-off-by: Prachya Saechua --- .github/workflows/ci.yml | 385 +++++++++++++++++---- .github/workflows/release.yml | 40 ++- AGENTS.md | 8 +- CMakePresets.json | 1 + README.md | 193 ++++++++--- cmake/presets/base.json | 8 + cmake/presets/linux.json | 264 +++++++++++---- cmake/presets/macos.json | 612 ++++++++++++++++++++++++++++++++++ cmake/presets/windows.json | 312 +++++++++++------ 9 files changed, 1532 insertions(+), 291 deletions(-) create mode 100644 cmake/presets/macos.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4e0e9d3d7..77e5b51d7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,7 +20,7 @@ on: jobs: # Linux build job (builds and uploads artifacts for test jobs) linux-build-test: - name: Linux Build (Test) + name: Linux Clang Build (Test) runs-on: ubuntu-latest env: @@ -30,10 +30,10 @@ jobs: fail-fast: false matrix: config: - - { preset: x64-linux-debug-test, build_type: Debug, ssl: true } - - { preset: x64-linux-release-test, build_type: Release, ssl: true } - - { preset: x64-linux-debug-no-ssl-test, build_type: Debug, ssl: false } - - { preset: x64-linux-release-no-ssl-test, build_type: Release, ssl: false } + - { preset: x64-linux-clang-debug-test, build_type: Debug, ssl: true } + - { preset: x64-linux-clang-release-test, build_type: Release, ssl: true } + - { preset: x64-linux-clang-debug-no-ssl-test, build_type: Debug, ssl: false } + - { preset: x64-linux-clang-release-no-ssl-test, build_type: Release, ssl: false } steps: - name: Checkout code @@ -42,7 +42,7 @@ jobs: - name: Install system dependencies run: | sudo apt-get update - sudo apt-get install -y ninja-build + sudo apt-get install -y ninja-build clang - name: Set VCPKG_ROOT environment variable run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV @@ -85,7 +85,7 @@ jobs: # Linux unit test jobs (run in parallel after build) linux-unit-test: - name: Linux Unit Test (${{ matrix.config.preset }}) + name: Linux Clang Unit Test (${{ matrix.config.preset }}) runs-on: ubuntu-latest needs: linux-build-test @@ -96,10 +96,10 @@ jobs: fail-fast: false matrix: config: - - { preset: x64-linux-debug-test, build_type: Debug, ssl: true } - - { preset: x64-linux-release-test, build_type: Release, ssl: true } - - { preset: x64-linux-debug-no-ssl-test, build_type: Debug, ssl: false } - - { preset: x64-linux-release-no-ssl-test, build_type: Release, ssl: false } + - { preset: x64-linux-clang-debug-test, build_type: Debug, ssl: true } + - { preset: x64-linux-clang-release-test, build_type: Release, ssl: true } + - { preset: x64-linux-clang-debug-no-ssl-test, build_type: Debug, ssl: false } + - { preset: x64-linux-clang-release-no-ssl-test, build_type: Release, ssl: false } steps: - name: Checkout code @@ -108,7 +108,7 @@ jobs: - name: Install system dependencies run: | sudo apt-get update - sudo apt-get install -y ninja-build + sudo apt-get install -y ninja-build clang - name: Set VCPKG_ROOT environment variable run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV @@ -152,7 +152,7 @@ jobs: # Linux benchmark jobs (run in parallel after build) linux-benchmark: - name: Linux Benchmark + name: Linux Clang Benchmark runs-on: ubuntu-latest needs: linux-build-test @@ -163,10 +163,10 @@ jobs: fail-fast: false matrix: config: - - { preset: x64-linux-debug-test, build_type: Debug, ssl: true } - - { preset: x64-linux-release-test, build_type: Release, ssl: true } - - { preset: x64-linux-debug-no-ssl-test, build_type: Debug, ssl: false } - - { preset: x64-linux-release-no-ssl-test, build_type: Release, ssl: false } + - { preset: x64-linux-clang-debug-test, build_type: Debug, ssl: true } + - { preset: x64-linux-clang-release-test, build_type: Release, ssl: true } + - { preset: x64-linux-clang-debug-no-ssl-test, build_type: Debug, ssl: false } + - { preset: x64-linux-clang-release-no-ssl-test, build_type: Release, ssl: false } steps: - name: Checkout code @@ -175,7 +175,7 @@ jobs: - name: Install system dependencies run: | sudo apt-get update - sudo apt-get install -y ninja-build + sudo apt-get install -y ninja-build clang - name: Set VCPKG_ROOT environment variable run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV @@ -229,7 +229,7 @@ jobs: matrix: # Use no-SSL release build for non-SSL integration tests config: - - { preset: x64-linux-release-no-ssl-test, build_type: Release } + - { preset: x64-linux-clang-release-no-ssl-test, build_type: Release } # Test with multiple ActiveMQ versions activemq: - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } @@ -242,7 +242,7 @@ jobs: - name: Install system dependencies run: | sudo apt-get update - sudo apt-get install -y ninja-build + sudo apt-get install -y ninja-build clang - name: Set VCPKG_ROOT environment variable run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV @@ -320,7 +320,7 @@ jobs: matrix: # Only test with SSL-enabled presets (release build) config: - - { preset: x64-linux-release-test, build_type: Release } + - { preset: x64-linux-clang-release-test, build_type: Release } # Test with ActiveMQ versions that support SSL activemq: - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } @@ -333,7 +333,7 @@ jobs: - name: Install system dependencies run: | sudo apt-get update - sudo apt-get install -y ninja-build + sudo apt-get install -y ninja-build clang - name: Set VCPKG_ROOT environment variable run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV @@ -414,7 +414,7 @@ jobs: matrix: # Use release build for integration benchmark tests (one config to avoid excessive combinations) config: - - { preset: x64-linux-release-test, build_type: Release } + - { preset: x64-linux-clang-release-test, build_type: Release } # Test with multiple ActiveMQ versions activemq: - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } @@ -427,7 +427,7 @@ jobs: - name: Install system dependencies run: | sudo apt-get update - sudo apt-get install -y ninja-build + sudo apt-get install -y ninja-build clang - name: Set VCPKG_ROOT environment variable run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV @@ -503,14 +503,14 @@ jobs: fail-fast: false matrix: preset: - - x64-linux-debug - - x64-linux-release - - x64-linux-debug-static - - x64-linux-release-static - - x64-linux-debug-no-ssl - - x64-linux-release-no-ssl - - x64-linux-debug-static-no-ssl - - x64-linux-release-static-no-ssl + - x64-linux-gcc-debug + - x64-linux-gcc-release + - x64-linux-gcc-debug-static + - x64-linux-gcc-release-static + - x64-linux-gcc-debug-no-ssl + - x64-linux-gcc-release-no-ssl + - x64-linux-gcc-debug-static-no-ssl + - x64-linux-gcc-release-static-no-ssl steps: - name: Checkout code @@ -553,7 +553,7 @@ jobs: # Windows build job (builds and uploads artifacts for test jobs) windows-build-test: - name: Windows Build (Test) + name: Windows Clang-CL Build (Test) runs-on: windows-latest env: @@ -563,12 +563,10 @@ jobs: fail-fast: false matrix: config: - - { preset: x86-windows-debug-test, build_type: Debug, arch: amd64_x86, ssl: true } - - { preset: x86-windows-release-test, build_type: Release, arch: amd64_x86, ssl: true } - - { preset: x64-windows-debug-test, build_type: Debug, arch: amd64, ssl: true } - - { preset: x64-windows-release-test, build_type: Release, arch: amd64, ssl: true } - - { preset: x64-windows-debug-no-ssl-test, build_type: Debug, arch: amd64, ssl: false } - - { preset: x64-windows-release-no-ssl-test, build_type: Release, arch: amd64, ssl: false } + - { preset: x64-windows-clang-debug-test, build_type: Debug, arch: amd64, ssl: true } + - { preset: x64-windows-clang-release-test, build_type: Release, arch: amd64, ssl: true } + - { preset: x64-windows-clang-debug-no-ssl-test, build_type: Debug, arch: amd64, ssl: false } + - { preset: x64-windows-clang-release-no-ssl-test, build_type: Release, arch: amd64, ssl: false } steps: - name: Checkout code @@ -625,7 +623,7 @@ jobs: # Windows unit test jobs (run in parallel after build, no Docker on Windows CI) windows-unit-test: - name: Windows Unit Test (${{ matrix.config.preset }}) + name: Windows Clang-CL Unit Test (${{ matrix.config.preset }}) runs-on: windows-latest needs: windows-build-test @@ -636,12 +634,10 @@ jobs: fail-fast: false matrix: config: - - { preset: x86-windows-debug-test, build_type: Debug, arch: amd64_x86, ssl: true } - - { preset: x86-windows-release-test, build_type: Release, arch: amd64_x86, ssl: true } - - { preset: x64-windows-debug-test, build_type: Debug, arch: amd64, ssl: true } - - { preset: x64-windows-release-test, build_type: Release, arch: amd64, ssl: true } - - { preset: x64-windows-debug-no-ssl-test, build_type: Debug, arch: amd64, ssl: false } - - { preset: x64-windows-release-no-ssl-test, build_type: Release, arch: amd64, ssl: false } + - { preset: x64-windows-clang-debug-test, build_type: Debug, arch: amd64, ssl: true } + - { preset: x64-windows-clang-release-test, build_type: Release, arch: amd64, ssl: true } + - { preset: x64-windows-clang-debug-no-ssl-test, build_type: Debug, arch: amd64, ssl: false } + - { preset: x64-windows-clang-release-no-ssl-test, build_type: Release, arch: amd64, ssl: false } steps: - name: Checkout code @@ -706,12 +702,10 @@ jobs: fail-fast: false matrix: config: - - { preset: x86-windows-debug-test, build_type: Debug, arch: amd64_x86, ssl: true } - - { preset: x86-windows-release-test, build_type: Release, arch: amd64_x86, ssl: true } - - { preset: x64-windows-debug-test, build_type: Debug, arch: amd64, ssl: true } - - { preset: x64-windows-release-test, build_type: Release, arch: amd64, ssl: true } - - { preset: x64-windows-debug-no-ssl-test, build_type: Debug, arch: amd64, ssl: false } - - { preset: x64-windows-release-no-ssl-test, build_type: Release, arch: amd64, ssl: false } + - { preset: x64-windows-clang-debug-test, build_type: Debug, arch: amd64, ssl: true } + - { preset: x64-windows-clang-release-test, build_type: Release, arch: amd64, ssl: true } + - { preset: x64-windows-clang-debug-no-ssl-test, build_type: Debug, arch: amd64, ssl: false } + - { preset: x64-windows-clang-release-no-ssl-test, build_type: Release, arch: amd64, ssl: false } steps: - name: Checkout code @@ -775,17 +769,17 @@ jobs: matrix: config: # x86 builds (shared with SSL only) - - { preset: x86-windows-debug, build_type: Debug, arch: x86 } - - { preset: x86-windows-release, build_type: Release, arch: x86 } + - { preset: x86-windows-cl-debug, build_type: Debug, arch: x86 } + - { preset: x86-windows-cl-release, build_type: Release, arch: x86 } # x64 builds (all variants) - - { preset: x64-windows-debug, build_type: Debug, arch: x64 } - - { preset: x64-windows-release, build_type: Release, arch: x64 } - - { preset: x64-windows-debug-static, build_type: Debug, arch: x64 } - - { preset: x64-windows-release-static, build_type: Release, arch: x64 } - - { preset: x64-windows-debug-no-ssl, build_type: Debug, arch: x64 } - - { preset: x64-windows-release-no-ssl, build_type: Release, arch: x64 } - - { preset: x64-windows-debug-static-no-ssl, build_type: Debug, arch: x64 } - - { preset: x64-windows-release-static-no-ssl, build_type: Release, arch: x64 } + - { preset: x64-windows-cl-debug, build_type: Debug, arch: x64 } + - { preset: x64-windows-cl-release, build_type: Release, arch: x64 } + - { preset: x64-windows-cl-debug-static, build_type: Debug, arch: x64 } + - { preset: x64-windows-cl-release-static, build_type: Release, arch: x64 } + - { preset: x64-windows-cl-debug-no-ssl, build_type: Debug, arch: x64 } + - { preset: x64-windows-cl-release-no-ssl, build_type: Release, arch: x64 } + - { preset: x64-windows-cl-debug-static-no-ssl, build_type: Debug, arch: x64 } + - { preset: x64-windows-cl-release-static-no-ssl, build_type: Release, arch: x64 } steps: - name: Checkout code @@ -830,3 +824,270 @@ jobs: - name: Install run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} + + # macOS build job (builds and uploads artifacts for test jobs) + macos-build-test: + name: macOS Build (Test) + runs-on: ${{ matrix.config.runner }} + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" + + strategy: + fail-fast: false + matrix: + config: + - { runner: macos-13, preset: x64-osx-debug-test, arch: x64, build_type: Debug, ssl: true } + - { runner: macos-13, preset: x64-osx-release-test, arch: x64, build_type: Release, ssl: true } + - { runner: macos-13, preset: x64-osx-debug-no-ssl-test, arch: x64, build_type: Debug, ssl: false } + - { runner: macos-13, preset: x64-osx-release-no-ssl-test, arch: x64, build_type: Release, ssl: false } + - { runner: macos-latest, preset: arm64-osx-debug-test, arch: arm64, build_type: Debug, ssl: true } + - { runner: macos-latest, preset: arm64-osx-release-test, arch: arm64, build_type: Release, ssl: true } + - { runner: macos-latest, preset: arm64-osx-debug-no-ssl-test, arch: arm64, build_type: Debug, ssl: false } + - { runner: macos-latest, preset: arm64-osx-release-no-ssl-test, arch: arm64, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: brew install ninja + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake + run: cmake --preset ${{ matrix.config.preset }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Build + run: cmake --build --preset ${{ matrix.config.preset }} -j $(nproc 2>/dev/null || sysctl -n hw.logicalcpu) + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Install + run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} + + - name: Upload build artifacts + uses: actions/upload-artifact@v6 + with: + name: macos-build-${{ matrix.config.preset }} + path: | + output/build/${{ matrix.config.preset }}/bin/ + output/build/${{ matrix.config.preset }}/lib/ + retention-days: 1 + + # macOS unit test jobs (run in parallel after build) + macos-unit-test: + name: macOS Unit Test (${{ matrix.config.preset }}) + runs-on: ${{ matrix.config.runner }} + needs: macos-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { runner: macos-13, preset: x64-osx-debug-test, arch: x64, build_type: Debug, ssl: true } + - { runner: macos-13, preset: x64-osx-release-test, arch: x64, build_type: Release, ssl: true } + - { runner: macos-13, preset: x64-osx-debug-no-ssl-test, arch: x64, build_type: Debug, ssl: false } + - { runner: macos-13, preset: x64-osx-release-no-ssl-test, arch: x64, build_type: Release, ssl: false } + - { runner: macos-latest, preset: arm64-osx-debug-test, arch: arm64, build_type: Debug, ssl: true } + - { runner: macos-latest, preset: arm64-osx-release-test, arch: arm64, build_type: Release, ssl: true } + - { runner: macos-latest, preset: arm64-osx-debug-no-ssl-test, arch: arm64, build_type: Debug, ssl: false } + - { runner: macos-latest, preset: arm64-osx-release-no-ssl-test, arch: arm64, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: brew install ninja + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: macos-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Run unit tests + run: | + ctest --preset ${{ matrix.config.preset }} \ + -L unit -j $(nproc 2>/dev/null || sysctl -n hw.logicalcpu) --output-on-failure --timeout 300 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-unit-${{ strategy.job-index }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # macOS benchmark jobs (run in parallel after build) + macos-benchmark: + name: macOS Benchmark + runs-on: ${{ matrix.config.runner }} + needs: macos-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { runner: macos-13, preset: x64-osx-debug-test, arch: x64, build_type: Debug, ssl: true } + - { runner: macos-13, preset: x64-osx-release-test, arch: x64, build_type: Release, ssl: true } + - { runner: macos-13, preset: x64-osx-debug-no-ssl-test, arch: x64, build_type: Debug, ssl: false } + - { runner: macos-13, preset: x64-osx-release-no-ssl-test, arch: x64, build_type: Release, ssl: false } + - { runner: macos-latest, preset: arm64-osx-debug-test, arch: arm64, build_type: Debug, ssl: true } + - { runner: macos-latest, preset: arm64-osx-release-test, arch: arm64, build_type: Release, ssl: true } + - { runner: macos-latest, preset: arm64-osx-debug-no-ssl-test, arch: arm64, build_type: Debug, ssl: false } + - { runner: macos-latest, preset: arm64-osx-release-no-ssl-test, arch: arm64, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: brew install ninja + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: macos-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Run benchmarks + run: ctest --preset ${{ matrix.config.preset }} -L ^benchmark$ --output-on-failure --timeout 600 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-benchmark + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # macOS builds without tests (all variants) + macos-build: + name: macOS Build + runs-on: ${{ matrix.config.runner }} + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" + + strategy: + fail-fast: false + matrix: + config: + # Intel x64 builds + - { runner: macos-13, preset: x64-osx-debug, arch: x64 } + - { runner: macos-13, preset: x64-osx-release, arch: x64 } + - { runner: macos-13, preset: x64-osx-debug-static, arch: x64 } + - { runner: macos-13, preset: x64-osx-release-static, arch: x64 } + - { runner: macos-13, preset: x64-osx-debug-no-ssl, arch: x64 } + - { runner: macos-13, preset: x64-osx-release-no-ssl, arch: x64 } + # Apple Silicon arm64 builds + - { runner: macos-latest, preset: arm64-osx-debug, arch: arm64 } + - { runner: macos-latest, preset: arm64-osx-release, arch: arm64 } + - { runner: macos-latest, preset: arm64-osx-debug-static, arch: arm64 } + - { runner: macos-latest, preset: arm64-osx-release-static, arch: arm64 } + - { runner: macos-latest, preset: arm64-osx-debug-no-ssl, arch: arm64 } + - { runner: macos-latest, preset: arm64-osx-release-no-ssl, arch: arm64 } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: brew install ninja + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake + run: cmake --preset ${{ matrix.config.preset }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Build + run: cmake --build --preset ${{ matrix.config.preset }} -j $(nproc 2>/dev/null || sysctl -n hw.logicalcpu) + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Install + run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d2260b0c0..ee2ff7ac9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -96,18 +96,24 @@ jobs: matrix: include: - os: ubuntu-latest - preset: x64-linux-release + preset: x64-linux-gcc-release artifact_name: activemq-cpp-${{ needs.create-release.outputs.new_version }}-linux-x64 - os: windows-latest - preset: x64-windows-release + preset: x64-windows-cl-release build_type: Release arch: x64 artifact_name: activemq-cpp-${{ needs.create-release.outputs.new_version }}-windows-x64 - os: windows-latest - preset: x86-windows-release + preset: x86-windows-cl-release build_type: Release arch: x86 artifact_name: activemq-cpp-${{ needs.create-release.outputs.new_version }}-windows-x86 + - os: macos-13 + preset: x64-osx-release + artifact_name: activemq-cpp-${{ needs.create-release.outputs.new_version }}-macos-x64 + - os: macos-latest + preset: arm64-osx-release + artifact_name: activemq-cpp-${{ needs.create-release.outputs.new_version }}-macos-arm64 steps: - name: Checkout code @@ -119,10 +125,14 @@ jobs: if: runner.os == 'Linux' run: | sudo apt-get update - sudo apt-get install -y ninja-build ccache + sudo apt-get install -y ninja-build - - name: Setup vcpkg (Linux) - if: runner.os == 'Linux' + - name: Install system dependencies (macOS) + if: runner.os == 'macOS' + run: brew install ninja + + - name: Setup vcpkg (Unix) + if: runner.os != 'Windows' run: | git clone https://github.com/microsoft/vcpkg.git ${{ env.VCPKG_ROOT }} ${{ env.VCPKG_ROOT }}/bootstrap-vcpkg.sh @@ -153,32 +163,32 @@ jobs: - name: Configure CMake run: cmake --preset ${{ matrix.preset }} - - name: Build (Linux) - if: runner.os == 'Linux' - run: cmake --build --preset ${{ matrix.preset }} -j $(nproc) + - name: Build (Unix) + if: runner.os != 'Windows' + run: cmake --build --preset ${{ matrix.preset }} -j $(nproc 2>/dev/null || sysctl -n hw.logicalcpu) - name: Build (Windows) if: runner.os == 'Windows' run: cmake --build --preset ${{ matrix.preset }} --config ${{ matrix.build_type }} - - name: Install (Linux) - if: runner.os == 'Linux' + - name: Install (Unix) + if: runner.os != 'Windows' run: cmake --install output/build/${{ matrix.preset }} --prefix ${{ matrix.artifact_name }} - name: Install (Windows) if: runner.os == 'Windows' run: cmake --install output/build/${{ matrix.preset }} --prefix ${{ matrix.artifact_name }} --config ${{ matrix.build_type }} - - name: Create archive (Linux) - if: runner.os == 'Linux' + - name: Create archive (Unix) + if: runner.os != 'Windows' run: tar -czf ${{ matrix.artifact_name }}.tar.gz ${{ matrix.artifact_name }} - name: Create archive (Windows) if: runner.os == 'Windows' run: Compress-Archive -Path ${{ matrix.artifact_name }} -DestinationPath ${{ matrix.artifact_name }}.zip - - name: Upload artifact (Linux) - if: runner.os == 'Linux' + - name: Upload artifact (Unix) + if: runner.os != 'Windows' uses: actions/upload-artifact@v6 with: name: ${{ matrix.artifact_name }} diff --git a/AGENTS.md b/AGENTS.md index 96a25ae2a..f83be7034 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,15 +7,15 @@ This project uses **CMake with presets**. Always use CMake presets for configura ### Configure ```powershell -# Configure with a preset (e.g., x86-windows-debug-test) -cmake --preset x86-windows-debug-test +# Configure with a preset (e.g., x86-windows-cl-debug-test) +cmake --preset x86-windows-cl-debug-test ``` ### Build ```powershell # Build using the configured preset -cmake --build --preset x86-windows-debug-test +cmake --build --preset x86-windows-cl-debug-test ``` ### Available Presets @@ -29,7 +29,7 @@ cmake --list-presets ```powershell # Run all unit tests via CTest after building -ctest --preset x86-windows-debug-test +ctest --preset x86-windows-cl-debug-test ``` ## Important Notes diff --git a/CMakePresets.json b/CMakePresets.json index 006755a5e..6c6872acf 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -8,6 +8,7 @@ "include": [ "cmake/presets/base.json", "cmake/presets/linux.json", + "cmake/presets/macos.json", "cmake/presets/windows.json" ] } \ No newline at end of file diff --git a/README.md b/README.md index 5a02ffb0b..83b5817a2 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,13 @@ NeoActiveMQ CPP is a modernized C++17 messaging library that can use multiple pr | Tool | Recommended Version | |------|-------------------| -| CMake | >= 3.15 | +| CMake | >= 3.27 (>= 3.31 on Windows) | | vcpkg | latest | | C++ Compiler | C++17 support required | | MSVC | >= 2019 (Windows) | -| GCC | >= 7.0 (Linux) | -| Clang | >= 5.0 (macOS/Linux) | +| Clang-CL | >= 14 (Windows, for test builds) | +| GCC | >= 7.0 (Linux, non-test builds) | +| Clang | >= 14 (Linux/macOS) | ### 1.2 Automatic Dependency Management @@ -37,63 +38,149 @@ To see all available presets: cmake --list-presets ``` -Common presets: +Presets follow the naming pattern `---[-]`: + +**Windows (MSVC cl.exe — standard builds):** + +| Preset | Description | +|--------|-------------| +| `x86-windows-cl-debug` | Windows 32-bit Debug | +| `x86-windows-cl-release` | Windows 32-bit Release | +| `x64-windows-cl-debug` | Windows 64-bit Debug | +| `x64-windows-cl-release` | Windows 64-bit Release | +| `x64-windows-cl-debug-static` | Windows 64-bit Debug, static runtime | +| `x64-windows-cl-release-static` | Windows 64-bit Release, static runtime | +| `x64-windows-cl-debug-no-ssl` | Windows 64-bit Debug, no SSL | +| `x64-windows-cl-release-no-ssl` | Windows 64-bit Release, no SSL | + +**Windows (MSVC cl.exe — test builds):** + +| Preset | Description | +|--------|-------------| +| `x86-windows-cl-debug-test` | Windows 32-bit Debug with tests | +| `x86-windows-cl-release-test` | Windows 32-bit Release with tests | +| `x64-windows-cl-debug-test` | Windows 64-bit Debug with tests | +| `x64-windows-cl-release-test` | Windows 64-bit Release with tests | +| `x64-windows-cl-debug-no-ssl-test` | Windows 64-bit Debug with tests, no SSL | +| `x64-windows-cl-release-no-ssl-test` | Windows 64-bit Release with tests, no SSL | + +**Windows (clang-cl — test builds, used in CI):** + +| Preset | Description | +|--------|-------------| +| `x64-windows-clang-debug-test` | Windows 64-bit Debug with tests | +| `x64-windows-clang-release-test` | Windows 64-bit Release with tests | +| `x64-windows-clang-debug-no-ssl-test` | Windows 64-bit Debug with tests, no SSL | +| `x64-windows-clang-release-no-ssl-test` | Windows 64-bit Release with tests, no SSL | + +**Linux (GCC — standard builds):** + +| Preset | Description | +|--------|-------------| +| `x64-linux-gcc-debug` | Linux 64-bit Debug | +| `x64-linux-gcc-release` | Linux 64-bit Release | +| `x64-linux-gcc-debug-static` | Linux 64-bit Debug, static | +| `x64-linux-gcc-release-static` | Linux 64-bit Release, static | +| `x64-linux-gcc-debug-no-ssl` | Linux 64-bit Debug, no SSL | +| `x64-linux-gcc-release-no-ssl` | Linux 64-bit Release, no SSL | + +**Linux (GCC — test builds):** + +| Preset | Description | +|--------|-------------| +| `x64-linux-gcc-debug-test` | Linux 64-bit Debug with tests | +| `x64-linux-gcc-release-test` | Linux 64-bit Release with tests | +| `x64-linux-gcc-debug-no-ssl-test` | Linux 64-bit Debug with tests, no SSL | +| `x64-linux-gcc-release-no-ssl-test` | Linux 64-bit Release with tests, no SSL | + +**Linux (Clang — test builds, used in CI):** + +| Preset | Description | +|--------|-------------| +| `x64-linux-clang-debug-test` | Linux 64-bit Debug with tests | +| `x64-linux-clang-release-test` | Linux 64-bit Release with tests | +| `x64-linux-clang-debug-no-ssl-test` | Linux 64-bit Debug with tests, no SSL | +| `x64-linux-clang-release-no-ssl-test` | Linux 64-bit Release with tests, no SSL | + +**macOS (Clang):** | Preset | Description | |--------|-------------| -| `x86-windows-debug-test` | Windows 32-bit Debug with tests | -| `x86-windows-release` | Windows 32-bit Release | -| `x64-windows-debug-test` | Windows 64-bit Debug with tests | -| `x64-windows-release` | Windows 64-bit Release | -| `x64-linux-debug-test` | Linux 64-bit Debug with tests | -| `x64-linux-release` | Linux 64-bit Release | +| `x64-osx-debug` | macOS Intel Debug | +| `x64-osx-release` | macOS Intel Release | +| `x64-osx-debug-test` | macOS Intel Debug with tests | +| `x64-osx-release-test` | macOS Intel Release with tests | +| `arm64-osx-debug` | macOS Apple Silicon Debug | +| `arm64-osx-release` | macOS Apple Silicon Release | +| `arm64-osx-debug-test` | macOS Apple Silicon Debug with tests | +| `arm64-osx-release-test` | macOS Apple Silicon Release with tests | ### 2.2 Quick Start - Windows 1. Configure the project: ```bash - cmake --preset x86-windows-debug-test + cmake --preset x64-windows-cl-debug-test ``` This will: - Download and build all dependencies via vcpkg - Configure the build with tests enabled - - Generate build files in `output/build/x86-windows-debug-test/` + - Generate build files in `output/build/x64-windows-cl-debug-test/` 2. Build the project: ```bash - cmake --build --preset x86-windows-debug-test + cmake --build --preset x64-windows-cl-debug-test ``` The build output will be in: - Libraries: `output/build//lib/` - Executables: `output/build//bin/` -### 2.3 Quick Start - Linux/macOS +### 2.3 Quick Start - Linux 1. Configure the project: ```bash - cmake --preset x64-linux-debug-test + cmake --preset x64-linux-gcc-debug-test + ``` + +2. Build the project: + + ```bash + cmake --build --preset x64-linux-gcc-debug-test + ``` + +### 2.4 Quick Start - macOS + +1. Configure the project (Apple Silicon): + + ```bash + cmake --preset arm64-osx-debug-test + ``` + + Or for Intel Macs: + + ```bash + cmake --preset x64-osx-debug-test ``` 2. Build the project: ```bash - cmake --build --preset x64-linux-debug-test + cmake --build --preset arm64-osx-debug-test ``` -### 2.4 Installation +### 2.5 Installation -To install the library to the system: +To install the library: ```bash cmake --install output/build/ --prefix /usr/local ``` -Or on Windows with administrator privileges: +Or on Windows: ```bash cmake --install output/build/ --prefix "C:/Program Files/neoactivemq-cpp" @@ -108,12 +195,16 @@ This installs: ### 3.1 Unit Tests -The test executables are built automatically when using a preset with `-test` in the name (e.g., `x86-windows-debug-test`). +Test executables are built automatically when using a preset with `-test` in the name. Test builds use Clang on Linux/macOS and clang-cl on Windows for consistent diagnostics across platforms. To run unit tests via CTest: ```bash -ctest --preset x86-windows-debug-test -L unit +# Linux (GCC) +ctest --preset x64-linux-gcc-debug-test -L unit + +# Windows (MSVC) +ctest --preset x64-windows-cl-debug-test -L unit ``` ### 3.2 Integration Tests @@ -166,18 +257,18 @@ docker compose --profile ssl down ``` **SSL Test Coverage:** -- ✅ All acknowledgment modes (client, individual, optimized) -- ✅ Advisory messages -- ✅ Async sending and callbacks -- ✅ Message selectors and groups -- ✅ Durable subscriptions -- ✅ Transactions (local and XA) -- ✅ Redelivery policies and session recovery -- ✅ Temporary destinations -- ✅ Message compression and priority -- ✅ Queue browsing and virtual topics -- ✅ Slow consumers and expiration -- ✅ Enhanced connection features +- All acknowledgment modes (client, individual, optimized) +- Advisory messages +- Async sending and callbacks +- Message selectors and groups +- Durable subscriptions +- Transactions (local and XA) +- Redelivery policies and session recovery +- Temporary destinations +- Message compression and priority +- Queue browsing and virtual topics +- Slow consumers and expiration +- Enhanced connection features ### 3.4 Integration Benchmark Tests @@ -242,7 +333,7 @@ The following CMake options can be configured: To customize a preset, pass options during configuration: ```bash -cmake --preset x86-windows-debug-test -DBUILD_EXAMPLES=OFF +cmake --preset x64-windows-cl-debug-test -DBUILD_EXAMPLES=OFF ``` ## 6. Project Structure @@ -260,44 +351,58 @@ activemq-cpp/src/test-integration/ Integration tests activemq-cpp/src/test-integration-benchmarks/ Failover & high-volume benchmark tests activemq-cpp/src/examples/ Example applications cmake/ CMake configuration files + presets/ Platform-specific preset files docker/ssl/ SSL certificate generation and broker config output/build/ Build output directory (created by CMake) ``` -## 7. Notes for Windows Users +## 7. Compiler Strategy + +This project supports multiple compilers. CI uses Clang/clang-cl for test builds (similar to the Chromium project), but all compilers can be used locally: + +| Platform | Standard Builds | Test Builds (local) | Test Builds (CI) | +|----------|----------------|---------------------|------------------| +| Windows | MSVC (`cl.exe`) | MSVC (`cl.exe`) | clang-cl | +| Linux | GCC | GCC | Clang | +| macOS | Clang | Clang | Clang | + +CI uses Clang/clang-cl to benefit from better diagnostics, improved sanitizer support, and consistent cross-platform behavior. + +## 8. Notes for Windows Users - Visual Studio 2019 or later is required for C++17 support -- No need to manually install dependencies -- vcpkg handles everything +- No need to manually install dependencies — vcpkg handles everything - The Platform SDK is included with Visual Studio 2019+ +- clang-cl is included with Visual Studio 2019+ (LLVM toolset component) - When linking applications: - **Static library** (default): No special considerations - **Shared library**: Ensure runtime library matches (MD vs MT flags) -## 8. Notes for Linux/macOS Users +## 9. Notes for Linux/macOS Users -- GCC 7+ or Clang 5+ required for C++17 support +- Clang 14+ recommended for test builds; GCC 7+ supported for standard builds - vcpkg automatically downloads and builds all dependencies -- No need for manual `apt-get` or `yum` package installations +- No need for manual `apt-get` or `yum` package installations for library dependencies - For system-wide installation, use `sudo` with `cmake --install` -## 9. Troubleshooting +## 10. Troubleshooting -### 9.1 CMake Configuration Fails +### 10.1 CMake Configuration Fails If CMake can't find the compiler: - Ensure Visual Studio is installed (Windows) - Ensure GCC/Clang is in PATH (Linux/macOS) - Try running from Visual Studio Developer Command Prompt (Windows) -### 9.2 Build Fails +### 10.2 Build Fails If build fails with missing dependencies: - Delete `output/build/` and reconfigure - vcpkg will re-download dependencies -### 9.3 Preset Not Found +### 10.3 Preset Not Found If preset is not recognized: - Ensure you're in the project root directory - Check `CMakePresets.json` exists -- Update CMake to version 3.15 or later +- Update CMake to version 3.27 or later (3.31+ on Windows) diff --git a/cmake/presets/base.json b/cmake/presets/base.json index 26431a502..2414d8789 100644 --- a/cmake/presets/base.json +++ b/cmake/presets/base.json @@ -65,6 +65,14 @@ "value": "x64" } }, + { + "name": "arm64", + "hidden": true, + "architecture": { + "strategy": "external", + "value": "arm64" + } + }, { "name": "debug", "hidden": true, diff --git a/cmake/presets/linux.json b/cmake/presets/linux.json index 04211d151..fc0c59eb8 100644 --- a/cmake/presets/linux.json +++ b/cmake/presets/linux.json @@ -29,6 +29,26 @@ "VCPKG_FORCE_SYSTEM_BINARIES": "1" } }, + { + "name": "linux-clang", + "inherits": [ + "base" + ], + "hidden": true, + "generator": "Ninja", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + }, + "environment": { + "VCPKG_FORCE_SYSTEM_BINARIES": "1" + } + }, { "name": "vcpkg-x64-linux", "hidden": true, @@ -37,7 +57,7 @@ } }, { - "name": "x64-linux-debug", + "name": "x64-linux-gcc-debug", "inherits": [ "x64", "linux", @@ -46,7 +66,7 @@ ] }, { - "name": "x64-linux-debug-test", + "name": "x64-linux-gcc-debug-test", "inherits": [ "x64", "linux", @@ -56,7 +76,7 @@ ] }, { - "name": "x64-linux-release", + "name": "x64-linux-gcc-release", "inherits": [ "x64", "linux", @@ -65,7 +85,7 @@ ] }, { - "name": "x64-linux-release-test", + "name": "x64-linux-gcc-release-test", "inherits": [ "x64", "linux", @@ -75,7 +95,7 @@ ] }, { - "name": "x64-linux-debug-static", + "name": "x64-linux-gcc-debug-static", "inherits": [ "x64", "linux", @@ -85,7 +105,7 @@ ] }, { - "name": "x64-linux-release-static", + "name": "x64-linux-gcc-release-static", "inherits": [ "x64", "linux", @@ -95,7 +115,7 @@ ] }, { - "name": "x64-linux-debug-no-ssl", + "name": "x64-linux-gcc-debug-no-ssl", "inherits": [ "x64", "linux", @@ -105,7 +125,7 @@ ] }, { - "name": "x64-linux-release-no-ssl", + "name": "x64-linux-gcc-release-no-ssl", "inherits": [ "x64", "linux", @@ -115,7 +135,7 @@ ] }, { - "name": "x64-linux-debug-static-no-ssl", + "name": "x64-linux-gcc-debug-static-no-ssl", "inherits": [ "x64", "linux", @@ -126,7 +146,7 @@ ] }, { - "name": "x64-linux-release-static-no-ssl", + "name": "x64-linux-gcc-release-static-no-ssl", "inherits": [ "x64", "linux", @@ -137,7 +157,7 @@ ] }, { - "name": "x64-linux-debug-no-ssl-test", + "name": "x64-linux-gcc-debug-no-ssl-test", "inherits": [ "x64", "linux", @@ -148,7 +168,7 @@ ] }, { - "name": "x64-linux-release-no-ssl-test", + "name": "x64-linux-gcc-release-no-ssl-test", "inherits": [ "x64", "linux", @@ -157,56 +177,140 @@ "release", "no-ssl" ] + }, + { + "name": "x64-linux-clang-debug", + "inherits": [ + "x64", + "linux-clang", + "vcpkg-x64-linux", + "debug" + ] + }, + { + "name": "x64-linux-clang-debug-test", + "inherits": [ + "x64", + "linux-clang", + "test", + "vcpkg-x64-linux", + "debug" + ] + }, + { + "name": "x64-linux-clang-release", + "inherits": [ + "x64", + "linux-clang", + "vcpkg-x64-linux", + "release" + ] + }, + { + "name": "x64-linux-clang-release-test", + "inherits": [ + "x64", + "linux-clang", + "test", + "vcpkg-x64-linux", + "release" + ] + }, + { + "name": "x64-linux-clang-debug-no-ssl-test", + "inherits": [ + "x64", + "linux-clang", + "test-no-ssl", + "vcpkg-x64-linux", + "debug", + "no-ssl" + ] + }, + { + "name": "x64-linux-clang-release-no-ssl-test", + "inherits": [ + "x64", + "linux-clang", + "test-no-ssl", + "vcpkg-x64-linux", + "release", + "no-ssl" + ] } ], "buildPresets": [ { - "name": "x64-linux-debug", - "configurePreset": "x64-linux-debug" + "name": "x64-linux-gcc-debug", + "configurePreset": "x64-linux-gcc-debug" + }, + { + "name": "x64-linux-gcc-debug-test", + "configurePreset": "x64-linux-gcc-debug-test" }, { - "name": "x64-linux-debug-test", - "configurePreset": "x64-linux-debug-test" + "name": "x64-linux-gcc-release", + "configurePreset": "x64-linux-gcc-release" }, { - "name": "x64-linux-release", - "configurePreset": "x64-linux-release" + "name": "x64-linux-gcc-release-test", + "configurePreset": "x64-linux-gcc-release-test" }, { - "name": "x64-linux-release-test", - "configurePreset": "x64-linux-release-test" + "name": "x64-linux-gcc-debug-static", + "configurePreset": "x64-linux-gcc-debug-static" }, { - "name": "x64-linux-debug-static", - "configurePreset": "x64-linux-debug-static" + "name": "x64-linux-gcc-release-static", + "configurePreset": "x64-linux-gcc-release-static" }, { - "name": "x64-linux-release-static", - "configurePreset": "x64-linux-release-static" + "name": "x64-linux-gcc-debug-no-ssl", + "configurePreset": "x64-linux-gcc-debug-no-ssl" }, { - "name": "x64-linux-debug-no-ssl", - "configurePreset": "x64-linux-debug-no-ssl" + "name": "x64-linux-gcc-release-no-ssl", + "configurePreset": "x64-linux-gcc-release-no-ssl" }, { - "name": "x64-linux-release-no-ssl", - "configurePreset": "x64-linux-release-no-ssl" + "name": "x64-linux-gcc-debug-static-no-ssl", + "configurePreset": "x64-linux-gcc-debug-static-no-ssl" }, { - "name": "x64-linux-debug-static-no-ssl", - "configurePreset": "x64-linux-debug-static-no-ssl" + "name": "x64-linux-gcc-release-static-no-ssl", + "configurePreset": "x64-linux-gcc-release-static-no-ssl" }, { - "name": "x64-linux-release-static-no-ssl", - "configurePreset": "x64-linux-release-static-no-ssl" + "name": "x64-linux-gcc-debug-no-ssl-test", + "configurePreset": "x64-linux-gcc-debug-no-ssl-test" }, { - "name": "x64-linux-debug-no-ssl-test", - "configurePreset": "x64-linux-debug-no-ssl-test" + "name": "x64-linux-gcc-release-no-ssl-test", + "configurePreset": "x64-linux-gcc-release-no-ssl-test" }, { - "name": "x64-linux-release-no-ssl-test", - "configurePreset": "x64-linux-release-no-ssl-test" + "name": "x64-linux-clang-debug", + "configurePreset": "x64-linux-clang-debug" + }, + { + "name": "x64-linux-clang-debug-test", + "configurePreset": "x64-linux-clang-debug-test" + }, + { + "name": "x64-linux-clang-release", + "configurePreset": "x64-linux-clang-release" + }, + { + "name": "x64-linux-clang-release-test", + "configurePreset": "x64-linux-clang-release-test" + }, + { + "name": "x64-linux-clang-debug-no-ssl-test", + "configurePreset": "x64-linux-clang-debug-no-ssl-test" + }, + { + "name": "x64-linux-clang-release-no-ssl-test", + "configurePreset": "x64-linux-clang-release-no-ssl-test" } ], "testPresets": [ @@ -221,24 +325,44 @@ } }, { - "name": "x64-linux-debug-test", + "name": "x64-linux-gcc-debug-test", + "inherits": "linux-test", + "configurePreset": "x64-linux-gcc-debug-test" + }, + { + "name": "x64-linux-gcc-release-test", + "inherits": "linux-test", + "configurePreset": "x64-linux-gcc-release-test" + }, + { + "name": "x64-linux-gcc-debug-no-ssl-test", + "inherits": "linux-test", + "configurePreset": "x64-linux-gcc-debug-no-ssl-test" + }, + { + "name": "x64-linux-gcc-release-no-ssl-test", + "inherits": "linux-test", + "configurePreset": "x64-linux-gcc-release-no-ssl-test" + }, + { + "name": "x64-linux-clang-debug-test", "inherits": "linux-test", - "configurePreset": "x64-linux-debug-test" + "configurePreset": "x64-linux-clang-debug-test" }, { - "name": "x64-linux-release-test", + "name": "x64-linux-clang-release-test", "inherits": "linux-test", - "configurePreset": "x64-linux-release-test" + "configurePreset": "x64-linux-clang-release-test" }, { - "name": "x64-linux-debug-no-ssl-test", + "name": "x64-linux-clang-debug-no-ssl-test", "inherits": "linux-test", - "configurePreset": "x64-linux-debug-no-ssl-test" + "configurePreset": "x64-linux-clang-debug-no-ssl-test" }, { - "name": "x64-linux-release-no-ssl-test", + "name": "x64-linux-clang-release-no-ssl-test", "inherits": "linux-test", - "configurePreset": "x64-linux-release-no-ssl-test" + "configurePreset": "x64-linux-clang-release-no-ssl-test" } ], "packagePresets": [ @@ -252,15 +376,15 @@ ] }, { - "name": "x64-linux-debug", - "configurePreset": "x64-linux-debug", + "name": "x64-linux-gcc-debug", + "configurePreset": "x64-linux-gcc-debug", "inherits": [ "linux-common" ] }, { - "name": "x64-linux-release", - "configurePreset": "x64-linux-release", + "name": "x64-linux-gcc-release", + "configurePreset": "x64-linux-gcc-release", "inherits": [ "linux-common" ] @@ -268,96 +392,96 @@ ], "workflowPresets": [ { - "name": "x64-linux-debug", + "name": "x64-linux-gcc-debug", "steps": [ { "type": "configure", - "name": "x64-linux-debug" + "name": "x64-linux-gcc-debug" }, { "type": "build", - "name": "x64-linux-debug" + "name": "x64-linux-gcc-debug" } ] }, { - "name": "x64-linux-debug-test", + "name": "x64-linux-gcc-debug-test", "steps": [ { "type": "configure", - "name": "x64-linux-debug-test" + "name": "x64-linux-gcc-debug-test" }, { "type": "build", - "name": "x64-linux-debug-test" + "name": "x64-linux-gcc-debug-test" }, { "type": "test", - "name": "x64-linux-debug-test" + "name": "x64-linux-gcc-debug-test" } ] }, { - "name": "x64-linux-release", + "name": "x64-linux-gcc-release", "steps": [ { "type": "configure", - "name": "x64-linux-release" + "name": "x64-linux-gcc-release" }, { "type": "build", - "name": "x64-linux-release" + "name": "x64-linux-gcc-release" } ] }, { - "name": "x64-linux-release-test", + "name": "x64-linux-gcc-release-test", "steps": [ { "type": "configure", - "name": "x64-linux-release-test" + "name": "x64-linux-gcc-release-test" }, { "type": "build", - "name": "x64-linux-release-test" + "name": "x64-linux-gcc-release-test" }, { "type": "test", - "name": "x64-linux-release-test" + "name": "x64-linux-gcc-release-test" } ] }, { - "name": "x64-linux-debug-no-ssl-test", + "name": "x64-linux-gcc-debug-no-ssl-test", "steps": [ { "type": "configure", - "name": "x64-linux-debug-no-ssl-test" + "name": "x64-linux-gcc-debug-no-ssl-test" }, { "type": "build", - "name": "x64-linux-debug-no-ssl-test" + "name": "x64-linux-gcc-debug-no-ssl-test" }, { "type": "test", - "name": "x64-linux-debug-no-ssl-test" + "name": "x64-linux-gcc-debug-no-ssl-test" } ] }, { - "name": "x64-linux-release-no-ssl-test", + "name": "x64-linux-gcc-release-no-ssl-test", "steps": [ { "type": "configure", - "name": "x64-linux-release-no-ssl-test" + "name": "x64-linux-gcc-release-no-ssl-test" }, { "type": "build", - "name": "x64-linux-release-no-ssl-test" + "name": "x64-linux-gcc-release-no-ssl-test" }, { "type": "test", - "name": "x64-linux-release-no-ssl-test" + "name": "x64-linux-gcc-release-no-ssl-test" } ] } diff --git a/cmake/presets/macos.json b/cmake/presets/macos.json new file mode 100644 index 000000000..30a0a9ef0 --- /dev/null +++ b/cmake/presets/macos.json @@ -0,0 +1,612 @@ +{ + "version": 7, + "cmakeMinimumRequired": { + "major": 3, + "minor": 27, + "patch": 0 + }, + "include": [ + "base.json" + ], + "configurePresets": [ + { + "name": "macos", + "inherits": [ + "base" + ], + "hidden": true, + "generator": "Ninja", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Darwin" + } + }, + { + "name": "vcpkg-x64-osx", + "hidden": true, + "cacheVariables": { + "CMAKE_OSX_ARCHITECTURES": "x86_64" + }, + "environment": { + "VCPKG_DEFAULT_TRIPLET": "x64-osx" + } + }, + { + "name": "vcpkg-arm64-osx", + "hidden": true, + "cacheVariables": { + "CMAKE_OSX_ARCHITECTURES": "arm64" + }, + "environment": { + "VCPKG_DEFAULT_TRIPLET": "arm64-osx" + } + }, + { + "name": "x64-osx-debug", + "inherits": [ + "x64", + "macos", + "vcpkg-x64-osx", + "debug" + ] + }, + { + "name": "x64-osx-debug-test", + "inherits": [ + "x64", + "macos", + "test", + "vcpkg-x64-osx", + "debug" + ] + }, + { + "name": "x64-osx-release", + "inherits": [ + "x64", + "macos", + "vcpkg-x64-osx", + "release" + ] + }, + { + "name": "x64-osx-release-test", + "inherits": [ + "x64", + "macos", + "test", + "vcpkg-x64-osx", + "release" + ] + }, + { + "name": "x64-osx-debug-static", + "inherits": [ + "x64", + "macos", + "vcpkg-x64-osx", + "debug", + "static" + ] + }, + { + "name": "x64-osx-release-static", + "inherits": [ + "x64", + "macos", + "vcpkg-x64-osx", + "release", + "static" + ] + }, + { + "name": "x64-osx-debug-no-ssl", + "inherits": [ + "x64", + "macos", + "vcpkg-x64-osx", + "debug", + "no-ssl" + ] + }, + { + "name": "x64-osx-release-no-ssl", + "inherits": [ + "x64", + "macos", + "vcpkg-x64-osx", + "release", + "no-ssl" + ] + }, + { + "name": "x64-osx-debug-no-ssl-test", + "inherits": [ + "x64", + "macos", + "test-no-ssl", + "vcpkg-x64-osx", + "debug", + "no-ssl" + ] + }, + { + "name": "x64-osx-release-no-ssl-test", + "inherits": [ + "x64", + "macos", + "test-no-ssl", + "vcpkg-x64-osx", + "release", + "no-ssl" + ] + }, + { + "name": "arm64-osx-debug", + "inherits": [ + "arm64", + "macos", + "vcpkg-arm64-osx", + "debug" + ] + }, + { + "name": "arm64-osx-debug-test", + "inherits": [ + "arm64", + "macos", + "test", + "vcpkg-arm64-osx", + "debug" + ] + }, + { + "name": "arm64-osx-release", + "inherits": [ + "arm64", + "macos", + "vcpkg-arm64-osx", + "release" + ] + }, + { + "name": "arm64-osx-release-test", + "inherits": [ + "arm64", + "macos", + "test", + "vcpkg-arm64-osx", + "release" + ] + }, + { + "name": "arm64-osx-debug-static", + "inherits": [ + "arm64", + "macos", + "vcpkg-arm64-osx", + "debug", + "static" + ] + }, + { + "name": "arm64-osx-release-static", + "inherits": [ + "arm64", + "macos", + "vcpkg-arm64-osx", + "release", + "static" + ] + }, + { + "name": "arm64-osx-debug-no-ssl", + "inherits": [ + "arm64", + "macos", + "vcpkg-arm64-osx", + "debug", + "no-ssl" + ] + }, + { + "name": "arm64-osx-release-no-ssl", + "inherits": [ + "arm64", + "macos", + "vcpkg-arm64-osx", + "release", + "no-ssl" + ] + }, + { + "name": "arm64-osx-debug-no-ssl-test", + "inherits": [ + "arm64", + "macos", + "test-no-ssl", + "vcpkg-arm64-osx", + "debug", + "no-ssl" + ] + }, + { + "name": "arm64-osx-release-no-ssl-test", + "inherits": [ + "arm64", + "macos", + "test-no-ssl", + "vcpkg-arm64-osx", + "release", + "no-ssl" + ] + } + ], + "buildPresets": [ + { + "name": "x64-osx-debug", + "configurePreset": "x64-osx-debug" + }, + { + "name": "x64-osx-debug-test", + "configurePreset": "x64-osx-debug-test" + }, + { + "name": "x64-osx-release", + "configurePreset": "x64-osx-release" + }, + { + "name": "x64-osx-release-test", + "configurePreset": "x64-osx-release-test" + }, + { + "name": "x64-osx-debug-static", + "configurePreset": "x64-osx-debug-static" + }, + { + "name": "x64-osx-release-static", + "configurePreset": "x64-osx-release-static" + }, + { + "name": "x64-osx-debug-no-ssl", + "configurePreset": "x64-osx-debug-no-ssl" + }, + { + "name": "x64-osx-release-no-ssl", + "configurePreset": "x64-osx-release-no-ssl" + }, + { + "name": "x64-osx-debug-no-ssl-test", + "configurePreset": "x64-osx-debug-no-ssl-test" + }, + { + "name": "x64-osx-release-no-ssl-test", + "configurePreset": "x64-osx-release-no-ssl-test" + }, + { + "name": "arm64-osx-debug", + "configurePreset": "arm64-osx-debug" + }, + { + "name": "arm64-osx-debug-test", + "configurePreset": "arm64-osx-debug-test" + }, + { + "name": "arm64-osx-release", + "configurePreset": "arm64-osx-release" + }, + { + "name": "arm64-osx-release-test", + "configurePreset": "arm64-osx-release-test" + }, + { + "name": "arm64-osx-debug-static", + "configurePreset": "arm64-osx-debug-static" + }, + { + "name": "arm64-osx-release-static", + "configurePreset": "arm64-osx-release-static" + }, + { + "name": "arm64-osx-debug-no-ssl", + "configurePreset": "arm64-osx-debug-no-ssl" + }, + { + "name": "arm64-osx-release-no-ssl", + "configurePreset": "arm64-osx-release-no-ssl" + }, + { + "name": "arm64-osx-debug-no-ssl-test", + "configurePreset": "arm64-osx-debug-no-ssl-test" + }, + { + "name": "arm64-osx-release-no-ssl-test", + "configurePreset": "arm64-osx-release-no-ssl-test" + } + ], + "testPresets": [ + { + "name": "macos-test", + "hidden": true, + "output": { + "outputOnFailure": true + }, + "execution": { + "timeout": 300 + } + }, + { + "name": "x64-osx-debug-test", + "inherits": "macos-test", + "configurePreset": "x64-osx-debug-test" + }, + { + "name": "x64-osx-release-test", + "inherits": "macos-test", + "configurePreset": "x64-osx-release-test" + }, + { + "name": "x64-osx-debug-no-ssl-test", + "inherits": "macos-test", + "configurePreset": "x64-osx-debug-no-ssl-test" + }, + { + "name": "x64-osx-release-no-ssl-test", + "inherits": "macos-test", + "configurePreset": "x64-osx-release-no-ssl-test" + }, + { + "name": "arm64-osx-debug-test", + "inherits": "macos-test", + "configurePreset": "arm64-osx-debug-test" + }, + { + "name": "arm64-osx-release-test", + "inherits": "macos-test", + "configurePreset": "arm64-osx-release-test" + }, + { + "name": "arm64-osx-debug-no-ssl-test", + "inherits": "macos-test", + "configurePreset": "arm64-osx-debug-no-ssl-test" + }, + { + "name": "arm64-osx-release-no-ssl-test", + "inherits": "macos-test", + "configurePreset": "arm64-osx-release-no-ssl-test" + } + ], + "packagePresets": [ + { + "name": "macos-common", + "hidden": true, + "generators": [ + "TGZ", + "ZIP" + ] + }, + { + "name": "x64-osx-debug", + "configurePreset": "x64-osx-debug", + "inherits": [ + "macos-common" + ] + }, + { + "name": "x64-osx-release", + "configurePreset": "x64-osx-release", + "inherits": [ + "macos-common" + ] + }, + { + "name": "arm64-osx-debug", + "configurePreset": "arm64-osx-debug", + "inherits": [ + "macos-common" + ] + }, + { + "name": "arm64-osx-release", + "configurePreset": "arm64-osx-release", + "inherits": [ + "macos-common" + ] + } + ], + "workflowPresets": [ + { + "name": "x64-osx-debug", + "steps": [ + { + "type": "configure", + "name": "x64-osx-debug" + }, + { + "type": "build", + "name": "x64-osx-debug" + } + ] + }, + { + "name": "x64-osx-debug-test", + "steps": [ + { + "type": "configure", + "name": "x64-osx-debug-test" + }, + { + "type": "build", + "name": "x64-osx-debug-test" + }, + { + "type": "test", + "name": "x64-osx-debug-test" + } + ] + }, + { + "name": "x64-osx-release", + "steps": [ + { + "type": "configure", + "name": "x64-osx-release" + }, + { + "type": "build", + "name": "x64-osx-release" + } + ] + }, + { + "name": "x64-osx-release-test", + "steps": [ + { + "type": "configure", + "name": "x64-osx-release-test" + }, + { + "type": "build", + "name": "x64-osx-release-test" + }, + { + "type": "test", + "name": "x64-osx-release-test" + } + ] + }, + { + "name": "x64-osx-debug-no-ssl-test", + "steps": [ + { + "type": "configure", + "name": "x64-osx-debug-no-ssl-test" + }, + { + "type": "build", + "name": "x64-osx-debug-no-ssl-test" + }, + { + "type": "test", + "name": "x64-osx-debug-no-ssl-test" + } + ] + }, + { + "name": "x64-osx-release-no-ssl-test", + "steps": [ + { + "type": "configure", + "name": "x64-osx-release-no-ssl-test" + }, + { + "type": "build", + "name": "x64-osx-release-no-ssl-test" + }, + { + "type": "test", + "name": "x64-osx-release-no-ssl-test" + } + ] + }, + { + "name": "arm64-osx-debug", + "steps": [ + { + "type": "configure", + "name": "arm64-osx-debug" + }, + { + "type": "build", + "name": "arm64-osx-debug" + } + ] + }, + { + "name": "arm64-osx-debug-test", + "steps": [ + { + "type": "configure", + "name": "arm64-osx-debug-test" + }, + { + "type": "build", + "name": "arm64-osx-debug-test" + }, + { + "type": "test", + "name": "arm64-osx-debug-test" + } + ] + }, + { + "name": "arm64-osx-release", + "steps": [ + { + "type": "configure", + "name": "arm64-osx-release" + }, + { + "type": "build", + "name": "arm64-osx-release" + } + ] + }, + { + "name": "arm64-osx-release-test", + "steps": [ + { + "type": "configure", + "name": "arm64-osx-release-test" + }, + { + "type": "build", + "name": "arm64-osx-release-test" + }, + { + "type": "test", + "name": "arm64-osx-release-test" + } + ] + }, + { + "name": "arm64-osx-debug-no-ssl-test", + "steps": [ + { + "type": "configure", + "name": "arm64-osx-debug-no-ssl-test" + }, + { + "type": "build", + "name": "arm64-osx-debug-no-ssl-test" + }, + { + "type": "test", + "name": "arm64-osx-debug-no-ssl-test" + } + ] + }, + { + "name": "arm64-osx-release-no-ssl-test", + "steps": [ + { + "type": "configure", + "name": "arm64-osx-release-no-ssl-test" + }, + { + "type": "build", + "name": "arm64-osx-release-no-ssl-test" + }, + { + "type": "test", + "name": "arm64-osx-release-no-ssl-test" + } + ] + } + ] +} diff --git a/cmake/presets/windows.json b/cmake/presets/windows.json index becb2134b..bebada836 100644 --- a/cmake/presets/windows.json +++ b/cmake/presets/windows.json @@ -25,6 +25,22 @@ "rhs": "Windows" } }, + { + "name": "windows-clang-cl", + "inherits": [ + "base" + ], + "hidden": true, + "cacheVariables": { + "CMAKE_C_COMPILER": "clang-cl", + "CMAKE_CXX_COMPILER": "clang-cl" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, { "name": "vcpkg-x86-windows", "hidden": true, @@ -40,7 +56,7 @@ } }, { - "name": "x86-windows-debug", + "name": "x86-windows-cl-debug", "inherits": [ "x86", "windows", @@ -49,7 +65,7 @@ ] }, { - "name": "x86-windows-debug-test", + "name": "x86-windows-cl-debug-test", "inherits": [ "x86", "windows", @@ -59,7 +75,7 @@ ] }, { - "name": "x86-windows-release", + "name": "x86-windows-cl-release", "inherits": [ "x86", "windows", @@ -68,7 +84,7 @@ ] }, { - "name": "x86-windows-release-test", + "name": "x86-windows-cl-release-test", "inherits": [ "x86", "windows", @@ -78,7 +94,7 @@ ] }, { - "name": "x64-windows-debug", + "name": "x64-windows-cl-debug", "inherits": [ "x64", "windows", @@ -87,7 +103,7 @@ ] }, { - "name": "x64-windows-debug-test", + "name": "x64-windows-cl-debug-test", "inherits": [ "x64", "windows", @@ -97,7 +113,7 @@ ] }, { - "name": "x64-windows-release", + "name": "x64-windows-cl-release", "inherits": [ "x64", "windows", @@ -106,7 +122,7 @@ ] }, { - "name": "x64-windows-release-test", + "name": "x64-windows-cl-release-test", "inherits": [ "x64", "windows", @@ -116,7 +132,7 @@ ] }, { - "name": "x64-windows-debug-static", + "name": "x64-windows-cl-debug-static", "inherits": [ "x64", "windows", @@ -126,7 +142,7 @@ ] }, { - "name": "x64-windows-release-static", + "name": "x64-windows-cl-release-static", "inherits": [ "x64", "windows", @@ -136,7 +152,7 @@ ] }, { - "name": "x64-windows-debug-no-ssl", + "name": "x64-windows-cl-debug-no-ssl", "inherits": [ "x64", "windows", @@ -146,7 +162,7 @@ ] }, { - "name": "x64-windows-release-no-ssl", + "name": "x64-windows-cl-release-no-ssl", "inherits": [ "x64", "windows", @@ -156,7 +172,7 @@ ] }, { - "name": "x64-windows-debug-static-no-ssl", + "name": "x64-windows-cl-debug-static-no-ssl", "inherits": [ "x64", "windows", @@ -167,7 +183,7 @@ ] }, { - "name": "x64-windows-release-static-no-ssl", + "name": "x64-windows-cl-release-static-no-ssl", "inherits": [ "x64", "windows", @@ -178,7 +194,7 @@ ] }, { - "name": "x64-windows-debug-no-ssl-test", + "name": "x64-windows-cl-debug-no-ssl-test", "inherits": [ "x64", "windows", @@ -189,7 +205,7 @@ ] }, { - "name": "x64-windows-release-no-ssl-test", + "name": "x64-windows-cl-release-no-ssl-test", "inherits": [ "x64", "windows", @@ -198,72 +214,156 @@ "release", "no-ssl" ] + }, + { + "name": "x64-windows-clang-debug", + "inherits": [ + "x64", + "windows-clang-cl", + "vcpkg-x64-windows", + "debug" + ] + }, + { + "name": "x64-windows-clang-debug-test", + "inherits": [ + "x64", + "windows-clang-cl", + "test", + "vcpkg-x64-windows", + "debug" + ] + }, + { + "name": "x64-windows-clang-release", + "inherits": [ + "x64", + "windows-clang-cl", + "vcpkg-x64-windows", + "release" + ] + }, + { + "name": "x64-windows-clang-release-test", + "inherits": [ + "x64", + "windows-clang-cl", + "test", + "vcpkg-x64-windows", + "release" + ] + }, + { + "name": "x64-windows-clang-debug-no-ssl-test", + "inherits": [ + "x64", + "windows-clang-cl", + "test-no-ssl", + "vcpkg-x64-windows", + "debug", + "no-ssl" + ] + }, + { + "name": "x64-windows-clang-release-no-ssl-test", + "inherits": [ + "x64", + "windows-clang-cl", + "test-no-ssl", + "vcpkg-x64-windows", + "release", + "no-ssl" + ] } ], "buildPresets": [ { - "name": "x86-windows-debug", - "configurePreset": "x86-windows-debug" + "name": "x86-windows-cl-debug", + "configurePreset": "x86-windows-cl-debug" + }, + { + "name": "x86-windows-cl-debug-test", + "configurePreset": "x86-windows-cl-debug-test" + }, + { + "name": "x86-windows-cl-release", + "configurePreset": "x86-windows-cl-release" + }, + { + "name": "x86-windows-cl-release-test", + "configurePreset": "x86-windows-cl-release-test" }, { - "name": "x86-windows-debug-test", - "configurePreset": "x86-windows-debug-test" + "name": "x64-windows-cl-debug", + "configurePreset": "x64-windows-cl-debug" }, { - "name": "x86-windows-release", - "configurePreset": "x86-windows-release" + "name": "x64-windows-cl-debug-test", + "configurePreset": "x64-windows-cl-debug-test" }, { - "name": "x86-windows-release-test", - "configurePreset": "x86-windows-release-test" + "name": "x64-windows-cl-release", + "configurePreset": "x64-windows-cl-release" }, { - "name": "x64-windows-debug", - "configurePreset": "x64-windows-debug" + "name": "x64-windows-cl-release-test", + "configurePreset": "x64-windows-cl-release-test" }, { - "name": "x64-windows-debug-test", - "configurePreset": "x64-windows-debug-test" + "name": "x64-windows-cl-debug-static", + "configurePreset": "x64-windows-cl-debug-static" }, { - "name": "x64-windows-release", - "configurePreset": "x64-windows-release" + "name": "x64-windows-cl-release-static", + "configurePreset": "x64-windows-cl-release-static" }, { - "name": "x64-windows-release-test", - "configurePreset": "x64-windows-release-test" + "name": "x64-windows-cl-debug-no-ssl", + "configurePreset": "x64-windows-cl-debug-no-ssl" }, { - "name": "x64-windows-debug-static", - "configurePreset": "x64-windows-debug-static" + "name": "x64-windows-cl-release-no-ssl", + "configurePreset": "x64-windows-cl-release-no-ssl" }, { - "name": "x64-windows-release-static", - "configurePreset": "x64-windows-release-static" + "name": "x64-windows-cl-debug-static-no-ssl", + "configurePreset": "x64-windows-cl-debug-static-no-ssl" }, { - "name": "x64-windows-debug-no-ssl", - "configurePreset": "x64-windows-debug-no-ssl" + "name": "x64-windows-cl-release-static-no-ssl", + "configurePreset": "x64-windows-cl-release-static-no-ssl" }, { - "name": "x64-windows-release-no-ssl", - "configurePreset": "x64-windows-release-no-ssl" + "name": "x64-windows-cl-debug-no-ssl-test", + "configurePreset": "x64-windows-cl-debug-no-ssl-test" }, { - "name": "x64-windows-debug-static-no-ssl", - "configurePreset": "x64-windows-debug-static-no-ssl" + "name": "x64-windows-cl-release-no-ssl-test", + "configurePreset": "x64-windows-cl-release-no-ssl-test" }, { - "name": "x64-windows-release-static-no-ssl", - "configurePreset": "x64-windows-release-static-no-ssl" + "name": "x64-windows-clang-debug", + "configurePreset": "x64-windows-clang-debug" }, { - "name": "x64-windows-debug-no-ssl-test", - "configurePreset": "x64-windows-debug-no-ssl-test" + "name": "x64-windows-clang-debug-test", + "configurePreset": "x64-windows-clang-debug-test" }, { - "name": "x64-windows-release-no-ssl-test", - "configurePreset": "x64-windows-release-no-ssl-test" + "name": "x64-windows-clang-release", + "configurePreset": "x64-windows-clang-release" + }, + { + "name": "x64-windows-clang-release-test", + "configurePreset": "x64-windows-clang-release-test" + }, + { + "name": "x64-windows-clang-debug-no-ssl-test", + "configurePreset": "x64-windows-clang-debug-no-ssl-test" + }, + { + "name": "x64-windows-clang-release-no-ssl-test", + "configurePreset": "x64-windows-clang-release-no-ssl-test" } ], "testPresets": [ @@ -275,188 +375,208 @@ } }, { - "name": "x86-windows-debug-test", + "name": "x86-windows-cl-debug-test", + "inherits": "windows-test", + "configurePreset": "x86-windows-cl-debug-test" + }, + { + "name": "x86-windows-cl-release-test", + "inherits": "windows-test", + "configurePreset": "x86-windows-cl-release-test" + }, + { + "name": "x64-windows-cl-debug-test", + "inherits": "windows-test", + "configurePreset": "x64-windows-cl-debug-test" + }, + { + "name": "x64-windows-cl-release-test", + "inherits": "windows-test", + "configurePreset": "x64-windows-cl-release-test" + }, + { + "name": "x64-windows-cl-debug-no-ssl-test", "inherits": "windows-test", - "configurePreset": "x86-windows-debug-test" + "configurePreset": "x64-windows-cl-debug-no-ssl-test" }, { - "name": "x86-windows-release-test", + "name": "x64-windows-cl-release-no-ssl-test", "inherits": "windows-test", - "configurePreset": "x86-windows-release-test" + "configurePreset": "x64-windows-cl-release-no-ssl-test" }, { - "name": "x64-windows-debug-test", + "name": "x64-windows-clang-debug-test", "inherits": "windows-test", - "configurePreset": "x64-windows-debug-test" + "configurePreset": "x64-windows-clang-debug-test" }, { - "name": "x64-windows-release-test", + "name": "x64-windows-clang-release-test", "inherits": "windows-test", - "configurePreset": "x64-windows-release-test" + "configurePreset": "x64-windows-clang-release-test" }, { - "name": "x64-windows-debug-no-ssl-test", + "name": "x64-windows-clang-debug-no-ssl-test", "inherits": "windows-test", - "configurePreset": "x64-windows-debug-no-ssl-test" + "configurePreset": "x64-windows-clang-debug-no-ssl-test" }, { - "name": "x64-windows-release-no-ssl-test", + "name": "x64-windows-clang-release-no-ssl-test", "inherits": "windows-test", - "configurePreset": "x64-windows-release-no-ssl-test" + "configurePreset": "x64-windows-clang-release-no-ssl-test" } ], "workflowPresets": [ { - "name": "x86-windows-debug", + "name": "x86-windows-cl-debug", "steps": [ { "type": "configure", - "name": "x86-windows-debug" + "name": "x86-windows-cl-debug" }, { "type": "build", - "name": "x86-windows-debug" + "name": "x86-windows-cl-debug" } ] }, { - "name": "x86-windows-debug-test", + "name": "x86-windows-cl-debug-test", "steps": [ { "type": "configure", - "name": "x86-windows-debug-test" + "name": "x86-windows-cl-debug-test" }, { "type": "build", - "name": "x86-windows-debug-test" + "name": "x86-windows-cl-debug-test" }, { "type": "test", - "name": "x86-windows-debug-test" + "name": "x86-windows-cl-debug-test" } ] }, { - "name": "x86-windows-release", + "name": "x86-windows-cl-release", "steps": [ { "type": "configure", - "name": "x86-windows-release" + "name": "x86-windows-cl-release" }, { "type": "build", - "name": "x86-windows-release" + "name": "x86-windows-cl-release" } ] }, { - "name": "x86-windows-release-test", + "name": "x86-windows-cl-release-test", "steps": [ { "type": "configure", - "name": "x86-windows-release-test" + "name": "x86-windows-cl-release-test" }, { "type": "build", - "name": "x86-windows-release-test" + "name": "x86-windows-cl-release-test" }, { "type": "test", - "name": "x86-windows-release-test" + "name": "x86-windows-cl-release-test" } ] }, { - "name": "x64-windows-debug", + "name": "x64-windows-cl-debug", "steps": [ { "type": "configure", - "name": "x64-windows-debug" + "name": "x64-windows-cl-debug" }, { "type": "build", - "name": "x64-windows-debug" + "name": "x64-windows-cl-debug" } ] }, { - "name": "x64-windows-debug-test", + "name": "x64-windows-cl-debug-test", "steps": [ { "type": "configure", - "name": "x64-windows-debug-test" + "name": "x64-windows-cl-debug-test" }, { "type": "build", - "name": "x64-windows-debug-test" + "name": "x64-windows-cl-debug-test" }, { "type": "test", - "name": "x64-windows-debug-test" + "name": "x64-windows-cl-debug-test" } ] }, { - "name": "x64-windows-release", + "name": "x64-windows-cl-release", "steps": [ { "type": "configure", - "name": "x64-windows-release" + "name": "x64-windows-cl-release" }, { "type": "build", - "name": "x64-windows-release" + "name": "x64-windows-cl-release" } ] }, { - "name": "x64-windows-release-test", + "name": "x64-windows-cl-release-test", "steps": [ { "type": "configure", - "name": "x64-windows-release-test" + "name": "x64-windows-cl-release-test" }, { "type": "build", - "name": "x64-windows-release-test" + "name": "x64-windows-cl-release-test" }, { "type": "test", - "name": "x64-windows-release-test" + "name": "x64-windows-cl-release-test" } ] }, { - "name": "x64-windows-debug-no-ssl-test", + "name": "x64-windows-cl-debug-no-ssl-test", "steps": [ { "type": "configure", - "name": "x64-windows-debug-no-ssl-test" + "name": "x64-windows-cl-debug-no-ssl-test" }, { "type": "build", - "name": "x64-windows-debug-no-ssl-test" + "name": "x64-windows-cl-debug-no-ssl-test" }, { "type": "test", - "name": "x64-windows-debug-no-ssl-test" + "name": "x64-windows-cl-debug-no-ssl-test" } ] }, { - "name": "x64-windows-release-no-ssl-test", + "name": "x64-windows-cl-release-no-ssl-test", "steps": [ { "type": "configure", - "name": "x64-windows-release-no-ssl-test" + "name": "x64-windows-cl-release-no-ssl-test" }, { "type": "build", - "name": "x64-windows-release-no-ssl-test" + "name": "x64-windows-cl-release-no-ssl-test" }, { "type": "test", - "name": "x64-windows-release-no-ssl-test" + "name": "x64-windows-cl-release-no-ssl-test" } ] } From 75f42ef60cf4d6ab13f59887c00c8adb8e139493 Mon Sep 17 00:00:00 2001 From: Prachya Saechua Date: Thu, 19 Feb 2026 17:19:17 +0700 Subject: [PATCH 02/25] Fix narrow method call in ResponseCorrelatorTest to use reference for MyTransport Signed-off-by: Prachya Saechua --- .../activemq/transport/correlator/ResponseCorrelatorTest.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/activemq-cpp/src/test/activemq/transport/correlator/ResponseCorrelatorTest.cpp b/activemq-cpp/src/test/activemq/transport/correlator/ResponseCorrelatorTest.cpp index dee65c05b..6743d0981 100644 --- a/activemq-cpp/src/test/activemq/transport/correlator/ResponseCorrelatorTest.cpp +++ b/activemq-cpp/src/test/activemq/transport/correlator/ResponseCorrelatorTest.cpp @@ -535,7 +535,8 @@ TEST_F(ResponseCorrelatorTest, testNarrow){ Pointer transport(new MyTransport()); ResponseCorrelator correlator(transport); - Transport* narrowed = correlator.narrow(typeid( *transport )); + MyTransport& transportRef = *transport; + Transport* narrowed = correlator.narrow(typeid( transportRef )); ASSERT_TRUE(narrowed == transport); narrowed = correlator.narrow(typeid(std::string())); From fc89f5efd3e22d8c4d0b01b6bb152aedcc4dd216 Mon Sep 17 00:00:00 2001 From: Prachya Saechua Date: Thu, 19 Feb 2026 17:21:01 +0700 Subject: [PATCH 03/25] Fix include directive for sys/sysctl.h on macOS Signed-off-by: Prachya Saechua --- activemq-cpp/src/main/decaf/lang/System.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/activemq-cpp/src/main/decaf/lang/System.cpp b/activemq-cpp/src/main/decaf/lang/System.cpp index 9b301e456..4083d2c9a 100644 --- a/activemq-cpp/src/main/decaf/lang/System.cpp +++ b/activemq-cpp/src/main/decaf/lang/System.cpp @@ -50,6 +50,8 @@ #endif #ifdef HAVE_SYS_SYSCTL_H #include +#elif defined(__APPLE__) +#include #endif #ifdef HAVE_STRING_H #include From 846481d2db033c54802bac031b00c1c8d150bb81 Mon Sep 17 00:00:00 2001 From: Prachya Saechua Date: Thu, 19 Feb 2026 17:36:54 +0700 Subject: [PATCH 04/25] Fix NullPointerException test assertions in StringTest Signed-off-by: Prachya Saechua --- activemq-cpp/src/test/decaf/lang/StringTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activemq-cpp/src/test/decaf/lang/StringTest.cpp b/activemq-cpp/src/test/decaf/lang/StringTest.cpp index 1eb01446e..687cb0837 100644 --- a/activemq-cpp/src/test/decaf/lang/StringTest.cpp +++ b/activemq-cpp/src/test/decaf/lang/StringTest.cpp @@ -978,7 +978,7 @@ TEST_F(StringTest, testOperatorLessCString) { ASSERT_TRUE(upper < lower) << ("Failed comparison"); ASSERT_TRUE(!(upper < "HELLOWORLD")) << ("Failed comparison"); - ASSERT_THROW((upper < NULL), NullPointerException) << ("Should have thrown a NullPointerException"); + ASSERT_THROW((void)(upper < NULL), NullPointerException) << ("Should have thrown a NullPointerException"); // test lhs as std::string ASSERT_TRUE("aaab" < String("aaac")) << ("Failed comparison"); @@ -1018,7 +1018,7 @@ TEST_F(StringTest, testOperatorGreaterCString) { ASSERT_TRUE(lower > upper) << ("Failed comparison"); ASSERT_TRUE(!(lower > "helloworld")) << ("Failed comparison"); - ASSERT_THROW((lower < NULL), NullPointerException) << ("Should have thrown a NullPointerException"); + ASSERT_THROW((void)(lower < NULL), NullPointerException) << ("Should have thrown a NullPointerException"); // test lhs as C string ASSERT_TRUE("aaac" > String("aaab")) << ("Failed comparison"); From ffca2e74db1bf22d854327767b97f072de89fa55 Mon Sep 17 00:00:00 2001 From: Prachya Saechua Date: Thu, 19 Feb 2026 18:29:23 +0700 Subject: [PATCH 05/25] Refactor getBrokerURL method to override in OpenWireMessageListenerRedeliveryTest and OpenwireNonBlockingRedeliveryTest Signed-off-by: Prachya Saechua --- .../test/openwire/OpenWireMessageListenerRedeliveryTest.cpp | 2 +- .../test/openwire/OpenwireNonBlockingRedeliveryTest.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/activemq-cpp/src/test-integration/activemq/test/openwire/OpenWireMessageListenerRedeliveryTest.cpp b/activemq-cpp/src/test-integration/activemq/test/openwire/OpenWireMessageListenerRedeliveryTest.cpp index b61ef25fe..b6d81582f 100644 --- a/activemq-cpp/src/test-integration/activemq/test/openwire/OpenWireMessageListenerRedeliveryTest.cpp +++ b/activemq-cpp/src/test-integration/activemq/test/openwire/OpenWireMessageListenerRedeliveryTest.cpp @@ -25,7 +25,7 @@ namespace openwire { public: void SetUp() override {} void TearDown() override {} - virtual std::string getBrokerURL() const { + std::string getBrokerURL() const override { return activemq::util::IntegrationCommon::getInstance().getOpenwireURL(); } }; diff --git a/activemq-cpp/src/test-integration/activemq/test/openwire/OpenwireNonBlockingRedeliveryTest.cpp b/activemq-cpp/src/test-integration/activemq/test/openwire/OpenwireNonBlockingRedeliveryTest.cpp index 58bc2836a..a5572e27b 100644 --- a/activemq-cpp/src/test-integration/activemq/test/openwire/OpenwireNonBlockingRedeliveryTest.cpp +++ b/activemq-cpp/src/test-integration/activemq/test/openwire/OpenwireNonBlockingRedeliveryTest.cpp @@ -25,7 +25,7 @@ namespace openwire { public: void SetUp() override {} void TearDown() override {} - virtual std::string getBrokerURL() const { + std::string getBrokerURL() const override { return activemq::util::IntegrationCommon::getInstance().getOpenwireURL() + "?connection.nonBlockingRedelivery=true"; } From 89e872ec6882f4c21ab9ab86120d093d028c6fe3 Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Thu, 19 Feb 2026 19:07:49 +0700 Subject: [PATCH 06/25] Enhance test classes to override getBrokerURL method - Updated multiple test classes in the OpenWire and OpenWire SSL namespaces to override the getBrokerURL method instead of using the virtual keyword. This change improves clarity and ensures proper polymorphic behavior. - Added installation instructions for build tools in the README for macOS users. Signed-off-by: blackb1rd --- README.md | 12 ++++++++++-- .../OpenWireCmsSendWithAsyncCallbackTest.cpp | 2 +- .../test/openwire/OpenWireRedeliveryPolicyTest.cpp | 2 +- .../activemq/test/openwire/OpenwireAdvisoryTest.cpp | 2 +- .../test/openwire/OpenwireAsyncSenderTest.cpp | 2 +- .../activemq/test/openwire/OpenwireClientAckTest.cpp | 2 +- .../activemq/test/openwire/OpenwireDurableTest.cpp | 4 ++-- .../test/openwire/OpenwireEnhancedConnectionTest.cpp | 2 +- .../test/openwire/OpenwireIndividualAckTest.cpp | 2 +- .../test/openwire/OpenwireJmsMessageGroupsTest.cpp | 2 +- .../test/openwire/OpenwireJmsRecoverTest.cpp | 2 +- .../test/openwire/OpenwireMessagePriorityTest.cpp | 2 +- .../test/openwire/OpenwireMessageSelectorTest.cpp | 2 +- .../test/openwire/OpenwireOptimizedAckTest.cpp | 2 +- .../test/openwire/OpenwireQueueBrowserTest.cpp | 2 +- .../test/openwire/OpenwireSimpleRollbackTest.cpp | 2 +- .../activemq/test/openwire/OpenwireSimpleTest.cpp | 2 +- .../test/openwire/OpenwireSlowListenerTest.cpp | 2 +- .../test/openwire/OpenwireTempDestinationTest.cpp | 2 +- .../test/openwire/OpenwireTransactionTest.cpp | 2 +- .../test/openwire/OpenwireXATransactionsTest.cpp | 2 +- .../test/openwire_ssl/OpenwireSslAdvisoryTest.cpp | 2 +- .../test/openwire_ssl/OpenwireSslAsyncSenderTest.cpp | 2 +- .../test/openwire_ssl/OpenwireSslClientAckTest.cpp | 2 +- .../OpenwireSslCmsSendWithAsyncCallbackTest.cpp | 2 +- .../test/openwire_ssl/OpenwireSslDurableTest.cpp | 4 ++-- .../OpenwireSslEnhancedConnectionTest.cpp | 2 +- .../openwire_ssl/OpenwireSslIndividualAckTest.cpp | 2 +- .../openwire_ssl/OpenwireSslJmsMessageGroupsTest.cpp | 2 +- .../test/openwire_ssl/OpenwireSslJmsRecoverTest.cpp | 2 +- .../OpenwireSslMessageListenerRedeliveryTest.cpp | 2 +- .../openwire_ssl/OpenwireSslMessagePriorityTest.cpp | 2 +- .../openwire_ssl/OpenwireSslMessageSelectorTest.cpp | 2 +- .../OpenwireSslNonBlockingRedeliveryTest.cpp | 2 +- .../openwire_ssl/OpenwireSslOptimizedAckTest.cpp | 2 +- .../openwire_ssl/OpenwireSslQueueBrowserTest.cpp | 2 +- .../openwire_ssl/OpenwireSslRedeliveryPolicyTest.cpp | 2 +- .../openwire_ssl/OpenwireSslSimpleRollbackTest.cpp | 2 +- .../test/openwire_ssl/OpenwireSslSimpleTest.cpp | 2 +- .../openwire_ssl/OpenwireSslSlowListenerTest.cpp | 2 +- .../openwire_ssl/OpenwireSslTempDestinationTest.cpp | 2 +- .../test/openwire_ssl/OpenwireSslTransactionTest.cpp | 2 +- .../openwire_ssl/OpenwireSslXATransactionsTest.cpp | 2 +- .../activemq/test/stomp/StompAdvisoryTest.cpp | 2 +- .../activemq/test/stomp/StompAsyncSenderTest.cpp | 2 +- .../activemq/test/stomp/StompBulkMessageTest.cpp | 2 +- .../test/stomp/StompCmsConnectionStartStopTest.cpp | 2 +- .../activemq/test/stomp/StompCmsTemplateTest.cpp | 2 +- .../activemq/test/stomp/StompDurableTest.cpp | 4 ++-- .../activemq/test/stomp/StompExpirationTest.cpp | 2 +- .../test/stomp/StompJmsMessageGroupsTest.cpp | 2 +- .../activemq/test/stomp/StompSimpleRollbackTest.cpp | 2 +- .../activemq/test/stomp/StompSimpleTest.cpp | 2 +- .../activemq/test/stomp/StompSlowListenerTest.cpp | 2 +- .../activemq/test/stomp/StompTransactionTest.cpp | 2 +- 55 files changed, 67 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 83b5817a2..950c8769d 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,15 @@ Presets follow the naming pattern `---[- **Note:** Clang is provided by Xcode Command Line Tools. Install them with `xcode-select --install` if not already installed. + +2. Configure the project (Apple Silicon): ```bash cmake --preset arm64-osx-debug-test @@ -166,7 +174,7 @@ Presets follow the naming pattern `---[-getConnection()->getClientID(); } }; diff --git a/activemq-cpp/src/test-integration/activemq/test/stomp/StompExpirationTest.cpp b/activemq-cpp/src/test-integration/activemq/test/stomp/StompExpirationTest.cpp index 4d4f4bce9..e8075244e 100644 --- a/activemq-cpp/src/test-integration/activemq/test/stomp/StompExpirationTest.cpp +++ b/activemq-cpp/src/test-integration/activemq/test/stomp/StompExpirationTest.cpp @@ -24,7 +24,7 @@ namespace stomp{ public: StompExpirationTest(); virtual ~StompExpirationTest(); - virtual std::string getBrokerURL() const { + std::string getBrokerURL() const override { return activemq::util::IntegrationCommon::getInstance().getStompURL(); } }; diff --git a/activemq-cpp/src/test-integration/activemq/test/stomp/StompJmsMessageGroupsTest.cpp b/activemq-cpp/src/test-integration/activemq/test/stomp/StompJmsMessageGroupsTest.cpp index de3772b9d..79dc4bb4a 100644 --- a/activemq-cpp/src/test-integration/activemq/test/stomp/StompJmsMessageGroupsTest.cpp +++ b/activemq-cpp/src/test-integration/activemq/test/stomp/StompJmsMessageGroupsTest.cpp @@ -24,7 +24,7 @@ namespace stomp { public: StompJmsMessageGroupsTest(); virtual ~StompJmsMessageGroupsTest(); - virtual std::string getBrokerURL() const { + std::string getBrokerURL() const override { return activemq::util::IntegrationCommon::getInstance().getStompURL(); } }; diff --git a/activemq-cpp/src/test-integration/activemq/test/stomp/StompSimpleRollbackTest.cpp b/activemq-cpp/src/test-integration/activemq/test/stomp/StompSimpleRollbackTest.cpp index 7df7ad117..47c4b7b20 100644 --- a/activemq-cpp/src/test-integration/activemq/test/stomp/StompSimpleRollbackTest.cpp +++ b/activemq-cpp/src/test-integration/activemq/test/stomp/StompSimpleRollbackTest.cpp @@ -24,7 +24,7 @@ namespace stomp{ public: StompSimpleRollbackTest(); virtual ~StompSimpleRollbackTest(); - virtual std::string getBrokerURL() const { + std::string getBrokerURL() const override { return activemq::util::IntegrationCommon::getInstance().getStompURL(); } }; diff --git a/activemq-cpp/src/test-integration/activemq/test/stomp/StompSimpleTest.cpp b/activemq-cpp/src/test-integration/activemq/test/stomp/StompSimpleTest.cpp index 4b85c2402..cbea7e42e 100644 --- a/activemq-cpp/src/test-integration/activemq/test/stomp/StompSimpleTest.cpp +++ b/activemq-cpp/src/test-integration/activemq/test/stomp/StompSimpleTest.cpp @@ -24,7 +24,7 @@ namespace stomp{ public: StompSimpleTest(); virtual ~StompSimpleTest(); - virtual std::string getBrokerURL() const { + std::string getBrokerURL() const override { return activemq::util::IntegrationCommon::getInstance().getStompURL(); } }; diff --git a/activemq-cpp/src/test-integration/activemq/test/stomp/StompSlowListenerTest.cpp b/activemq-cpp/src/test-integration/activemq/test/stomp/StompSlowListenerTest.cpp index f52dc5688..30405333a 100644 --- a/activemq-cpp/src/test-integration/activemq/test/stomp/StompSlowListenerTest.cpp +++ b/activemq-cpp/src/test-integration/activemq/test/stomp/StompSlowListenerTest.cpp @@ -24,7 +24,7 @@ namespace stomp{ public: StompSlowListenerTest(); virtual ~StompSlowListenerTest(); - virtual std::string getBrokerURL() const { + std::string getBrokerURL() const override { return activemq::util::IntegrationCommon::getInstance().getStompURL(); } }; diff --git a/activemq-cpp/src/test-integration/activemq/test/stomp/StompTransactionTest.cpp b/activemq-cpp/src/test-integration/activemq/test/stomp/StompTransactionTest.cpp index 58d027dd5..9af1c4ffc 100644 --- a/activemq-cpp/src/test-integration/activemq/test/stomp/StompTransactionTest.cpp +++ b/activemq-cpp/src/test-integration/activemq/test/stomp/StompTransactionTest.cpp @@ -24,7 +24,7 @@ namespace stomp{ public: StompTransactionTest(); virtual ~StompTransactionTest(); - virtual std::string getBrokerURL() const { + std::string getBrokerURL() const override { return activemq::util::IntegrationCommon::getInstance().getStompURL(); } }; From 371b784e32ae12328e8fa54c5fc0c2c52c09f3c7 Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Thu, 19 Feb 2026 19:11:53 +0700 Subject: [PATCH 07/25] Update README.md for SSL integration tests and remove outdated documentation Signed-off-by: blackb1rd --- README.md | 70 ++++++++++++---- docker/ssl/QUICKSTART.md | 26 ------ docker/ssl/README.md | 176 --------------------------------------- 3 files changed, 53 insertions(+), 219 deletions(-) delete mode 100644 docker/ssl/QUICKSTART.md delete mode 100644 docker/ssl/README.md diff --git a/README.md b/README.md index 950c8769d..e2a294d87 100644 --- a/README.md +++ b/README.md @@ -249,34 +249,45 @@ Or use the CMake helper target: cmake --build --preset --target integration-full ``` -### 3.3 SSL Integration Tests (Linux only) +### 3.3 SSL Integration Tests -SSL integration tests provide **comprehensive validation** of the SSL/TLS transport layer against an SSL-enabled ActiveMQ broker. The SSL test suite mirrors the complete OpenWire test suite (29 tests) to ensure SSL transport works for all features. +SSL integration tests validate the SSL/TLS transport layer against an SSL-enabled ActiveMQ broker. The SSL test suite mirrors the complete OpenWire test suite (29 tests). CI runs these on Linux; they can also be run locally on any platform with Docker. + +**How it works:** running `docker compose --profile ssl up` starts a `ssl-cert-generator` container first. It checks whether valid certificates already exist; if they are missing or expiring within 30 days it generates new ones, then exits. The `activemq-ssl` broker starts only after certificate generation succeeds. ```bash -# Start the SSL-enabled broker (certificates are generated automatically) +# Start the SSL-enabled broker (certificates auto-generated on first run) docker compose --profile ssl up -d -# Run all OpenWire SSL integration tests (29 comprehensive tests) +# View logs (cert generator + broker) +docker compose --profile ssl logs -f + +# Run all OpenWire SSL integration tests (29 tests) SSL_CERT_FILE=docker/ssl/certs/ca.pem ctest --preset -L integration-openwire-ssl --output-on-failure # Stop the broker docker compose --profile ssl down ``` -**SSL Test Coverage:** -- All acknowledgment modes (client, individual, optimized) -- Advisory messages -- Async sending and callbacks -- Message selectors and groups -- Durable subscriptions -- Transactions (local and XA) -- Redelivery policies and session recovery -- Temporary destinations -- Message compression and priority -- Queue browsing and virtual topics -- Slow consumers and expiration -- Enhanced connection features +**Generated certificates** (written to `docker/ssl/certs/` on first start): + +| File | Description | +|------|-------------| +| `ca.pem` | CA certificate — passed to the client via `SSL_CERT_FILE` | +| `ca-key.pem` | CA private key — used only during cert generation | +| `broker.p12` | Broker keystore (PKCS12) — loaded by ActiveMQ | +| `broker-truststore.p12` | Broker truststore (PKCS12) — loaded by ActiveMQ | + +Certificates are valid for 10 years and regenerate automatically when missing or expiring within 30 days. To force regeneration: + +```bash +rm -rf docker/ssl/certs/*.pem docker/ssl/certs/*.p12 +docker compose --profile ssl up -d +``` + +**SSL Test Coverage:** All acknowledgment modes, advisory messages, async sending and callbacks, message selectors and groups, durable subscriptions, transactions (local and XA), redelivery policies, session recovery, temporary destinations, message compression and priority, queue browsing, virtual topics, slow consumers, expiration, and enhanced connection features. + +> **Security note:** The generated certificates are self-signed and intended for testing only. The keystore password is `password` and should never be used in production. For production use, obtain certificates from a trusted CA. ### 3.4 Integration Benchmark Tests @@ -414,3 +425,28 @@ If preset is not recognized: - Ensure you're in the project root directory - Check `CMakePresets.json` exists - Update CMake to version 3.27 or later (3.31+ on Windows) + +### 10.4 SSL Test Failures + +If SSL integration tests fail: + +1. Verify certificates were generated: `ls docker/ssl/certs/` +2. Confirm the SSL broker is running: `docker compose --profile ssl ps` +3. Check broker logs: `docker compose --profile ssl logs activemq-ssl` +4. Check certificate validity: `openssl x509 -in docker/ssl/certs/ca.pem -noout -dates` +5. Ensure `SSL_CERT_FILE` points to `docker/ssl/certs/ca.pem` when running tests + +If port 61617 is already in use, update the port mapping in `docker-compose.yml`: + +```yaml +ports: + - "127.0.0.1:61627:61617" # map to a different local port +``` + +To force certificate regeneration: + +```bash +docker compose --profile ssl down +rm -rf docker/ssl/certs/*.pem docker/ssl/certs/*.p12 +docker compose --profile ssl up -d +``` diff --git a/docker/ssl/QUICKSTART.md b/docker/ssl/QUICKSTART.md deleted file mode 100644 index b1c742a5e..000000000 --- a/docker/ssl/QUICKSTART.md +++ /dev/null @@ -1,26 +0,0 @@ -# SSL Testing Quick Start - -## Start ActiveMQ with SSL - -```bash -docker compose --profile ssl up -``` - -Certificates are generated automatically. The SSL broker will be available at `ssl://localhost:61617` - -## Run SSL Tests - -```bash -cmake --build --preset x86-windows-debug-test -ctest --preset x86-windows-debug-test -R SSL -``` - -## Stop the Broker - -```bash -docker compose --profile ssl down -``` - -## Need More Info? - -See [README.md](README.md) for detailed documentation, troubleshooting, and advanced usage. diff --git a/docker/ssl/README.md b/docker/ssl/README.md deleted file mode 100644 index a1c6ef61c..000000000 --- a/docker/ssl/README.md +++ /dev/null @@ -1,176 +0,0 @@ -# SSL Certificate Generation for ActiveMQ Testing - -This directory contains scripts to generate self-signed SSL certificates for ActiveMQ integration testing. - -## Quick Start - -Start the SSL broker with automatic certificate generation: - -```bash -docker compose --profile ssl up -``` - -That's it! The `ssl-cert-generator` service will: -1. Check if valid certificates already exist -2. Generate new certificates if needed (or if they're expiring soon) -3. Start ActiveMQ SSL broker on `ssl://localhost:61617` - -**Prerequisites:** -- Docker Desktop (Windows/macOS) or Docker Engine (Linux) -- Docker Compose V2 - -**Tip:** See [QUICKSTART.md](QUICKSTART.md) for just the essential commands. - -## Generated Files - -The scripts create the following files in the `certs/` directory: - -| File | Description | Used By | -|------|-------------|---------| -| `ca.pem` | CA certificate (PEM format) | C++ client for trust verification | -| `ca-key.pem` | CA private key | Certificate signing (not used in tests) | -| `broker.p12` | Broker keystore (PKCS12) | ActiveMQ broker (server certificate) | -| `broker-truststore.p12` | Broker truststore (PKCS12) | ActiveMQ broker (CA trust) | -| `broker-cert.pem` | Broker certificate (PEM) | Intermediate file | -| `broker-key.pem` | Broker private key (PEM) | Intermediate file | - -**Password:** All keystores use the password `password` - -**Validity:** All certificates are valid for 3650 days (10 years) - -**Subject Alternative Names:** The broker certificate includes: -- DNS: `localhost` -- IP: `127.0.0.1` - -## How It Works - -When you run `docker compose --profile ssl up`: - -1. The `ssl-cert-generator` service starts first using the `alpine/openssl` image -2. It runs [generate-certs-entrypoint.sh](generate-certs-entrypoint.sh) inside the container -3. The script checks if valid certificates exist (valid for at least 30 more days) -4. If certificates are missing or expiring, it generates new ones -5. Once complete, the service exits successfully -6. The `activemq-ssl` service starts only after certificate generation succeeds -7. ActiveMQ loads the certificates from the shared `certs/` volume - -## Common Operations - -### Viewing Logs - -```bash -# View certificate generator logs -docker compose --profile ssl logs ssl-cert-generator - -# View ActiveMQ SSL broker logs -docker compose --profile ssl logs activemq-ssl - -# Follow logs in real-time -docker compose --profile ssl logs -f -``` - -### Stopping the Broker - -```bash -# Stop and remove containers -docker compose --profile ssl down - -# Stop but keep containers -docker compose --profile ssl stop -``` - -### Regenerating Certificates - -Certificates are valid for 10 years and automatically regenerate when: -- They don't exist -- They're expiring within 30 days - -To force regeneration: - -```bash -# Stop the broker -docker compose --profile ssl down - -# Delete certificates -rm -rf docker/ssl/certs/*.pem docker/ssl/certs/*.p12 -# On Windows PowerShell: Remove-Item docker/ssl/certs/*.pem,docker/ssl/certs/*.p12 - -# Restart (will regenerate automatically) -docker compose --profile ssl up -``` - -### Running Tests - -The SSL integration tests provide comprehensive validation of the SSL/TLS transport layer (29 tests total, mirroring all OpenWire test functionality). - -```bash -# Build tests -cmake --build --preset x86-windows-debug-test - -# Run all SSL integration tests (29 tests) -SSL_CERT_FILE=docker/ssl/certs/ca.pem ctest --preset x86-windows-debug-test -L integration-openwire-ssl --output-on-failure - -# Or run all integration tests (OpenWire + OpenWire SSL + STOMP) -ctest --preset x86-windows-debug-test -L integration --output-on-failure -``` - -**SSL Test Coverage:** -- ✅ All acknowledgment modes (client, individual, optimized) -- ✅ Advisory messages -- ✅ Async sending and callbacks -- ✅ Message selectors and groups -- ✅ Durable subscriptions -- ✅ Transactions (local and XA) -- ✅ Redelivery policies and session recovery -- ✅ Temporary destinations -- ✅ Message compression and priority -- ✅ Queue browsing and virtual topics -- ✅ Slow consumers and expiration -- ✅ Enhanced connection features - -## Troubleshooting - -### "No such file or directory" error -Make sure you're running from the project root directory (where `docker-compose.yml` is located). - -### Docker not found -Install Docker Desktop and ensure it's running: -```bash -docker --version -docker ps -``` - -### Certificate validation failures in tests -1. Check certificates were generated: `ls docker/ssl/certs/` -2. Verify broker is running: `docker compose --profile ssl ps` -3. Check broker logs: `docker compose --profile ssl logs activemq-ssl` -4. Verify certificate expiry: `openssl x509 -in docker/ssl/certs/ca.pem -noout -dates` - -### Port already in use (61617) -Another service is using port 61617. Change the port mapping in `docker-compose.yml`: -```yaml -ports: - - "127.0.0.1:61627:61617" # Map to different local port -``` - -## Integration with Tests - -The generated certificates are used by: - -1. **ActiveMQ Broker** (via `activemq-ssl.xml`): - - Keystore: `broker.p12` - - Truststore: `broker-truststore.p12` - -2. **C++ Client Tests** (via SSL tests): - - Trust certificate: `ca.pem` - -## Security Notes - -⚠️ **These certificates are for testing only!** - -- Self-signed certificates should never be used in production -- The keystore password is hardcoded and publicly known -- Certificates are checked into source control -- No certificate revocation mechanism exists - -For production use, obtain certificates from a trusted Certificate Authority (CA). From 921fa00875593ffc1ca2e0050e1f633f73e08f77 Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Thu, 19 Feb 2026 19:13:34 +0700 Subject: [PATCH 08/25] Update README.md to enhance Table of Contents with additional sections for quick start and troubleshooting Signed-off-by: blackb1rd --- README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/README.md b/README.md index e2a294d87..ae0016d5c 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,36 @@ NeoActiveMQ CPP is a modernized C++17 messaging library that can use multiple protocols to talk to a MOM (e.g. ActiveMQ). This is a fork of Apache ActiveMQ CPP with updated build system and modern C++ standards. +## Table of Contents + +- [1. Prerequisites](#1-prerequisites) + - [1.1 Required Tools](#11-required-tools) + - [1.2 Automatic Dependency Management](#12-automatic-dependency-management) +- [2. Building with CMake Presets](#2-building-with-cmake-presets) + - [2.1 Available Presets](#21-available-presets) + - [2.2 Quick Start - Windows](#22-quick-start---windows) + - [2.3 Quick Start - Linux](#23-quick-start---linux) + - [2.4 Quick Start - macOS](#24-quick-start---macos) + - [2.5 Installation](#25-installation) +- [3. Running Tests](#3-running-tests) + - [3.1 Unit Tests](#31-unit-tests) + - [3.2 Integration Tests](#32-integration-tests) + - [3.3 SSL Integration Tests](#33-ssl-integration-tests) + - [3.4 Integration Benchmark Tests](#34-integration-benchmark-tests) +- [4. Examples](#4-examples) +- [5. Using in Your Project](#5-using-in-your-project) + - [5.1 With CMake](#51-with-cmake) + - [5.2 Build Options](#52-build-options) +- [6. Project Structure](#6-project-structure) +- [7. Compiler Strategy](#7-compiler-strategy) +- [8. Notes for Windows Users](#8-notes-for-windows-users) +- [9. Notes for Linux/macOS Users](#9-notes-for-linuxmacos-users) +- [10. Troubleshooting](#10-troubleshooting) + - [10.1 CMake Configuration Fails](#101-cmake-configuration-fails) + - [10.2 Build Fails](#102-build-fails) + - [10.3 Preset Not Found](#103-preset-not-found) + - [10.4 SSL Test Failures](#104-ssl-test-failures) + ## 1. Prerequisites ### 1.1 Required Tools From a5be5755d84e9eafed86aa48223be01d08e3c80d Mon Sep 17 00:00:00 2001 From: Prachya Saechua Date: Thu, 19 Feb 2026 19:42:05 +0700 Subject: [PATCH 09/25] Remove outdated macOS build configurations from CI workflow Signed-off-by: Prachya Saechua --- .github/workflows/ci.yml | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 77e5b51d7..7e03f37ce 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -837,10 +837,6 @@ jobs: fail-fast: false matrix: config: - - { runner: macos-13, preset: x64-osx-debug-test, arch: x64, build_type: Debug, ssl: true } - - { runner: macos-13, preset: x64-osx-release-test, arch: x64, build_type: Release, ssl: true } - - { runner: macos-13, preset: x64-osx-debug-no-ssl-test, arch: x64, build_type: Debug, ssl: false } - - { runner: macos-13, preset: x64-osx-release-no-ssl-test, arch: x64, build_type: Release, ssl: false } - { runner: macos-latest, preset: arm64-osx-debug-test, arch: arm64, build_type: Debug, ssl: true } - { runner: macos-latest, preset: arm64-osx-release-test, arch: arm64, build_type: Release, ssl: true } - { runner: macos-latest, preset: arm64-osx-debug-no-ssl-test, arch: arm64, build_type: Debug, ssl: false } @@ -905,10 +901,6 @@ jobs: fail-fast: false matrix: config: - - { runner: macos-13, preset: x64-osx-debug-test, arch: x64, build_type: Debug, ssl: true } - - { runner: macos-13, preset: x64-osx-release-test, arch: x64, build_type: Release, ssl: true } - - { runner: macos-13, preset: x64-osx-debug-no-ssl-test, arch: x64, build_type: Debug, ssl: false } - - { runner: macos-13, preset: x64-osx-release-no-ssl-test, arch: x64, build_type: Release, ssl: false } - { runner: macos-latest, preset: arm64-osx-debug-test, arch: arm64, build_type: Debug, ssl: true } - { runner: macos-latest, preset: arm64-osx-release-test, arch: arm64, build_type: Release, ssl: true } - { runner: macos-latest, preset: arm64-osx-debug-no-ssl-test, arch: arm64, build_type: Debug, ssl: false } @@ -974,10 +966,6 @@ jobs: fail-fast: false matrix: config: - - { runner: macos-13, preset: x64-osx-debug-test, arch: x64, build_type: Debug, ssl: true } - - { runner: macos-13, preset: x64-osx-release-test, arch: x64, build_type: Release, ssl: true } - - { runner: macos-13, preset: x64-osx-debug-no-ssl-test, arch: x64, build_type: Debug, ssl: false } - - { runner: macos-13, preset: x64-osx-release-no-ssl-test, arch: x64, build_type: Release, ssl: false } - { runner: macos-latest, preset: arm64-osx-debug-test, arch: arm64, build_type: Debug, ssl: true } - { runner: macos-latest, preset: arm64-osx-release-test, arch: arm64, build_type: Release, ssl: true } - { runner: macos-latest, preset: arm64-osx-debug-no-ssl-test, arch: arm64, build_type: Debug, ssl: false } @@ -1040,13 +1028,6 @@ jobs: fail-fast: false matrix: config: - # Intel x64 builds - - { runner: macos-13, preset: x64-osx-debug, arch: x64 } - - { runner: macos-13, preset: x64-osx-release, arch: x64 } - - { runner: macos-13, preset: x64-osx-debug-static, arch: x64 } - - { runner: macos-13, preset: x64-osx-release-static, arch: x64 } - - { runner: macos-13, preset: x64-osx-debug-no-ssl, arch: x64 } - - { runner: macos-13, preset: x64-osx-release-no-ssl, arch: x64 } # Apple Silicon arm64 builds - { runner: macos-latest, preset: arm64-osx-debug, arch: arm64 } - { runner: macos-latest, preset: arm64-osx-release, arch: arm64 } From e9d8364e9db84a301ec3e1e25d9a073767aea356 Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Thu, 19 Feb 2026 20:54:33 +0700 Subject: [PATCH 10/25] Enhance ArrayPointer with type-correct deleters for derived-to-base ownership transfer and update main.cpp to handle SIGTRAP for ARM64 macOS. Signed-off-by: blackb1rd --- .../src/main/decaf/lang/ArrayPointer.h | 66 ++++++++++++++++++- activemq-cpp/src/test/main.cpp | 1 + 2 files changed, 64 insertions(+), 3 deletions(-) diff --git a/activemq-cpp/src/main/decaf/lang/ArrayPointer.h b/activemq-cpp/src/main/decaf/lang/ArrayPointer.h index 4c030ca96..b6d6224b0 100755 --- a/activemq-cpp/src/main/decaf/lang/ArrayPointer.h +++ b/activemq-cpp/src/main/decaf/lang/ArrayPointer.h @@ -29,6 +29,7 @@ #include #include #include +#include namespace decaf { namespace lang { @@ -62,9 +63,15 @@ namespace lang { T* value; int length; decaf::util::concurrent::atomic::AtomicInteger refs; + void (*arrayDeleter)(T*); - ArrayData() : value(NULL), length(0), refs(1) {} - ArrayData(T* value, int length) : value(value), length(length), refs(1) { + static void defaultArrayDeleter(T* p) { + delete[] p; + } + + ArrayData() : value(NULL), length(0), refs(1), arrayDeleter(&defaultArrayDeleter) {} + ArrayData(T* value, int length, void (*deleter)(T*) = &defaultArrayDeleter) + : value(value), length(length), refs(1), arrayDeleter(deleter) { if( value != NULL && length <= 0 ) { throw decaf::lang::exceptions::IllegalArgumentException( __FILE__, __LINE__, "Non-NULL array pointer cannot have a size <= zero" ); @@ -119,6 +126,7 @@ namespace lang { ArrayPointer(int size) : array(NULL), onDelete(onDeleteFunc) { if (size == 0) { + this->array = new ArrayData(); return; } @@ -146,6 +154,7 @@ namespace lang { ArrayPointer(int size, const T& fillWith) : array(NULL), onDelete(onDeleteFunc) { if (size == 0) { + this->array = new ArrayData(); return; } @@ -180,6 +189,35 @@ namespace lang { } } + /** + * Explicit Constructor for derived-to-base array ownership transfer. + * + * Stores a type-correct deleter so delete[] uses the original allocated type U, + * avoiding undefined behavior when T is abstract (Apple clang 17 traps the + * abstract D1 destructor called by delete[] through a base pointer). + * + * @param value + * Pointer to a derived-type array being transferred to this owner. + * @param size + * The size of the array. + */ + template + explicit ArrayPointer(U* value, int size, + typename std::enable_if< + std::is_convertible::value && + !std::is_same::value + >::type* = NULL) + : array(NULL), onDelete(onDeleteFunc) { + + try { + this->array = new ArrayData(static_cast(value), size, &typedArrayDeleter); + } catch (std::exception& ex) { + throw ex; + } catch (...) { + throw std::bad_alloc(); + } + } + /** * Copy constructor. Copies the value contained in the ArrayPointer to the new * instance and increments the reference counter. @@ -209,6 +247,20 @@ namespace lang { ArrayPointer(value, size).swap(*this); } + /** + * Resets the ArrayPointer to hold a new derived-type array value, storing a + * type-correct deleter so delete[] uses the original allocated type U. + */ + template + typename std::enable_if< + std::is_convertible::value && + !std::is_same::value + >::type + reset(U* value, int size = 0) { + ArrayPointer temp(value, size); + temp.swap(*this); + } + /** * Releases the Pointer held and resets the internal pointer value to Null. This method * is not guaranteed to be safe if the Pointer is held by more than one object or this @@ -366,9 +418,17 @@ namespace lang { private: + // Type-correct deletion for derived-to-base array ownership. + // Casts back to the original allocated type U before calling delete[], + // avoiding the abstract D1 destructor trap in Apple clang 17. + template + static void typedArrayDeleter(T* p) { + delete[] static_cast(p); + } + // Internal Static deletion function. static void onDeleteFunc(ArrayData* value) { - delete [] value->value; + value->arrayDeleter(value->value); delete value; } diff --git a/activemq-cpp/src/test/main.cpp b/activemq-cpp/src/test/main.cpp index 54f972a8b..4f2b6e113 100644 --- a/activemq-cpp/src/test/main.cpp +++ b/activemq-cpp/src/test/main.cpp @@ -99,6 +99,7 @@ int main( int argc, char **argv ) { sigaction(SIGFPE, &sa, nullptr); sigaction(SIGBUS, &sa, nullptr); sigaction(SIGILL, &sa, nullptr); + sigaction(SIGTRAP, &sa, nullptr); // ARM64 macOS: BRK instruction (e.g. abstract class dtor) #endif // Enable record-only mode: skip formatting overhead, only record to flight recorder // Logs will be formatted and printed only on failure/timeout (lazy formatting) From 516d3c9143684cd88047d0d80347b2ff46238f7a Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Thu, 19 Feb 2026 21:01:40 +0700 Subject: [PATCH 11/25] Add Linux GCC build, unit test, benchmark, and integration jobs to CI workflow Signed-off-by: blackb1rd --- .github/workflows/ci.yml | 677 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 677 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7e03f37ce..e235d44cb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1016,6 +1016,472 @@ jobs: output/build/${{ matrix.config.preset }}/Testing/Temporary/ output/build/${{ matrix.config.preset }}/**/*.log + # Linux GCC build job (builds and uploads artifacts for test jobs) + linux-gcc-build-test: + name: Linux GCC Build (Test) + runs-on: ubuntu-latest + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-gcc-debug-test, build_type: Debug, ssl: true } + - { preset: x64-linux-gcc-release-test, build_type: Release, ssl: true } + - { preset: x64-linux-gcc-debug-no-ssl-test, build_type: Debug, ssl: false } + - { preset: x64-linux-gcc-release-no-ssl-test, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake + run: cmake --preset ${{ matrix.config.preset }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Build + run: cmake --build --preset ${{ matrix.config.preset }} -j $(nproc) + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Install + run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} + + - name: Upload build artifacts + uses: actions/upload-artifact@v6 + with: + name: linux-build-${{ matrix.config.preset }} + path: | + output/build/${{ matrix.config.preset }}/bin/ + output/build/${{ matrix.config.preset }}/lib/ + retention-days: 1 + + # Linux GCC unit test jobs (run in parallel after build) + linux-gcc-unit-test: + name: Linux GCC Unit Test (${{ matrix.config.preset }}) + runs-on: ubuntu-latest + needs: linux-gcc-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-gcc-debug-test, build_type: Debug, ssl: true } + - { preset: x64-linux-gcc-release-test, build_type: Release, ssl: true } + - { preset: x64-linux-gcc-debug-no-ssl-test, build_type: Debug, ssl: false } + - { preset: x64-linux-gcc-release-no-ssl-test, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Run unit tests + run: | + ctest --preset ${{ matrix.config.preset }} \ + -L unit -j $(nproc) --output-on-failure --timeout 300 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-unit-${{ strategy.job-index }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Linux GCC benchmark jobs (run in parallel after build) + linux-gcc-benchmark: + name: Linux GCC Benchmark + runs-on: ubuntu-latest + needs: linux-gcc-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-gcc-debug-test, build_type: Debug, ssl: true } + - { preset: x64-linux-gcc-release-test, build_type: Release, ssl: true } + - { preset: x64-linux-gcc-debug-no-ssl-test, build_type: Debug, ssl: false } + - { preset: x64-linux-gcc-release-no-ssl-test, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Run benchmarks + run: ctest --preset ${{ matrix.config.preset }} -L ^benchmark$ --output-on-failure --timeout 600 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-benchmark + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Linux GCC integration tests - run with multiple ActiveMQ versions + linux-gcc-integration-test: + name: Linux GCC Integration Test + runs-on: ubuntu-latest + needs: linux-gcc-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-gcc-release-no-ssl-test, build_type: Release } + activemq: + - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } + - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Start ActiveMQ (${{ matrix.activemq.name }}) + run: | + echo "Starting ActiveMQ using image: ${{ matrix.activemq.image }}" + ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose up -d + echo "Waiting for ActiveMQ to be ready..." + timeout 60 bash -c 'until docker compose ps | grep -q "healthy"; do sleep 2; done' || true + sleep 10 + + - name: Show broker status + run: docker compose ps + + - name: Run OpenWire integration tests (${{ matrix.activemq.name }}) + run: ctest --preset ${{ matrix.config.preset }} -L ^integration-openwire$ --output-on-failure --timeout 900 + + - name: Run STOMP integration tests (${{ matrix.activemq.name }}) + run: ctest --preset ${{ matrix.config.preset }} -L ^integration-stomp$ --output-on-failure --timeout 900 + + - name: Show broker logs on failure + if: failure() + run: | + echo "=== ActiveMQ logs ===" + docker compose logs --tail 100 || true + + - name: Stop ActiveMQ + if: always() + run: docker compose down + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-gcc-integration-${{ matrix.activemq.name }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Linux GCC SSL integration tests + linux-gcc-ssl-integration-test: + name: Linux GCC SSL Integration Test + runs-on: ubuntu-latest + needs: linux-gcc-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-gcc-release-test, build_type: Release } + activemq: + - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } + - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Start SSL broker (${{ matrix.activemq.name }}) + run: | + echo "Starting SSL-enabled ActiveMQ using image: ${{ matrix.activemq.image }}" + ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose --profile ssl up -d + echo "Waiting for SSL broker to be ready..." + timeout 60 bash -c 'until docker compose --profile ssl ps | grep -q "healthy"; do sleep 2; done' || true + sleep 10 + + - name: Show broker status + run: docker compose --profile ssl ps + + - name: Show broker logs (startup) + run: docker compose --profile ssl logs --tail 50 + + - name: Run OpenWire SSL integration tests (${{ matrix.activemq.name }}) + run: ctest --preset ${{ matrix.config.preset }} -L integration-openwire-ssl --output-on-failure --timeout 900 + env: + SSL_CERT_FILE: ${{ github.workspace }}/docker/ssl/certs/ca.pem + + - name: Show broker logs on failure + if: failure() + run: | + echo "=== ActiveMQ SSL broker logs ===" + docker compose --profile ssl logs --tail 200 || true + + - name: Stop SSL broker + if: always() + run: docker compose --profile ssl down + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-gcc-ssl-integration-${{ matrix.activemq.name }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Linux GCC integration benchmark tests + linux-gcc-integration-benchmark-test: + name: Linux GCC Integration Benchmark Test + runs-on: ubuntu-latest + needs: linux-gcc-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-gcc-release-test, build_type: Release } + activemq: + - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } + - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Start all brokers (${{ matrix.activemq.name }}) + run: | + echo "Starting ActiveMQ brokers using image: ${{ matrix.activemq.image }}" + ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose --profile failover up -d + echo "Waiting for all brokers to be ready..." + sleep 30 + + - name: Show broker status + run: docker compose --profile failover ps + + - name: Run integration benchmark tests (${{ matrix.activemq.name }}) + run: ctest --preset ${{ matrix.config.preset }} -L integration-benchmark --output-on-failure --timeout 1800 + + - name: Show broker logs on failure + if: failure() + run: | + echo "=== activemq-failover-1 logs ===" + docker compose --profile failover logs activemq1 --tail 100 || true + echo "=== activemq-failover-2 logs ===" + docker compose --profile failover logs activemq2 --tail 100 || true + echo "=== activemq-multi-3 logs ===" + docker compose --profile failover logs activemq3 --tail 100 || true + + - name: Stop all brokers + if: always() + run: docker compose --profile failover down + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-gcc-integration-benchmark-${{ matrix.activemq.name }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + # macOS builds without tests (all variants) macos-build: name: macOS Build @@ -1072,3 +1538,214 @@ jobs: - name: Install run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} + + # Windows CL build job (builds and uploads artifacts for test jobs) + windows-cl-build-test: + name: Windows CL Build (Test) + runs-on: windows-latest + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x86-windows-cl-debug-test, build_type: Debug, arch: x86, ssl: true } + - { preset: x86-windows-cl-release-test, build_type: Release, arch: x86, ssl: true } + - { preset: x64-windows-cl-debug-test, build_type: Debug, arch: x64, ssl: true } + - { preset: x64-windows-cl-release-test, build_type: Release, arch: x64, ssl: true } + - { preset: x64-windows-cl-debug-no-ssl-test, build_type: Debug, arch: x64, ssl: false } + - { preset: x64-windows-cl-release-no-ssl-test, build_type: Release, arch: x64, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install Ninja + run: choco install ninja -y + + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Setup MSVC Developer Command Prompt + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.config.arch }} + + - name: Set VCPKG_ROOT environment variable + shell: bash + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + shell: bash + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake + run: cmake --preset ${{ matrix.config.preset }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Build + run: cmake --build --preset ${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Install + run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} + + - name: Upload build artifacts + uses: actions/upload-artifact@v6 + with: + name: windows-build-${{ matrix.config.preset }} + path: | + output/build/${{ matrix.config.preset }}/bin/ + output/build/${{ matrix.config.preset }}/lib/ + retention-days: 1 + + # Windows CL unit test jobs (run in parallel after build) + windows-cl-unit-test: + name: Windows CL Unit Test (${{ matrix.config.preset }}) + runs-on: windows-latest + needs: windows-cl-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x86-windows-cl-debug-test, build_type: Debug, arch: x86, ssl: true } + - { preset: x86-windows-cl-release-test, build_type: Release, arch: x86, ssl: true } + - { preset: x64-windows-cl-debug-test, build_type: Debug, arch: x64, ssl: true } + - { preset: x64-windows-cl-release-test, build_type: Release, arch: x64, ssl: true } + - { preset: x64-windows-cl-debug-no-ssl-test, build_type: Debug, arch: x64, ssl: false } + - { preset: x64-windows-cl-release-no-ssl-test, build_type: Release, arch: x64, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install Ninja + run: choco install ninja -y + + - name: Setup MSVC Developer Command Prompt + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.config.arch }} + + - name: Set VCPKG_ROOT environment variable + shell: bash + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + shell: bash + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: windows-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Run unit tests + run: | + ctest --preset ${{ matrix.config.preset }} -C ${{ matrix.config.build_type }} -L unit -j $env:NUMBER_OF_PROCESSORS --output-on-failure --timeout 300 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-unit-${{ strategy.job-index }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Windows CL benchmark jobs (run in parallel after build) + windows-cl-benchmark: + name: Windows CL Benchmark + runs-on: windows-latest + needs: windows-cl-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x86-windows-cl-debug-test, build_type: Debug, arch: x86, ssl: true } + - { preset: x86-windows-cl-release-test, build_type: Release, arch: x86, ssl: true } + - { preset: x64-windows-cl-debug-test, build_type: Debug, arch: x64, ssl: true } + - { preset: x64-windows-cl-release-test, build_type: Release, arch: x64, ssl: true } + - { preset: x64-windows-cl-debug-no-ssl-test, build_type: Debug, arch: x64, ssl: false } + - { preset: x64-windows-cl-release-no-ssl-test, build_type: Release, arch: x64, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install Ninja + run: choco install ninja -y + + - name: Setup MSVC Developer Command Prompt + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.config.arch }} + + - name: Set VCPKG_ROOT environment variable + shell: bash + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + shell: bash + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: windows-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Run benchmarks + run: ctest --preset ${{ matrix.config.preset }} -C ${{ matrix.config.build_type }} -L ^benchmark$ --output-on-failure --timeout 600 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-benchmark + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log From 770c4000d85550e44df2c41064a4b67a4f10d93d Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Fri, 20 Feb 2026 01:53:51 +0700 Subject: [PATCH 12/25] Refactor tests to use anonymous namespaces and improve response handling in ResponseCorrelatorTest; add ASan configuration presets for macOS Signed-off-by: blackb1rd --- .../activemq/transport/IOTransportTest.cpp | 3 +++ .../correlator/ResponseCorrelatorTest.cpp | 17 ++++++++-------- activemq-cpp/src/test/main.cpp | 6 ++++++ cmake/presets/base.json | 9 +++++++++ cmake/presets/macos.json | 20 +++++++++++++++++++ 5 files changed, 47 insertions(+), 8 deletions(-) diff --git a/activemq-cpp/src/test/activemq/transport/IOTransportTest.cpp b/activemq-cpp/src/test/activemq/transport/IOTransportTest.cpp index 3a7ad216c..c8ea8b287 100644 --- a/activemq-cpp/src/test/activemq/transport/IOTransportTest.cpp +++ b/activemq-cpp/src/test/activemq/transport/IOTransportTest.cpp @@ -43,6 +43,7 @@ using namespace decaf::lang::exceptions; class IOTransportTest : public ::testing::Test { }; +namespace { //////////////////////////////////////////////////////////////////////////////// class MyCommand : public commands::BaseCommand { @@ -209,6 +210,8 @@ class MyTransportListener : public TransportListener{ virtual void transportResumed() {} }; +} // anonymous namespace + //////////////////////////////////////////////////////////////////////////////// // This will just test that we can start and stop the // transport without any exceptions. diff --git a/activemq-cpp/src/test/activemq/transport/correlator/ResponseCorrelatorTest.cpp b/activemq-cpp/src/test/activemq/transport/correlator/ResponseCorrelatorTest.cpp index 6743d0981..870c914b7 100644 --- a/activemq-cpp/src/test/activemq/transport/correlator/ResponseCorrelatorTest.cpp +++ b/activemq-cpp/src/test/activemq/transport/correlator/ResponseCorrelatorTest.cpp @@ -36,6 +36,8 @@ using namespace decaf::io; class ResponseCorrelatorTest : public ::testing::Test { }; +namespace { + //////////////////////////////////////////////////////////////////////////////// class MyCommand : public commands::BaseCommand { @@ -176,19 +178,17 @@ using namespace decaf::io; Pointer cmd = requests.front(); requests.pop(); - // Only send a response if one is required. - Pointer resp; - if (cmd->isResponseRequired()) { - resp = createResponse(cmd); - } - mutex.unlock(); // Send both the response and the original // command back to the correlator. if (listener != NULL) { - if (resp != NULL) { - listener->onCommand(resp); + // Only send a response if one is required. + // Avoid constructing a null Pointer to prevent + // unnecessary AtomicInteger heap allocation/deallocation + // racing with the test thread on macOS. + if (cmd->isResponseRequired()) { + listener->onCommand(createResponse(cmd)); } listener->onCommand(cmd); } @@ -322,6 +322,7 @@ using namespace decaf::io; } }; +} // anonymous namespace TEST_F(ResponseCorrelatorTest, testBasics) { diff --git a/activemq-cpp/src/test/main.cpp b/activemq-cpp/src/test/main.cpp index 4f2b6e113..923b70248 100644 --- a/activemq-cpp/src/test/main.cpp +++ b/activemq-cpp/src/test/main.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -183,6 +184,11 @@ int main( int argc, char **argv ) { std::thread testThread([&]() { testResult.store( RUN_ALL_TESTS() ); + // Detach this std::thread from the Decaf threading library before it exits. + // Calling Mutex::wait() during tests causes Threading::attachToCurrentThread() + // to register this thread in library->osThreads. Without this call, + // Threading::shutdown() would crash trying to clean up the stale proxy Thread. + decaf::internal::util::concurrent::Threading::releaseCurrentThreadHandle(); { std::lock_guard lock(mtx); completed.store(true); diff --git a/cmake/presets/base.json b/cmake/presets/base.json index 2414d8789..47a1f497e 100644 --- a/cmake/presets/base.json +++ b/cmake/presets/base.json @@ -100,6 +100,15 @@ "cacheVariables": { "AMQCPP_USE_SSL": false } + }, + { + "name": "asan", + "hidden": true, + "cacheVariables": { + "CMAKE_CXX_FLAGS": "-fsanitize=address -fno-omit-frame-pointer", + "CMAKE_C_FLAGS": "-fsanitize=address -fno-omit-frame-pointer", + "CMAKE_EXE_LINKER_FLAGS": "-fsanitize=address" + } } ] } \ No newline at end of file diff --git a/cmake/presets/macos.json b/cmake/presets/macos.json index 30a0a9ef0..a801ada4b 100644 --- a/cmake/presets/macos.json +++ b/cmake/presets/macos.json @@ -245,6 +245,17 @@ "release", "no-ssl" ] + }, + { + "name": "arm64-osx-asan-test", + "inherits": [ + "arm64", + "macos", + "test", + "vcpkg-arm64-osx", + "debug", + "asan" + ] } ], "buildPresets": [ @@ -327,6 +338,10 @@ { "name": "arm64-osx-release-no-ssl-test", "configurePreset": "arm64-osx-release-no-ssl-test" + }, + { + "name": "arm64-osx-asan-test", + "configurePreset": "arm64-osx-asan-test" } ], "testPresets": [ @@ -379,6 +394,11 @@ "name": "arm64-osx-release-no-ssl-test", "inherits": "macos-test", "configurePreset": "arm64-osx-release-no-ssl-test" + }, + { + "name": "arm64-osx-asan-test", + "inherits": "macos-test", + "configurePreset": "arm64-osx-asan-test" } ], "packagePresets": [ From 111d545cd0bdc914eaadf36ac861e48191889eac Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Fri, 20 Feb 2026 09:13:05 +0700 Subject: [PATCH 13/25] Add CI workflows for macOS and Windows - Created `ci-macos.yml` for macOS CI, including build, unit test, benchmark, and build without tests jobs. - Created `ci-windows.yml` for Windows CI, including Clang-CL build, unit test, benchmark, and build without tests jobs. - Implemented caching for vcpkg binary packages in both workflows. - Configured environment variables and setup steps for both macOS and Windows environments. Signed-off-by: blackb1rd --- .github/workflows/ci-linux-clang.yml | 552 ++++++++ .github/workflows/ci-linux-gcc.yml | 485 +++++++ .github/workflows/ci-macos.yml | 267 ++++ .github/workflows/ci-windows.yml | 504 ++++++++ .github/workflows/ci.yml | 1751 -------------------------- 5 files changed, 1808 insertions(+), 1751 deletions(-) create mode 100644 .github/workflows/ci-linux-clang.yml create mode 100644 .github/workflows/ci-linux-gcc.yml create mode 100644 .github/workflows/ci-macos.yml create mode 100644 .github/workflows/ci-windows.yml delete mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci-linux-clang.yml b/.github/workflows/ci-linux-clang.yml new file mode 100644 index 000000000..dd9447747 --- /dev/null +++ b/.github/workflows/ci-linux-clang.yml @@ -0,0 +1,552 @@ +name: CI Linux Clang + +on: + push: + branches: [ main ] + paths-ignore: + - '**.md' + - 'docs/**' + - '.gitignore' + - 'LICENSE' + pull_request: + branches: [ main ] + paths-ignore: + - '**.md' + - 'docs/**' + - '.gitignore' + - 'LICENSE' + workflow_dispatch: + +jobs: + # Linux build job (builds and uploads artifacts for test jobs) + linux-build-test: + name: Linux Clang Build (Test) + runs-on: ubuntu-latest + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-clang-debug-test, build_type: Debug, ssl: true } + - { preset: x64-linux-clang-release-test, build_type: Release, ssl: true } + - { preset: x64-linux-clang-debug-no-ssl-test, build_type: Debug, ssl: false } + - { preset: x64-linux-clang-release-no-ssl-test, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build clang + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake + run: cmake --preset ${{ matrix.config.preset }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Build + run: cmake --build --preset ${{ matrix.config.preset }} -j $(nproc) + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Install + run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} + + - name: Upload build artifacts + uses: actions/upload-artifact@v6 + with: + name: linux-build-${{ matrix.config.preset }} + path: | + output/build/${{ matrix.config.preset }}/bin/ + output/build/${{ matrix.config.preset }}/lib/ + retention-days: 1 + + # Linux unit test jobs (run in parallel after build) + linux-unit-test: + name: Linux Clang Unit Test (${{ matrix.config.preset }}) + runs-on: ubuntu-latest + needs: linux-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-clang-debug-test, build_type: Debug, ssl: true } + - { preset: x64-linux-clang-release-test, build_type: Release, ssl: true } + - { preset: x64-linux-clang-debug-no-ssl-test, build_type: Debug, ssl: false } + - { preset: x64-linux-clang-release-no-ssl-test, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build clang + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Run unit tests + run: | + ctest --preset ${{ matrix.config.preset }} \ + -L unit -j $(nproc) --output-on-failure --timeout 300 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-unit-${{ strategy.job-index }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Linux benchmark jobs (run in parallel after build) + linux-benchmark: + name: Linux Clang Benchmark + runs-on: ubuntu-latest + needs: linux-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-clang-debug-test, build_type: Debug, ssl: true } + - { preset: x64-linux-clang-release-test, build_type: Release, ssl: true } + - { preset: x64-linux-clang-debug-no-ssl-test, build_type: Debug, ssl: false } + - { preset: x64-linux-clang-release-no-ssl-test, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build clang + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Run benchmarks + run: ctest --preset ${{ matrix.config.preset }} -L ^benchmark$ --output-on-failure --timeout 600 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-benchmark + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Linux integration tests - run with multiple ActiveMQ versions + linux-integration-test: + name: Linux Integration Test + runs-on: ubuntu-latest + needs: linux-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + # Use no-SSL release build for non-SSL integration tests + config: + - { preset: x64-linux-clang-release-no-ssl-test, build_type: Release } + # Test with multiple ActiveMQ versions + activemq: + - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } + - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build clang + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Start ActiveMQ (${{ matrix.activemq.name }}) + run: | + echo "Starting ActiveMQ using image: ${{ matrix.activemq.image }}" + ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose up -d + echo "Waiting for ActiveMQ to be ready..." + timeout 60 bash -c 'until docker compose ps | grep -q "healthy"; do sleep 2; done' || true + sleep 10 + + - name: Show broker status + run: docker compose ps + + - name: Run OpenWire integration tests (${{ matrix.activemq.name }}) + run: ctest --preset ${{ matrix.config.preset }} -L ^integration-openwire$ --output-on-failure --timeout 900 + + - name: Run STOMP integration tests (${{ matrix.activemq.name }}) + run: ctest --preset ${{ matrix.config.preset }} -L ^integration-stomp$ --output-on-failure --timeout 900 + + - name: Show broker logs on failure + if: failure() + run: | + echo "=== ActiveMQ logs ===" + docker compose logs --tail 100 || true + + - name: Stop ActiveMQ + if: always() + run: docker compose down + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-integration-${{ matrix.activemq.name }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Linux SSL integration tests - run with SSL-enabled broker + linux-ssl-integration-test: + name: Linux SSL Integration Test + runs-on: ubuntu-latest + needs: linux-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + # Only test with SSL-enabled presets (release build) + config: + - { preset: x64-linux-clang-release-test, build_type: Release } + # Test with ActiveMQ versions that support SSL + activemq: + - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } + - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build clang + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Start SSL broker (${{ matrix.activemq.name }}) + run: | + echo "Starting SSL-enabled ActiveMQ using image: ${{ matrix.activemq.image }}" + ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose --profile ssl up -d + echo "Waiting for SSL broker to be ready..." + timeout 60 bash -c 'until docker compose --profile ssl ps | grep -q "healthy"; do sleep 2; done' || true + sleep 10 + + - name: Show broker status + run: docker compose --profile ssl ps + + - name: Show broker logs (startup) + run: docker compose --profile ssl logs --tail 50 + + - name: Run OpenWire SSL integration tests (${{ matrix.activemq.name }}) + run: ctest --preset ${{ matrix.config.preset }} -L integration-openwire-ssl --output-on-failure --timeout 900 + env: + SSL_CERT_FILE: ${{ github.workspace }}/docker/ssl/certs/ca.pem + + - name: Show broker logs on failure + if: failure() + run: | + echo "=== ActiveMQ SSL broker logs ===" + docker compose --profile ssl logs --tail 200 || true + + - name: Stop SSL broker + if: always() + run: docker compose --profile ssl down + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-ssl-integration-${{ matrix.activemq.name }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Linux integration benchmark tests - run separately with multiple ActiveMQ versions + # Tests failover, multi-connection, and high-volume scenarios + linux-integration-benchmark-test: + name: Linux Integration Benchmark Test + runs-on: ubuntu-latest + needs: linux-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + # Use release build for integration benchmark tests (one config to avoid excessive combinations) + config: + - { preset: x64-linux-clang-release-test, build_type: Release } + # Test with multiple ActiveMQ versions + activemq: + - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } + - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build clang + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Start all brokers (${{ matrix.activemq.name }}) + run: | + echo "Starting ActiveMQ brokers using image: ${{ matrix.activemq.image }}" + ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose --profile failover up -d + echo "Waiting for all brokers to be ready..." + sleep 30 + + - name: Show broker status + run: docker compose --profile failover ps + + - name: Run integration benchmark tests (${{ matrix.activemq.name }}) + run: ctest --preset ${{ matrix.config.preset }} -L integration-benchmark --output-on-failure --timeout 1800 + + - name: Show broker logs on failure + if: failure() + run: | + echo "=== activemq-failover-1 logs ===" + docker compose --profile failover logs activemq1 --tail 100 || true + echo "=== activemq-failover-2 logs ===" + docker compose --profile failover logs activemq2 --tail 100 || true + echo "=== activemq-multi-3 logs ===" + docker compose --profile failover logs activemq3 --tail 100 || true + + - name: Stop all brokers + if: always() + run: docker compose --profile failover down + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-integration-benchmark-${{ matrix.activemq.name }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Linux builds without tests (all variants) + linux-build: + name: Linux Build + runs-on: ubuntu-latest + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" + + strategy: + fail-fast: false + matrix: + preset: + - x64-linux-gcc-debug + - x64-linux-gcc-release + - x64-linux-gcc-debug-static + - x64-linux-gcc-release-static + - x64-linux-gcc-debug-no-ssl + - x64-linux-gcc-release-no-ssl + - x64-linux-gcc-debug-static-no-ssl + - x64-linux-gcc-release-static-no-ssl + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake + run: cmake --preset ${{ matrix.preset }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Build + run: cmake --build --preset ${{ matrix.preset }} -j $(nproc) + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Install + run: cmake --install output/build/${{ matrix.preset }} --prefix output/install/${{ matrix.preset }} diff --git a/.github/workflows/ci-linux-gcc.yml b/.github/workflows/ci-linux-gcc.yml new file mode 100644 index 000000000..36deca871 --- /dev/null +++ b/.github/workflows/ci-linux-gcc.yml @@ -0,0 +1,485 @@ +name: CI Linux GCC + +on: + push: + branches: [ main ] + paths-ignore: + - '**.md' + - 'docs/**' + - '.gitignore' + - 'LICENSE' + pull_request: + branches: [ main ] + paths-ignore: + - '**.md' + - 'docs/**' + - '.gitignore' + - 'LICENSE' + workflow_dispatch: + +jobs: + # Linux GCC build job (builds and uploads artifacts for test jobs) + linux-gcc-build-test: + name: Linux GCC Build (Test) + runs-on: ubuntu-latest + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-gcc-debug-test, build_type: Debug, ssl: true } + - { preset: x64-linux-gcc-release-test, build_type: Release, ssl: true } + - { preset: x64-linux-gcc-debug-no-ssl-test, build_type: Debug, ssl: false } + - { preset: x64-linux-gcc-release-no-ssl-test, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake + run: cmake --preset ${{ matrix.config.preset }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Build + run: cmake --build --preset ${{ matrix.config.preset }} -j $(nproc) + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Install + run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} + + - name: Upload build artifacts + uses: actions/upload-artifact@v6 + with: + name: linux-build-${{ matrix.config.preset }} + path: | + output/build/${{ matrix.config.preset }}/bin/ + output/build/${{ matrix.config.preset }}/lib/ + retention-days: 1 + + # Linux GCC unit test jobs (run in parallel after build) + linux-gcc-unit-test: + name: Linux GCC Unit Test (${{ matrix.config.preset }}) + runs-on: ubuntu-latest + needs: linux-gcc-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-gcc-debug-test, build_type: Debug, ssl: true } + - { preset: x64-linux-gcc-release-test, build_type: Release, ssl: true } + - { preset: x64-linux-gcc-debug-no-ssl-test, build_type: Debug, ssl: false } + - { preset: x64-linux-gcc-release-no-ssl-test, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Run unit tests + run: | + ctest --preset ${{ matrix.config.preset }} \ + -L unit -j $(nproc) --output-on-failure --timeout 300 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-unit-${{ strategy.job-index }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Linux GCC benchmark jobs (run in parallel after build) + linux-gcc-benchmark: + name: Linux GCC Benchmark + runs-on: ubuntu-latest + needs: linux-gcc-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-gcc-debug-test, build_type: Debug, ssl: true } + - { preset: x64-linux-gcc-release-test, build_type: Release, ssl: true } + - { preset: x64-linux-gcc-debug-no-ssl-test, build_type: Debug, ssl: false } + - { preset: x64-linux-gcc-release-no-ssl-test, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Run benchmarks + run: ctest --preset ${{ matrix.config.preset }} -L ^benchmark$ --output-on-failure --timeout 600 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-benchmark + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Linux GCC integration tests - run with multiple ActiveMQ versions + linux-gcc-integration-test: + name: Linux GCC Integration Test + runs-on: ubuntu-latest + needs: linux-gcc-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-gcc-release-no-ssl-test, build_type: Release } + activemq: + - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } + - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Start ActiveMQ (${{ matrix.activemq.name }}) + run: | + echo "Starting ActiveMQ using image: ${{ matrix.activemq.image }}" + ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose up -d + echo "Waiting for ActiveMQ to be ready..." + timeout 60 bash -c 'until docker compose ps | grep -q "healthy"; do sleep 2; done' || true + sleep 10 + + - name: Show broker status + run: docker compose ps + + - name: Run OpenWire integration tests (${{ matrix.activemq.name }}) + run: ctest --preset ${{ matrix.config.preset }} -L ^integration-openwire$ --output-on-failure --timeout 900 + + - name: Run STOMP integration tests (${{ matrix.activemq.name }}) + run: ctest --preset ${{ matrix.config.preset }} -L ^integration-stomp$ --output-on-failure --timeout 900 + + - name: Show broker logs on failure + if: failure() + run: | + echo "=== ActiveMQ logs ===" + docker compose logs --tail 100 || true + + - name: Stop ActiveMQ + if: always() + run: docker compose down + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-gcc-integration-${{ matrix.activemq.name }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Linux GCC SSL integration tests + linux-gcc-ssl-integration-test: + name: Linux GCC SSL Integration Test + runs-on: ubuntu-latest + needs: linux-gcc-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-gcc-release-test, build_type: Release } + activemq: + - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } + - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Start SSL broker (${{ matrix.activemq.name }}) + run: | + echo "Starting SSL-enabled ActiveMQ using image: ${{ matrix.activemq.image }}" + ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose --profile ssl up -d + echo "Waiting for SSL broker to be ready..." + timeout 60 bash -c 'until docker compose --profile ssl ps | grep -q "healthy"; do sleep 2; done' || true + sleep 10 + + - name: Show broker status + run: docker compose --profile ssl ps + + - name: Show broker logs (startup) + run: docker compose --profile ssl logs --tail 50 + + - name: Run OpenWire SSL integration tests (${{ matrix.activemq.name }}) + run: ctest --preset ${{ matrix.config.preset }} -L integration-openwire-ssl --output-on-failure --timeout 900 + env: + SSL_CERT_FILE: ${{ github.workspace }}/docker/ssl/certs/ca.pem + + - name: Show broker logs on failure + if: failure() + run: | + echo "=== ActiveMQ SSL broker logs ===" + docker compose --profile ssl logs --tail 200 || true + + - name: Stop SSL broker + if: always() + run: docker compose --profile ssl down + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-gcc-ssl-integration-${{ matrix.activemq.name }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Linux GCC integration benchmark tests + linux-gcc-integration-benchmark-test: + name: Linux GCC Integration Benchmark Test + runs-on: ubuntu-latest + needs: linux-gcc-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-linux-gcc-release-test, build_type: Release } + activemq: + - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } + - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ninja-build + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: linux-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Start all brokers (${{ matrix.activemq.name }}) + run: | + echo "Starting ActiveMQ brokers using image: ${{ matrix.activemq.image }}" + ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose --profile failover up -d + echo "Waiting for all brokers to be ready..." + sleep 30 + + - name: Show broker status + run: docker compose --profile failover ps + + - name: Run integration benchmark tests (${{ matrix.activemq.name }}) + run: ctest --preset ${{ matrix.config.preset }} -L integration-benchmark --output-on-failure --timeout 1800 + + - name: Show broker logs on failure + if: failure() + run: | + echo "=== activemq-failover-1 logs ===" + docker compose --profile failover logs activemq1 --tail 100 || true + echo "=== activemq-failover-2 logs ===" + docker compose --profile failover logs activemq2 --tail 100 || true + echo "=== activemq-multi-3 logs ===" + docker compose --profile failover logs activemq3 --tail 100 || true + + - name: Stop all brokers + if: always() + run: docker compose --profile failover down + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-gcc-integration-benchmark-${{ matrix.activemq.name }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml new file mode 100644 index 000000000..8df9ede24 --- /dev/null +++ b/.github/workflows/ci-macos.yml @@ -0,0 +1,267 @@ +name: CI macOS + +on: + push: + branches: [ main ] + paths-ignore: + - '**.md' + - 'docs/**' + - '.gitignore' + - 'LICENSE' + pull_request: + branches: [ main ] + paths-ignore: + - '**.md' + - 'docs/**' + - '.gitignore' + - 'LICENSE' + workflow_dispatch: + +jobs: + # macOS build job (builds and uploads artifacts for test jobs) + macos-build-test: + name: macOS Build (Test) + runs-on: ${{ matrix.config.runner }} + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" + + strategy: + fail-fast: false + matrix: + config: + - { runner: macos-latest, preset: arm64-osx-debug-test, arch: arm64, build_type: Debug, ssl: true } + - { runner: macos-latest, preset: arm64-osx-release-test, arch: arm64, build_type: Release, ssl: true } + - { runner: macos-latest, preset: arm64-osx-debug-no-ssl-test, arch: arm64, build_type: Debug, ssl: false } + - { runner: macos-latest, preset: arm64-osx-release-no-ssl-test, arch: arm64, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: brew install ninja + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake + run: cmake --preset ${{ matrix.config.preset }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Build + run: cmake --build --preset ${{ matrix.config.preset }} -j $(nproc 2>/dev/null || sysctl -n hw.logicalcpu) + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Install + run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} + + - name: Upload build artifacts + uses: actions/upload-artifact@v6 + with: + name: macos-build-${{ matrix.config.preset }} + path: | + output/build/${{ matrix.config.preset }}/bin/ + output/build/${{ matrix.config.preset }}/lib/ + retention-days: 1 + + # macOS unit test jobs (run in parallel after build) + macos-unit-test: + name: macOS Unit Test (${{ matrix.config.preset }}) + runs-on: ${{ matrix.config.runner }} + needs: macos-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { runner: macos-latest, preset: arm64-osx-debug-test, arch: arm64, build_type: Debug, ssl: true } + - { runner: macos-latest, preset: arm64-osx-release-test, arch: arm64, build_type: Release, ssl: true } + - { runner: macos-latest, preset: arm64-osx-debug-no-ssl-test, arch: arm64, build_type: Debug, ssl: false } + - { runner: macos-latest, preset: arm64-osx-release-no-ssl-test, arch: arm64, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: brew install ninja + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: macos-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Run unit tests + run: | + ctest --preset ${{ matrix.config.preset }} \ + -L unit -j $(nproc 2>/dev/null || sysctl -n hw.logicalcpu) --output-on-failure --timeout 300 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-unit-${{ strategy.job-index }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # macOS benchmark jobs (run in parallel after build) + macos-benchmark: + name: macOS Benchmark + runs-on: ${{ matrix.config.runner }} + needs: macos-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { runner: macos-latest, preset: arm64-osx-debug-test, arch: arm64, build_type: Debug, ssl: true } + - { runner: macos-latest, preset: arm64-osx-release-test, arch: arm64, build_type: Release, ssl: true } + - { runner: macos-latest, preset: arm64-osx-debug-no-ssl-test, arch: arm64, build_type: Debug, ssl: false } + - { runner: macos-latest, preset: arm64-osx-release-no-ssl-test, arch: arm64, build_type: Release, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: brew install ninja + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: macos-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Make test executables runnable + run: chmod +x output/build/${{ matrix.config.preset }}/bin/* + + - name: Run benchmarks + run: ctest --preset ${{ matrix.config.preset }} -L ^benchmark$ --output-on-failure --timeout 600 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-benchmark + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # macOS builds without tests (all variants) + macos-build: + name: macOS Build + runs-on: ${{ matrix.config.runner }} + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" + + strategy: + fail-fast: false + matrix: + config: + # Apple Silicon arm64 builds + - { runner: macos-latest, preset: arm64-osx-debug, arch: arm64 } + - { runner: macos-latest, preset: arm64-osx-release, arch: arm64 } + - { runner: macos-latest, preset: arm64-osx-debug-static, arch: arm64 } + - { runner: macos-latest, preset: arm64-osx-release-static, arch: arm64 } + - { runner: macos-latest, preset: arm64-osx-debug-no-ssl, arch: arm64 } + - { runner: macos-latest, preset: arm64-osx-release-no-ssl, arch: arm64 } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install system dependencies + run: brew install ninja + + - name: Set VCPKG_ROOT environment variable + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Create vcpkg binary cache directory + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake + run: cmake --preset ${{ matrix.config.preset }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Build + run: cmake --build --preset ${{ matrix.config.preset }} -j $(nproc 2>/dev/null || sysctl -n hw.logicalcpu) + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Install + run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} diff --git a/.github/workflows/ci-windows.yml b/.github/workflows/ci-windows.yml new file mode 100644 index 000000000..d2d90c4b4 --- /dev/null +++ b/.github/workflows/ci-windows.yml @@ -0,0 +1,504 @@ +name: CI Windows + +on: + push: + branches: [ main ] + paths-ignore: + - '**.md' + - 'docs/**' + - '.gitignore' + - 'LICENSE' + pull_request: + branches: [ main ] + paths-ignore: + - '**.md' + - 'docs/**' + - '.gitignore' + - 'LICENSE' + workflow_dispatch: + +jobs: + # Windows Clang-CL build job (builds and uploads artifacts for test jobs) + windows-build-test: + name: Windows Clang-CL Build (Test) + runs-on: windows-latest + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-windows-clang-debug-test, build_type: Debug, arch: amd64, ssl: true } + - { preset: x64-windows-clang-release-test, build_type: Release, arch: amd64, ssl: true } + - { preset: x64-windows-clang-debug-no-ssl-test, build_type: Debug, arch: amd64, ssl: false } + - { preset: x64-windows-clang-release-no-ssl-test, build_type: Release, arch: amd64, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install Ninja + run: choco install ninja -y + + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Setup MSVC Developer Command Prompt + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.config.arch }} + + - name: Set VCPKG_ROOT environment variable + shell: bash + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + shell: bash + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake + run: cmake --preset ${{ matrix.config.preset }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Build + run: cmake --build --preset ${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Install + run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} + + - name: Upload build artifacts + uses: actions/upload-artifact@v6 + with: + name: windows-build-${{ matrix.config.preset }} + path: | + output/build/${{ matrix.config.preset }}/bin/ + output/build/${{ matrix.config.preset }}/lib/ + retention-days: 1 + + # Windows Clang-CL unit test jobs (run in parallel after build, no Docker on Windows CI) + windows-unit-test: + name: Windows Clang-CL Unit Test (${{ matrix.config.preset }}) + runs-on: windows-latest + needs: windows-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-windows-clang-debug-test, build_type: Debug, arch: amd64, ssl: true } + - { preset: x64-windows-clang-release-test, build_type: Release, arch: amd64, ssl: true } + - { preset: x64-windows-clang-debug-no-ssl-test, build_type: Debug, arch: amd64, ssl: false } + - { preset: x64-windows-clang-release-no-ssl-test, build_type: Release, arch: amd64, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install Ninja + run: choco install ninja -y + + - name: Setup MSVC Developer Command Prompt + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.config.arch }} + + - name: Set VCPKG_ROOT environment variable + shell: bash + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + shell: bash + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: windows-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Run unit tests + run: | + ctest --preset ${{ matrix.config.preset }} -C ${{ matrix.config.build_type }} -L unit -j $env:NUMBER_OF_PROCESSORS --output-on-failure --timeout 300 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-unit-${{ strategy.job-index }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Windows Clang-CL benchmark jobs (run in parallel after build) + windows-benchmark: + name: Windows Benchmark + runs-on: windows-latest + needs: windows-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x64-windows-clang-debug-test, build_type: Debug, arch: amd64, ssl: true } + - { preset: x64-windows-clang-release-test, build_type: Release, arch: amd64, ssl: true } + - { preset: x64-windows-clang-debug-no-ssl-test, build_type: Debug, arch: amd64, ssl: false } + - { preset: x64-windows-clang-release-no-ssl-test, build_type: Release, arch: amd64, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install Ninja + run: choco install ninja -y + + - name: Setup MSVC Developer Command Prompt + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.config.arch }} + + - name: Set VCPKG_ROOT environment variable + shell: bash + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + shell: bash + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: windows-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Run benchmarks + run: ctest --preset ${{ matrix.config.preset }} -C ${{ matrix.config.build_type }} -L ^benchmark$ --output-on-failure --timeout 600 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-benchmark + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Windows builds without tests (all variants) + windows-build: + name: Windows Build + runs-on: windows-latest + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" + + strategy: + fail-fast: false + matrix: + config: + # x86 builds (shared with SSL only) + - { preset: x86-windows-cl-debug, build_type: Debug, arch: x86 } + - { preset: x86-windows-cl-release, build_type: Release, arch: x86 } + # x64 builds (all variants) + - { preset: x64-windows-cl-debug, build_type: Debug, arch: x64 } + - { preset: x64-windows-cl-release, build_type: Release, arch: x64 } + - { preset: x64-windows-cl-debug-static, build_type: Debug, arch: x64 } + - { preset: x64-windows-cl-release-static, build_type: Release, arch: x64 } + - { preset: x64-windows-cl-debug-no-ssl, build_type: Debug, arch: x64 } + - { preset: x64-windows-cl-release-no-ssl, build_type: Release, arch: x64 } + - { preset: x64-windows-cl-debug-static-no-ssl, build_type: Debug, arch: x64 } + - { preset: x64-windows-cl-release-static-no-ssl, build_type: Release, arch: x64 } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install Ninja + run: choco install ninja -y + + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Setup MSVC Developer Command Prompt + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.config.arch }} + + - name: Set VCPKG_ROOT environment variable + shell: bash + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + shell: bash + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake + run: cmake --preset ${{ matrix.config.preset }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Build + run: cmake --build --preset ${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Install + run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} + + # Windows CL build job (builds and uploads artifacts for test jobs) + windows-cl-build-test: + name: Windows CL Build (Test) + runs-on: windows-latest + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x86-windows-cl-debug-test, build_type: Debug, arch: x86, ssl: true } + - { preset: x86-windows-cl-release-test, build_type: Release, arch: x86, ssl: true } + - { preset: x64-windows-cl-debug-test, build_type: Debug, arch: x64, ssl: true } + - { preset: x64-windows-cl-release-test, build_type: Release, arch: x64, ssl: true } + - { preset: x64-windows-cl-debug-no-ssl-test, build_type: Debug, arch: x64, ssl: false } + - { preset: x64-windows-cl-release-no-ssl-test, build_type: Release, arch: x64, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install Ninja + run: choco install ninja -y + + - name: Setup sccache + uses: mozilla-actions/sccache-action@v0.0.9 + + - name: Setup MSVC Developer Command Prompt + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.config.arch }} + + - name: Set VCPKG_ROOT environment variable + shell: bash + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + shell: bash + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake + run: cmake --preset ${{ matrix.config.preset }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Build + run: cmake --build --preset ${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} + env: + SCCACHE_GHA_ENABLED: "true" + + - name: Install + run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} + + - name: Upload build artifacts + uses: actions/upload-artifact@v6 + with: + name: windows-build-${{ matrix.config.preset }} + path: | + output/build/${{ matrix.config.preset }}/bin/ + output/build/${{ matrix.config.preset }}/lib/ + retention-days: 1 + + # Windows CL unit test jobs (run in parallel after build) + windows-cl-unit-test: + name: Windows CL Unit Test (${{ matrix.config.preset }}) + runs-on: windows-latest + needs: windows-cl-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x86-windows-cl-debug-test, build_type: Debug, arch: x86, ssl: true } + - { preset: x86-windows-cl-release-test, build_type: Release, arch: x86, ssl: true } + - { preset: x64-windows-cl-debug-test, build_type: Debug, arch: x64, ssl: true } + - { preset: x64-windows-cl-release-test, build_type: Release, arch: x64, ssl: true } + - { preset: x64-windows-cl-debug-no-ssl-test, build_type: Debug, arch: x64, ssl: false } + - { preset: x64-windows-cl-release-no-ssl-test, build_type: Release, arch: x64, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install Ninja + run: choco install ninja -y + + - name: Setup MSVC Developer Command Prompt + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.config.arch }} + + - name: Set VCPKG_ROOT environment variable + shell: bash + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + shell: bash + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: windows-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Run unit tests + run: | + ctest --preset ${{ matrix.config.preset }} -C ${{ matrix.config.build_type }} -L unit -j $env:NUMBER_OF_PROCESSORS --output-on-failure --timeout 300 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-unit-${{ strategy.job-index }} + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log + + # Windows CL benchmark jobs (run in parallel after build) + windows-cl-benchmark: + name: Windows CL Benchmark + runs-on: windows-latest + needs: windows-cl-build-test + + env: + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" + + strategy: + fail-fast: false + matrix: + config: + - { preset: x86-windows-cl-debug-test, build_type: Debug, arch: x86, ssl: true } + - { preset: x86-windows-cl-release-test, build_type: Release, arch: x86, ssl: true } + - { preset: x64-windows-cl-debug-test, build_type: Debug, arch: x64, ssl: true } + - { preset: x64-windows-cl-release-test, build_type: Release, arch: x64, ssl: true } + - { preset: x64-windows-cl-debug-no-ssl-test, build_type: Debug, arch: x64, ssl: false } + - { preset: x64-windows-cl-release-no-ssl-test, build_type: Release, arch: x64, ssl: false } + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Install Ninja + run: choco install ninja -y + + - name: Setup MSVC Developer Command Prompt + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: ${{ matrix.config.arch }} + + - name: Set VCPKG_ROOT environment variable + shell: bash + run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV + + - name: Create vcpkg binary cache directory + shell: bash + run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" + + - name: Cache vcpkg binary packages + uses: actions/cache@v5 + with: + path: ${{ github.workspace }}/.cache/vcpkg/archives + key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- + + - name: Configure CMake (for CTest) + run: cmake --preset ${{ matrix.config.preset }} + + - name: Download build artifacts + uses: actions/download-artifact@v7 + with: + name: windows-build-${{ matrix.config.preset }} + path: output/build/${{ matrix.config.preset }}/ + + - name: Run benchmarks + run: ctest --preset ${{ matrix.config.preset }} -C ${{ matrix.config.build_type }} -L ^benchmark$ --output-on-failure --timeout 600 + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.config.preset }}-benchmark + path: | + output/build/${{ matrix.config.preset }}/Testing/Temporary/ + output/build/${{ matrix.config.preset }}/**/*.log diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index e235d44cb..000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,1751 +0,0 @@ -name: CI - -on: - push: - branches: [ main ] - paths-ignore: - - '**.md' - - 'docs/**' - - '.gitignore' - - 'LICENSE' - pull_request: - branches: [ main ] - paths-ignore: - - '**.md' - - 'docs/**' - - '.gitignore' - - 'LICENSE' - workflow_dispatch: - -jobs: - # Linux build job (builds and uploads artifacts for test jobs) - linux-build-test: - name: Linux Clang Build (Test) - runs-on: ubuntu-latest - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x64-linux-clang-debug-test, build_type: Debug, ssl: true } - - { preset: x64-linux-clang-release-test, build_type: Release, ssl: true } - - { preset: x64-linux-clang-debug-no-ssl-test, build_type: Debug, ssl: false } - - { preset: x64-linux-clang-release-no-ssl-test, build_type: Release, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build clang - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.9 - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}- - - - name: Configure CMake - run: cmake --preset ${{ matrix.config.preset }} - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Build - run: cmake --build --preset ${{ matrix.config.preset }} -j $(nproc) - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Install - run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} - - - name: Upload build artifacts - uses: actions/upload-artifact@v6 - with: - name: linux-build-${{ matrix.config.preset }} - path: | - output/build/${{ matrix.config.preset }}/bin/ - output/build/${{ matrix.config.preset }}/lib/ - retention-days: 1 - - # Linux unit test jobs (run in parallel after build) - linux-unit-test: - name: Linux Clang Unit Test (${{ matrix.config.preset }}) - runs-on: ubuntu-latest - needs: linux-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x64-linux-clang-debug-test, build_type: Debug, ssl: true } - - { preset: x64-linux-clang-release-test, build_type: Release, ssl: true } - - { preset: x64-linux-clang-debug-no-ssl-test, build_type: Debug, ssl: false } - - { preset: x64-linux-clang-release-no-ssl-test, build_type: Release, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build clang - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: linux-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Make test executables runnable - run: chmod +x output/build/${{ matrix.config.preset }}/bin/* - - - name: Run unit tests - run: | - ctest --preset ${{ matrix.config.preset }} \ - -L unit -j $(nproc) --output-on-failure --timeout 300 - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-${{ matrix.config.preset }}-unit-${{ strategy.job-index }} - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # Linux benchmark jobs (run in parallel after build) - linux-benchmark: - name: Linux Clang Benchmark - runs-on: ubuntu-latest - needs: linux-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x64-linux-clang-debug-test, build_type: Debug, ssl: true } - - { preset: x64-linux-clang-release-test, build_type: Release, ssl: true } - - { preset: x64-linux-clang-debug-no-ssl-test, build_type: Debug, ssl: false } - - { preset: x64-linux-clang-release-no-ssl-test, build_type: Release, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build clang - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: linux-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Make test executables runnable - run: chmod +x output/build/${{ matrix.config.preset }}/bin/* - - - name: Run benchmarks - run: ctest --preset ${{ matrix.config.preset }} -L ^benchmark$ --output-on-failure --timeout 600 - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-${{ matrix.config.preset }}-benchmark - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # Linux integration tests - run with multiple ActiveMQ versions - linux-integration-test: - name: Linux Integration Test - runs-on: ubuntu-latest - needs: linux-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - # Use no-SSL release build for non-SSL integration tests - config: - - { preset: x64-linux-clang-release-no-ssl-test, build_type: Release } - # Test with multiple ActiveMQ versions - activemq: - - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } - - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build clang - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: linux-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Make test executables runnable - run: chmod +x output/build/${{ matrix.config.preset }}/bin/* - - - name: Start ActiveMQ (${{ matrix.activemq.name }}) - run: | - echo "Starting ActiveMQ using image: ${{ matrix.activemq.image }}" - ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose up -d - echo "Waiting for ActiveMQ to be ready..." - timeout 60 bash -c 'until docker compose ps | grep -q "healthy"; do sleep 2; done' || true - sleep 10 - - - name: Show broker status - run: docker compose ps - - - name: Run OpenWire integration tests (${{ matrix.activemq.name }}) - run: ctest --preset ${{ matrix.config.preset }} -L ^integration-openwire$ --output-on-failure --timeout 900 - - - name: Run STOMP integration tests (${{ matrix.activemq.name }}) - run: ctest --preset ${{ matrix.config.preset }} -L ^integration-stomp$ --output-on-failure --timeout 900 - - - name: Show broker logs on failure - if: failure() - run: | - echo "=== ActiveMQ logs ===" - docker compose logs --tail 100 || true - - - name: Stop ActiveMQ - if: always() - run: docker compose down - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-integration-${{ matrix.activemq.name }} - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # Linux SSL integration tests - run with SSL-enabled broker (Linux only) - linux-ssl-integration-test: - name: Linux SSL Integration Test - runs-on: ubuntu-latest - needs: linux-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - # Only test with SSL-enabled presets (release build) - config: - - { preset: x64-linux-clang-release-test, build_type: Release } - # Test with ActiveMQ versions that support SSL - activemq: - - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } - - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build clang - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: linux-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Make test executables runnable - run: chmod +x output/build/${{ matrix.config.preset }}/bin/* - - - name: Start SSL broker (${{ matrix.activemq.name }}) - run: | - echo "Starting SSL-enabled ActiveMQ using image: ${{ matrix.activemq.image }}" - ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose --profile ssl up -d - echo "Waiting for SSL broker to be ready..." - timeout 60 bash -c 'until docker compose --profile ssl ps | grep -q "healthy"; do sleep 2; done' || true - sleep 10 - - - name: Show broker status - run: docker compose --profile ssl ps - - - name: Show broker logs (startup) - run: docker compose --profile ssl logs --tail 50 - - - name: Run OpenWire SSL integration tests (${{ matrix.activemq.name }}) - run: ctest --preset ${{ matrix.config.preset }} -L integration-openwire-ssl --output-on-failure --timeout 900 - env: - SSL_CERT_FILE: ${{ github.workspace }}/docker/ssl/certs/ca.pem - - - name: Show broker logs on failure - if: failure() - run: | - echo "=== ActiveMQ SSL broker logs ===" - docker compose --profile ssl logs --tail 200 || true - - - name: Stop SSL broker - if: always() - run: docker compose --profile ssl down - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-ssl-integration-${{ matrix.activemq.name }} - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # Linux integration benchmark tests - run separately with multiple ActiveMQ versions - # Tests failover, multi-connection, and high-volume scenarios - linux-integration-benchmark-test: - name: Linux Integration Benchmark Test - runs-on: ubuntu-latest - needs: linux-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - # Use release build for integration benchmark tests (one config to avoid excessive combinations) - config: - - { preset: x64-linux-clang-release-test, build_type: Release } - # Test with multiple ActiveMQ versions - activemq: - - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } - - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build clang - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: linux-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Make test executables runnable - run: chmod +x output/build/${{ matrix.config.preset }}/bin/* - - - name: Start all brokers (${{ matrix.activemq.name }}) - run: | - echo "Starting ActiveMQ brokers using image: ${{ matrix.activemq.image }}" - ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose --profile failover up -d - echo "Waiting for all brokers to be ready..." - sleep 30 - - - name: Show broker status - run: docker compose --profile failover ps - - - name: Run integration benchmark tests (${{ matrix.activemq.name }}) - run: ctest --preset ${{ matrix.config.preset }} -L integration-benchmark --output-on-failure --timeout 1800 - - - name: Show broker logs on failure - if: failure() - run: | - echo "=== activemq-failover-1 logs ===" - docker compose --profile failover logs activemq1 --tail 100 || true - echo "=== activemq-failover-2 logs ===" - docker compose --profile failover logs activemq2 --tail 100 || true - echo "=== activemq-multi-3 logs ===" - docker compose --profile failover logs activemq3 --tail 100 || true - - - name: Stop all brokers - if: always() - run: docker compose --profile failover down - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-integration-benchmark-${{ matrix.activemq.name }} - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # Linux builds without tests (all variants) - linux-build: - name: Linux Build - runs-on: ubuntu-latest - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" - - strategy: - fail-fast: false - matrix: - preset: - - x64-linux-gcc-debug - - x64-linux-gcc-release - - x64-linux-gcc-debug-static - - x64-linux-gcc-release-static - - x64-linux-gcc-debug-no-ssl - - x64-linux-gcc-release-no-ssl - - x64-linux-gcc-debug-static-no-ssl - - x64-linux-gcc-release-static-no-ssl - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.9 - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}- - - - name: Configure CMake - run: cmake --preset ${{ matrix.preset }} - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Build - run: cmake --build --preset ${{ matrix.preset }} -j $(nproc) - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Install - run: cmake --install output/build/${{ matrix.preset }} --prefix output/install/${{ matrix.preset }} - - # Windows build job (builds and uploads artifacts for test jobs) - windows-build-test: - name: Windows Clang-CL Build (Test) - runs-on: windows-latest - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x64-windows-clang-debug-test, build_type: Debug, arch: amd64, ssl: true } - - { preset: x64-windows-clang-release-test, build_type: Release, arch: amd64, ssl: true } - - { preset: x64-windows-clang-debug-no-ssl-test, build_type: Debug, arch: amd64, ssl: false } - - { preset: x64-windows-clang-release-no-ssl-test, build_type: Release, arch: amd64, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install Ninja - run: choco install ninja -y - - - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.9 - - - name: Setup MSVC Developer Command Prompt - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: ${{ matrix.config.arch }} - - - name: Set VCPKG_ROOT environment variable - shell: bash - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - shell: bash - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- - - - name: Configure CMake - run: cmake --preset ${{ matrix.config.preset }} - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Build - run: cmake --build --preset ${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Install - run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} - - - name: Upload build artifacts - uses: actions/upload-artifact@v6 - with: - name: windows-build-${{ matrix.config.preset }} - path: | - output/build/${{ matrix.config.preset }}/bin/ - output/build/${{ matrix.config.preset }}/lib/ - retention-days: 1 - - # Windows unit test jobs (run in parallel after build, no Docker on Windows CI) - windows-unit-test: - name: Windows Clang-CL Unit Test (${{ matrix.config.preset }}) - runs-on: windows-latest - needs: windows-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x64-windows-clang-debug-test, build_type: Debug, arch: amd64, ssl: true } - - { preset: x64-windows-clang-release-test, build_type: Release, arch: amd64, ssl: true } - - { preset: x64-windows-clang-debug-no-ssl-test, build_type: Debug, arch: amd64, ssl: false } - - { preset: x64-windows-clang-release-no-ssl-test, build_type: Release, arch: amd64, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install Ninja - run: choco install ninja -y - - - name: Setup MSVC Developer Command Prompt - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: ${{ matrix.config.arch }} - - - name: Set VCPKG_ROOT environment variable - shell: bash - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - shell: bash - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: windows-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Run unit tests - run: | - ctest --preset ${{ matrix.config.preset }} -C ${{ matrix.config.build_type }} -L unit -j $env:NUMBER_OF_PROCESSORS --output-on-failure --timeout 300 - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-${{ matrix.config.preset }}-unit-${{ strategy.job-index }} - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # Windows benchmark jobs (run in parallel after build) - windows-benchmark: - name: Windows Benchmark - runs-on: windows-latest - needs: windows-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x64-windows-clang-debug-test, build_type: Debug, arch: amd64, ssl: true } - - { preset: x64-windows-clang-release-test, build_type: Release, arch: amd64, ssl: true } - - { preset: x64-windows-clang-debug-no-ssl-test, build_type: Debug, arch: amd64, ssl: false } - - { preset: x64-windows-clang-release-no-ssl-test, build_type: Release, arch: amd64, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install Ninja - run: choco install ninja -y - - - name: Setup MSVC Developer Command Prompt - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: ${{ matrix.config.arch }} - - - name: Set VCPKG_ROOT environment variable - shell: bash - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - shell: bash - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: windows-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Run benchmarks - run: ctest --preset ${{ matrix.config.preset }} -C ${{ matrix.config.build_type }} -L ^benchmark$ --output-on-failure --timeout 600 - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-${{ matrix.config.preset }}-benchmark - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # Windows builds without tests (all variants) - windows-build: - name: Windows Build - runs-on: windows-latest - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" - - strategy: - fail-fast: false - matrix: - config: - # x86 builds (shared with SSL only) - - { preset: x86-windows-cl-debug, build_type: Debug, arch: x86 } - - { preset: x86-windows-cl-release, build_type: Release, arch: x86 } - # x64 builds (all variants) - - { preset: x64-windows-cl-debug, build_type: Debug, arch: x64 } - - { preset: x64-windows-cl-release, build_type: Release, arch: x64 } - - { preset: x64-windows-cl-debug-static, build_type: Debug, arch: x64 } - - { preset: x64-windows-cl-release-static, build_type: Release, arch: x64 } - - { preset: x64-windows-cl-debug-no-ssl, build_type: Debug, arch: x64 } - - { preset: x64-windows-cl-release-no-ssl, build_type: Release, arch: x64 } - - { preset: x64-windows-cl-debug-static-no-ssl, build_type: Debug, arch: x64 } - - { preset: x64-windows-cl-release-static-no-ssl, build_type: Release, arch: x64 } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install Ninja - run: choco install ninja -y - - - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.9 - - - name: Setup MSVC Developer Command Prompt - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: ${{ matrix.config.arch }} - - - name: Set VCPKG_ROOT environment variable - shell: bash - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - shell: bash - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- - - - name: Configure CMake - run: cmake --preset ${{ matrix.config.preset }} - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Build - run: cmake --build --preset ${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Install - run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} - - # macOS build job (builds and uploads artifacts for test jobs) - macos-build-test: - name: macOS Build (Test) - runs-on: ${{ matrix.config.runner }} - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" - - strategy: - fail-fast: false - matrix: - config: - - { runner: macos-latest, preset: arm64-osx-debug-test, arch: arm64, build_type: Debug, ssl: true } - - { runner: macos-latest, preset: arm64-osx-release-test, arch: arm64, build_type: Release, ssl: true } - - { runner: macos-latest, preset: arm64-osx-debug-no-ssl-test, arch: arm64, build_type: Debug, ssl: false } - - { runner: macos-latest, preset: arm64-osx-release-no-ssl-test, arch: arm64, build_type: Release, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: brew install ninja - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.9 - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- - - - name: Configure CMake - run: cmake --preset ${{ matrix.config.preset }} - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Build - run: cmake --build --preset ${{ matrix.config.preset }} -j $(nproc 2>/dev/null || sysctl -n hw.logicalcpu) - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Install - run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} - - - name: Upload build artifacts - uses: actions/upload-artifact@v6 - with: - name: macos-build-${{ matrix.config.preset }} - path: | - output/build/${{ matrix.config.preset }}/bin/ - output/build/${{ matrix.config.preset }}/lib/ - retention-days: 1 - - # macOS unit test jobs (run in parallel after build) - macos-unit-test: - name: macOS Unit Test (${{ matrix.config.preset }}) - runs-on: ${{ matrix.config.runner }} - needs: macos-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - config: - - { runner: macos-latest, preset: arm64-osx-debug-test, arch: arm64, build_type: Debug, ssl: true } - - { runner: macos-latest, preset: arm64-osx-release-test, arch: arm64, build_type: Release, ssl: true } - - { runner: macos-latest, preset: arm64-osx-debug-no-ssl-test, arch: arm64, build_type: Debug, ssl: false } - - { runner: macos-latest, preset: arm64-osx-release-no-ssl-test, arch: arm64, build_type: Release, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: brew install ninja - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: macos-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Make test executables runnable - run: chmod +x output/build/${{ matrix.config.preset }}/bin/* - - - name: Run unit tests - run: | - ctest --preset ${{ matrix.config.preset }} \ - -L unit -j $(nproc 2>/dev/null || sysctl -n hw.logicalcpu) --output-on-failure --timeout 300 - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-${{ matrix.config.preset }}-unit-${{ strategy.job-index }} - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # macOS benchmark jobs (run in parallel after build) - macos-benchmark: - name: macOS Benchmark - runs-on: ${{ matrix.config.runner }} - needs: macos-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - config: - - { runner: macos-latest, preset: arm64-osx-debug-test, arch: arm64, build_type: Debug, ssl: true } - - { runner: macos-latest, preset: arm64-osx-release-test, arch: arm64, build_type: Release, ssl: true } - - { runner: macos-latest, preset: arm64-osx-debug-no-ssl-test, arch: arm64, build_type: Debug, ssl: false } - - { runner: macos-latest, preset: arm64-osx-release-no-ssl-test, arch: arm64, build_type: Release, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: brew install ninja - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: macos-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Make test executables runnable - run: chmod +x output/build/${{ matrix.config.preset }}/bin/* - - - name: Run benchmarks - run: ctest --preset ${{ matrix.config.preset }} -L ^benchmark$ --output-on-failure --timeout 600 - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-${{ matrix.config.preset }}-benchmark - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # Linux GCC build job (builds and uploads artifacts for test jobs) - linux-gcc-build-test: - name: Linux GCC Build (Test) - runs-on: ubuntu-latest - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x64-linux-gcc-debug-test, build_type: Debug, ssl: true } - - { preset: x64-linux-gcc-release-test, build_type: Release, ssl: true } - - { preset: x64-linux-gcc-debug-no-ssl-test, build_type: Debug, ssl: false } - - { preset: x64-linux-gcc-release-no-ssl-test, build_type: Release, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.9 - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}- - - - name: Configure CMake - run: cmake --preset ${{ matrix.config.preset }} - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Build - run: cmake --build --preset ${{ matrix.config.preset }} -j $(nproc) - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Install - run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} - - - name: Upload build artifacts - uses: actions/upload-artifact@v6 - with: - name: linux-build-${{ matrix.config.preset }} - path: | - output/build/${{ matrix.config.preset }}/bin/ - output/build/${{ matrix.config.preset }}/lib/ - retention-days: 1 - - # Linux GCC unit test jobs (run in parallel after build) - linux-gcc-unit-test: - name: Linux GCC Unit Test (${{ matrix.config.preset }}) - runs-on: ubuntu-latest - needs: linux-gcc-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x64-linux-gcc-debug-test, build_type: Debug, ssl: true } - - { preset: x64-linux-gcc-release-test, build_type: Release, ssl: true } - - { preset: x64-linux-gcc-debug-no-ssl-test, build_type: Debug, ssl: false } - - { preset: x64-linux-gcc-release-no-ssl-test, build_type: Release, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: linux-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Make test executables runnable - run: chmod +x output/build/${{ matrix.config.preset }}/bin/* - - - name: Run unit tests - run: | - ctest --preset ${{ matrix.config.preset }} \ - -L unit -j $(nproc) --output-on-failure --timeout 300 - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-${{ matrix.config.preset }}-unit-${{ strategy.job-index }} - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # Linux GCC benchmark jobs (run in parallel after build) - linux-gcc-benchmark: - name: Linux GCC Benchmark - runs-on: ubuntu-latest - needs: linux-gcc-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x64-linux-gcc-debug-test, build_type: Debug, ssl: true } - - { preset: x64-linux-gcc-release-test, build_type: Release, ssl: true } - - { preset: x64-linux-gcc-debug-no-ssl-test, build_type: Debug, ssl: false } - - { preset: x64-linux-gcc-release-no-ssl-test, build_type: Release, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: linux-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Make test executables runnable - run: chmod +x output/build/${{ matrix.config.preset }}/bin/* - - - name: Run benchmarks - run: ctest --preset ${{ matrix.config.preset }} -L ^benchmark$ --output-on-failure --timeout 600 - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-${{ matrix.config.preset }}-benchmark - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # Linux GCC integration tests - run with multiple ActiveMQ versions - linux-gcc-integration-test: - name: Linux GCC Integration Test - runs-on: ubuntu-latest - needs: linux-gcc-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x64-linux-gcc-release-no-ssl-test, build_type: Release } - activemq: - - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } - - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: linux-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Make test executables runnable - run: chmod +x output/build/${{ matrix.config.preset }}/bin/* - - - name: Start ActiveMQ (${{ matrix.activemq.name }}) - run: | - echo "Starting ActiveMQ using image: ${{ matrix.activemq.image }}" - ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose up -d - echo "Waiting for ActiveMQ to be ready..." - timeout 60 bash -c 'until docker compose ps | grep -q "healthy"; do sleep 2; done' || true - sleep 10 - - - name: Show broker status - run: docker compose ps - - - name: Run OpenWire integration tests (${{ matrix.activemq.name }}) - run: ctest --preset ${{ matrix.config.preset }} -L ^integration-openwire$ --output-on-failure --timeout 900 - - - name: Run STOMP integration tests (${{ matrix.activemq.name }}) - run: ctest --preset ${{ matrix.config.preset }} -L ^integration-stomp$ --output-on-failure --timeout 900 - - - name: Show broker logs on failure - if: failure() - run: | - echo "=== ActiveMQ logs ===" - docker compose logs --tail 100 || true - - - name: Stop ActiveMQ - if: always() - run: docker compose down - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-gcc-integration-${{ matrix.activemq.name }} - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # Linux GCC SSL integration tests - linux-gcc-ssl-integration-test: - name: Linux GCC SSL Integration Test - runs-on: ubuntu-latest - needs: linux-gcc-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x64-linux-gcc-release-test, build_type: Release } - activemq: - - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } - - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: linux-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Make test executables runnable - run: chmod +x output/build/${{ matrix.config.preset }}/bin/* - - - name: Start SSL broker (${{ matrix.activemq.name }}) - run: | - echo "Starting SSL-enabled ActiveMQ using image: ${{ matrix.activemq.image }}" - ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose --profile ssl up -d - echo "Waiting for SSL broker to be ready..." - timeout 60 bash -c 'until docker compose --profile ssl ps | grep -q "healthy"; do sleep 2; done' || true - sleep 10 - - - name: Show broker status - run: docker compose --profile ssl ps - - - name: Show broker logs (startup) - run: docker compose --profile ssl logs --tail 50 - - - name: Run OpenWire SSL integration tests (${{ matrix.activemq.name }}) - run: ctest --preset ${{ matrix.config.preset }} -L integration-openwire-ssl --output-on-failure --timeout 900 - env: - SSL_CERT_FILE: ${{ github.workspace }}/docker/ssl/certs/ca.pem - - - name: Show broker logs on failure - if: failure() - run: | - echo "=== ActiveMQ SSL broker logs ===" - docker compose --profile ssl logs --tail 200 || true - - - name: Stop SSL broker - if: always() - run: docker compose --profile ssl down - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-gcc-ssl-integration-${{ matrix.activemq.name }} - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # Linux GCC integration benchmark tests - linux-gcc-integration-benchmark-test: - name: Linux GCC Integration Benchmark Test - runs-on: ubuntu-latest - needs: linux-gcc-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x64-linux-gcc-release-test, build_type: Release } - activemq: - - { name: "AMQ-5.18", image: "apache/activemq-classic:5.18.7" } - - { name: "AMQ-6.2", image: "apache/activemq-classic:6.2.0" } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y ninja-build - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: linux-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Make test executables runnable - run: chmod +x output/build/${{ matrix.config.preset }}/bin/* - - - name: Start all brokers (${{ matrix.activemq.name }}) - run: | - echo "Starting ActiveMQ brokers using image: ${{ matrix.activemq.image }}" - ACTIVEMQ_IMAGE=${{ matrix.activemq.image }} docker compose --profile failover up -d - echo "Waiting for all brokers to be ready..." - sleep 30 - - - name: Show broker status - run: docker compose --profile failover ps - - - name: Run integration benchmark tests (${{ matrix.activemq.name }}) - run: ctest --preset ${{ matrix.config.preset }} -L integration-benchmark --output-on-failure --timeout 1800 - - - name: Show broker logs on failure - if: failure() - run: | - echo "=== activemq-failover-1 logs ===" - docker compose --profile failover logs activemq1 --tail 100 || true - echo "=== activemq-failover-2 logs ===" - docker compose --profile failover logs activemq2 --tail 100 || true - echo "=== activemq-multi-3 logs ===" - docker compose --profile failover logs activemq3 --tail 100 || true - - - name: Stop all brokers - if: always() - run: docker compose --profile failover down - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-gcc-integration-benchmark-${{ matrix.activemq.name }} - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # macOS builds without tests (all variants) - macos-build: - name: macOS Build - runs-on: ${{ matrix.config.runner }} - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" - - strategy: - fail-fast: false - matrix: - config: - # Apple Silicon arm64 builds - - { runner: macos-latest, preset: arm64-osx-debug, arch: arm64 } - - { runner: macos-latest, preset: arm64-osx-release, arch: arm64 } - - { runner: macos-latest, preset: arm64-osx-debug-static, arch: arm64 } - - { runner: macos-latest, preset: arm64-osx-release-static, arch: arm64 } - - { runner: macos-latest, preset: arm64-osx-debug-no-ssl, arch: arm64 } - - { runner: macos-latest, preset: arm64-osx-release-no-ssl, arch: arm64 } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install system dependencies - run: brew install ninja - - - name: Set VCPKG_ROOT environment variable - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.9 - - - name: Create vcpkg binary cache directory - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- - - - name: Configure CMake - run: cmake --preset ${{ matrix.config.preset }} - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Build - run: cmake --build --preset ${{ matrix.config.preset }} -j $(nproc 2>/dev/null || sysctl -n hw.logicalcpu) - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Install - run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} - - # Windows CL build job (builds and uploads artifacts for test jobs) - windows-cl-build-test: - name: Windows CL Build (Test) - runs-on: windows-latest - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,readwrite" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x86-windows-cl-debug-test, build_type: Debug, arch: x86, ssl: true } - - { preset: x86-windows-cl-release-test, build_type: Release, arch: x86, ssl: true } - - { preset: x64-windows-cl-debug-test, build_type: Debug, arch: x64, ssl: true } - - { preset: x64-windows-cl-release-test, build_type: Release, arch: x64, ssl: true } - - { preset: x64-windows-cl-debug-no-ssl-test, build_type: Debug, arch: x64, ssl: false } - - { preset: x64-windows-cl-release-no-ssl-test, build_type: Release, arch: x64, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install Ninja - run: choco install ninja -y - - - name: Setup sccache - uses: mozilla-actions/sccache-action@v0.0.9 - - - name: Setup MSVC Developer Command Prompt - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: ${{ matrix.config.arch }} - - - name: Set VCPKG_ROOT environment variable - shell: bash - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - shell: bash - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- - - - name: Configure CMake - run: cmake --preset ${{ matrix.config.preset }} - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Build - run: cmake --build --preset ${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} - env: - SCCACHE_GHA_ENABLED: "true" - - - name: Install - run: cmake --install output/build/${{ matrix.config.preset }} --prefix output/install/${{ matrix.config.preset }} --config ${{ matrix.config.build_type }} - - - name: Upload build artifacts - uses: actions/upload-artifact@v6 - with: - name: windows-build-${{ matrix.config.preset }} - path: | - output/build/${{ matrix.config.preset }}/bin/ - output/build/${{ matrix.config.preset }}/lib/ - retention-days: 1 - - # Windows CL unit test jobs (run in parallel after build) - windows-cl-unit-test: - name: Windows CL Unit Test (${{ matrix.config.preset }}) - runs-on: windows-latest - needs: windows-cl-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x86-windows-cl-debug-test, build_type: Debug, arch: x86, ssl: true } - - { preset: x86-windows-cl-release-test, build_type: Release, arch: x86, ssl: true } - - { preset: x64-windows-cl-debug-test, build_type: Debug, arch: x64, ssl: true } - - { preset: x64-windows-cl-release-test, build_type: Release, arch: x64, ssl: true } - - { preset: x64-windows-cl-debug-no-ssl-test, build_type: Debug, arch: x64, ssl: false } - - { preset: x64-windows-cl-release-no-ssl-test, build_type: Release, arch: x64, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install Ninja - run: choco install ninja -y - - - name: Setup MSVC Developer Command Prompt - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: ${{ matrix.config.arch }} - - - name: Set VCPKG_ROOT environment variable - shell: bash - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - shell: bash - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: windows-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Run unit tests - run: | - ctest --preset ${{ matrix.config.preset }} -C ${{ matrix.config.build_type }} -L unit -j $env:NUMBER_OF_PROCESSORS --output-on-failure --timeout 300 - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-${{ matrix.config.preset }}-unit-${{ strategy.job-index }} - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log - - # Windows CL benchmark jobs (run in parallel after build) - windows-cl-benchmark: - name: Windows CL Benchmark - runs-on: windows-latest - needs: windows-cl-build-test - - env: - VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.cache/vcpkg/archives,read" - - strategy: - fail-fast: false - matrix: - config: - - { preset: x86-windows-cl-debug-test, build_type: Debug, arch: x86, ssl: true } - - { preset: x86-windows-cl-release-test, build_type: Release, arch: x86, ssl: true } - - { preset: x64-windows-cl-debug-test, build_type: Debug, arch: x64, ssl: true } - - { preset: x64-windows-cl-release-test, build_type: Release, arch: x64, ssl: true } - - { preset: x64-windows-cl-debug-no-ssl-test, build_type: Debug, arch: x64, ssl: false } - - { preset: x64-windows-cl-release-no-ssl-test, build_type: Release, arch: x64, ssl: false } - - steps: - - name: Checkout code - uses: actions/checkout@v6 - - - name: Install Ninja - run: choco install ninja -y - - - name: Setup MSVC Developer Command Prompt - uses: ilammy/msvc-dev-cmd@v1 - with: - arch: ${{ matrix.config.arch }} - - - name: Set VCPKG_ROOT environment variable - shell: bash - run: echo "VCPKG_ROOT=$VCPKG_INSTALLATION_ROOT" >> $GITHUB_ENV - - - name: Create vcpkg binary cache directory - shell: bash - run: mkdir -p "${{ github.workspace }}/.cache/vcpkg/archives" - - - name: Cache vcpkg binary packages - uses: actions/cache@v5 - with: - path: ${{ github.workspace }}/.cache/vcpkg/archives - key: vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}-${{ hashFiles('vcpkg.json') }} - restore-keys: | - vcpkg-binary-${{ runner.os }}-${{ matrix.config.arch }}- - - - name: Configure CMake (for CTest) - run: cmake --preset ${{ matrix.config.preset }} - - - name: Download build artifacts - uses: actions/download-artifact@v7 - with: - name: windows-build-${{ matrix.config.preset }} - path: output/build/${{ matrix.config.preset }}/ - - - name: Run benchmarks - run: ctest --preset ${{ matrix.config.preset }} -C ${{ matrix.config.build_type }} -L ^benchmark$ --output-on-failure --timeout 600 - - - name: Upload test results - if: failure() - uses: actions/upload-artifact@v6 - with: - name: test-results-${{ matrix.config.preset }}-benchmark - path: | - output/build/${{ matrix.config.preset }}/Testing/Temporary/ - output/build/${{ matrix.config.preset }}/**/*.log From 0785c08f111cb283c4ad4518dac02b56fc8e57e7 Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Fri, 20 Feb 2026 12:31:35 +0700 Subject: [PATCH 14/25] Refactor FailoverTransport to improve reconnect handling and reduce shutdown timeout Signed-off-by: blackb1rd --- .../transport/failover/FailoverTransport.cpp | 55 +++++++++++++++++-- 1 file changed, 49 insertions(+), 6 deletions(-) diff --git a/activemq-cpp/src/main/activemq/transport/failover/FailoverTransport.cpp b/activemq-cpp/src/main/activemq/transport/failover/FailoverTransport.cpp index 1f731ca1a..70f323b0b 100644 --- a/activemq-cpp/src/main/activemq/transport/failover/FailoverTransport.cpp +++ b/activemq-cpp/src/main/activemq/transport/failover/FailoverTransport.cpp @@ -827,7 +827,7 @@ void FailoverTransport::close() { transportToStop->close(); } - this->impl->taskRunner->shutdown(TimeUnit::MINUTES.toMillis(5)); + this->impl->taskRunner->shutdown(TimeUnit::SECONDS.toMillis(30)); } AMQ_CATCH_RETHROW(IOException) AMQ_CATCH_EXCEPTION_CONVERT(Exception, IOException) @@ -1075,7 +1075,12 @@ bool FailoverTransport::iterate() { << ", connectFailures=" << this->impl->connectFailures << ", closed=" << this->impl->closed); - synchronized(&this->impl->reconnectMutex) { + { + // Use an explicit Lock instead of the synchronized macro so we can temporarily + // release reconnectMutex during the reconnect delay sleep. This lets close() + // acquire the mutex, set closed=true, and interrupt the sleep via + // sleepMutex.notifyAll() without waiting up to 30 seconds for the sleep to expire. + Lock reconnectLock(&this->impl->reconnectMutex); if (this->impl->isClosedOrFailed()) { this->impl->reconnectMutex.notifyAll(); @@ -1172,19 +1177,57 @@ bool FailoverTransport::iterate() { } } - // Sleep for the reconnectDelay if there's no backup and we aren't trying - // for the first time, or we were disposed for some reason. + // Capture the reconnect delay before releasing reconnectMutex. + // The actual sleep happens OUTSIDE reconnectMutex (below) so that close() + // can acquire the mutex, set closed=true, and interrupt the sleep via + // sleepMutex.notifyAll(). Previously the sleep held reconnectMutex, + // which blocked close() for the full reconnectDelay (up to 30 seconds). + long long sleepDelay = 0; if (transport == NULL && !this->impl->firstConnection && (this->impl->reconnectDelay > 0) && !this->impl->closed) { - synchronized (&this->impl->sleepMutex) { + sleepDelay = this->impl->reconnectDelay; + } + + // Release reconnectMutex before sleeping so close() can acquire it and: + // 1. Set closed=true immediately + // 2. Signal sleepMutex to wake us up early + reconnectLock.unlock(); + + // Sleep OUTSIDE reconnectMutex - close() can now interrupt us via + // sleepMutex.notifyAll() without waiting for us to finish sleeping. + if (sleepDelay > 0) { + synchronized(&this->impl->sleepMutex) { try { - this->impl->sleepMutex.wait(this->impl->reconnectDelay); + this->impl->sleepMutex.wait(sleepDelay); } catch (InterruptedException& e) { Thread::currentThread()->interrupt(); } } } + // Re-acquire reconnectMutex after sleep to proceed with reconnection. + reconnectLock.lock(); + + // Re-check state: close()/handleTransportFailure() may have run while we slept. + if (this->impl->isClosedOrFailed()) { + this->impl->reconnectMutex.notifyAll(); + if (transport != NULL) { + this->impl->closeTask->add(transport); + this->impl->taskRunner->wakeup(); + transport.reset(NULL); + } + return false; + } + + if (this->impl->isConnectionStateValid()) { + if (transport != NULL) { + this->impl->closeTask->add(transport); + this->impl->taskRunner->wakeup(); + transport.reset(NULL); + } + return false; + } + while ((transport != NULL || !connectList->isEmpty()) && this->impl->connectedTransport == NULL && !this->impl->closed) { try { // We could be starting the loop with a backup already. From b578ca5cde218ce9f441a9ddb68520205dcb62f1 Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Fri, 20 Feb 2026 17:48:28 +0700 Subject: [PATCH 15/25] Improve BackupTransportPool and InactivityMonitor error handling to prevent potential crashes during transport teardown Signed-off-by: blackb1rd --- .../failover/BackupTransportPool.cpp | 151 +++++++++++------- .../inactivity/InactivityMonitor.cpp | 6 + 2 files changed, 103 insertions(+), 54 deletions(-) diff --git a/activemq-cpp/src/main/activemq/transport/failover/BackupTransportPool.cpp b/activemq-cpp/src/main/activemq/transport/failover/BackupTransportPool.cpp index 00d91d115..0aff8104c 100644 --- a/activemq-cpp/src/main/activemq/transport/failover/BackupTransportPool.cpp +++ b/activemq-cpp/src/main/activemq/transport/failover/BackupTransportPool.cpp @@ -281,87 +281,130 @@ bool BackupTransportPool::isPending() const { //////////////////////////////////////////////////////////////////////////////// bool BackupTransportPool::iterate() { + // Fast exit if the pool is being torn down or has been disabled. + if (this->impl->closed || !this->isEnabled()) { + return false; + } + bool needsRetry = false; + bool wakeupParent = false; LinkedList failures; - synchronized(&this->impl->backups) { - - Pointer uriPool = this->uriPool; - - // We prefer the Broker updated URIs list if it has any URIs. - if (!updates->isEmpty()) { - uriPool = updates; - } - - bool wakeupParent = false; + // Determine which URI pool to use. Prefer broker-pushed updates when + // available. URIPool is internally synchronized so no external lock is + // needed here. + Pointer activeUriPool = this->uriPool; + if (!this->updates->isEmpty()) { + activeUriPool = this->updates; + } - while (impl->shouldBuildBackup()) { + while (!this->impl->closed && this->isEnabled()) { - URI connectTo; + URI connectTo; + bool foundWork = false; - // Try for a URI, if one isn't free return and indicate this task - // is done for now, the next time a backup is requested this task - // will become pending again and we will attempt to fill the pool. - // This will break the loop once we've tried all possible UIRs. - try { - connectTo = uriPool->getURI(); - } catch (NoSuchElementException& ex) { - break; + // Brief critical section: check whether we still need a backup and + // dequeue one URI to try. We release the lock immediately so that + // close()/setEnabled(false) are never blocked for the full TCP + // connect duration. + synchronized(&this->impl->backups) { + if (impl->shouldBuildBackup()) { + try { + connectTo = activeUriPool->getURI(); + foundWork = true; + } catch (NoSuchElementException&) { + // No URIs available right now; exit the loop. + } } + } - Pointer backup(new BackupTransport(this)); - backup->setUri(connectTo); - - try { - Pointer transport = createTransport(connectTo); + if (!foundWork) { + break; + } - transport->setTransportListener(backup.get()); - transport->start(); - backup->setTransport(transport); + // Attempt the TCP connection WITHOUT holding the backups lock. + // This is the critical change: previously the lock was held here, + // which blocked setEnabled(false) (called by close() while holding + // reconnectMutex) for the full connect-timeout duration, causing a + // lock-ordering stall of up to 300 s. + Pointer backup(new BackupTransport(this)); + backup->setUri(connectTo); + + try { + Pointer transport = createTransport(connectTo); + transport->setTransportListener(backup.get()); + transport->start(); // May block for TCP connect timeout — must NOT hold backups lock. + + // Re-acquire the lock to add the backup to the pool, but first + // check whether a shutdown occurred while we were connecting. + bool closedOrDisabled = false; + synchronized(&this->impl->backups) { + if (this->impl->closed || !this->isEnabled()) { + closedOrDisabled = true; + } else { + backup->setTransport(transport); - if (priorityUriPool->contains(connectTo) || (priorityUriPool->isEmpty() && uriPool->isPriority(connectTo))) { - backup->setPriority(true); + if (priorityUriPool->contains(connectTo) || + (priorityUriPool->isEmpty() && activeUriPool->isPriority(connectTo))) { + backup->setPriority(true); - if (!parent->isConnectedToPriority()) { - wakeupParent = true; + if (!parent->isConnectedToPriority()) { + wakeupParent = true; + } } - } - // Put any priority connections first so a reconnect picks them - // up automatically. - if (backup->isPriority()) { - this->impl->priorityBackups++; - this->impl->backups.addFirst(backup); - } else { - this->impl->backups.addLast(backup); + // Put priority connections first so a reconnect picks them + // up automatically. + if (backup->isPriority()) { + this->impl->priorityBackups++; + this->impl->backups.addFirst(backup); + } else { + this->impl->backups.addLast(backup); + } } - - } catch (...) { - // Store it in the list of URIs that didn't work, once done we - // return those to the pool. - failures.add(connectTo); } - // We connected to a priority backup and the parent isn't already using one - // so wake it up and quit the backups process for now. - if (wakeupParent) { - this->parent->reconnect(false); + if (closedOrDisabled) { + // A shutdown raced our connect. Hand the transport to the + // async close task and return the URI for future retries. + transport->setTransportListener(NULL); + this->closeTask->add(transport); + activeUriPool->addURI(connectTo); break; } + + } catch (...) { + // Connection failed; collect the URI and try the next one. + failures.add(connectTo); } - // return all failures to the URI Pool, we can try again later. - uriPool->addURIs(failures); + // We connected to a priority backup and the parent is not already + // using one. Break out so we can call reconnect() outside any lock + // (calling it inside the backups lock risks an ABBA deadlock with + // reconnectMutex, which close() holds while calling setEnabled()). + if (wakeupParent) { + break; + } + } - // Check if we still need more backups after this attempt - needsRetry = impl->shouldBuildBackup(); + // Return all failed URIs to the pool (URIPool is internally synchronized). + activeUriPool->addURIs(failures); + // Check whether more work remains and clear the pending flag. + synchronized(&this->impl->backups) { + needsRetry = impl->shouldBuildBackup(); this->impl->pending = false; } + // Notify the parent to reconnect to the newly-available priority backup. + // Called OUTSIDE any lock to avoid the ABBA deadlock with reconnectMutex. + if (wakeupParent && !this->impl->closed) { + this->parent->reconnect(false); + } + // Rate-limit retry attempts when we couldn't fill the backup pool // (e.g., target broker isn't available yet). Uses an interruptible - // wait so close() can wake us immediately. + // wait so close() can wake us immediately via retryMutex.notifyAll(). if (needsRetry && !this->impl->closed) { synchronized(&this->impl->retryMutex) { if (!this->impl->closed) { diff --git a/activemq-cpp/src/main/activemq/transport/inactivity/InactivityMonitor.cpp b/activemq-cpp/src/main/activemq/transport/inactivity/InactivityMonitor.cpp index 3e9cbcc3a..6a6c85415 100644 --- a/activemq-cpp/src/main/activemq/transport/inactivity/InactivityMonitor.cpp +++ b/activemq-cpp/src/main/activemq/transport/inactivity/InactivityMonitor.cpp @@ -158,6 +158,9 @@ namespace inactivity { IOException ex(__FILE__, __LINE__, (std::string("Channel was inactive for too long: ") + remote).c_str()); this->parent->onException(ex); + // onException() may destroy 'this' via the transport teardown chain. + // compareAndSet already cleared 'failed' to false, so return false directly. + return false; } return this->failed.get(); @@ -197,6 +200,9 @@ namespace inactivity { this->parent->oneway(info); } catch (IOException& e) { this->parent->onException(e); + // onException() may destroy 'this' via the transport teardown chain. + // compareAndSet already cleared 'write' to false, so return false directly. + return false; } } From 22bbab3a58549771976fdcc052edbb365fb9331c Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Fri, 20 Feb 2026 20:01:23 +0700 Subject: [PATCH 16/25] Enhance memory management in CompositeTaskRunner and TcpSocket by using shared_ptr for impl; add coding guideline to avoid auto type deduction Signed-off-by: blackb1rd --- AGENTS.md | 17 ++++ .../activemq/threads/CompositeTaskRunner.cpp | 79 ++++++++++------ .../activemq/threads/CompositeTaskRunner.h | 3 +- .../main/decaf/internal/net/tcp/TcpSocket.cpp | 89 +++++++++++-------- 4 files changed, 124 insertions(+), 64 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f83be7034..b1c2fa13f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,6 +42,23 @@ ctest --preset x86-windows-cl-debug-test ## Coding Guidelines +### Avoid `auto` + +- **DO NOT** use `auto` for variable type deduction +- **ALWAYS** write the explicit type name +- **REASON**: Explicit types make code easier to read, review, and reason about, especially in a multi-threaded codebase where the type of a variable directly communicates ownership and lifetime + +**Example:** +```cpp +// BAD: type is hidden +auto localImpl = this->impl; +auto it = tasks.begin(); + +// GOOD: type is explicit +std::shared_ptr localImpl = this->impl; +LinkedList::iterator it = tasks.begin(); +``` + ### Avoid Static Storage - **DO NOT** use `static` or `static thread_local` for storing state diff --git a/activemq-cpp/src/main/activemq/threads/CompositeTaskRunner.cpp b/activemq-cpp/src/main/activemq/threads/CompositeTaskRunner.cpp index 8608d7afe..af26420e8 100644 --- a/activemq-cpp/src/main/activemq/threads/CompositeTaskRunner.cpp +++ b/activemq-cpp/src/main/activemq/threads/CompositeTaskRunner.cpp @@ -71,23 +71,34 @@ namespace threads { }} //////////////////////////////////////////////////////////////////////////////// -CompositeTaskRunner::CompositeTaskRunner() : impl(new CompositeTaskRunnerImpl) { +CompositeTaskRunner::CompositeTaskRunner() : impl(std::make_shared()) { this->impl->thread.reset(new Thread(this, "ActiveMQ CompositeTaskRunner Thread")); } //////////////////////////////////////////////////////////////////////////////// CompositeTaskRunner::~CompositeTaskRunner() { try { - shutdown(); - impl->thread->join(); - impl->thread.reset(NULL); - } - AMQ_CATCHALL_NOTHROW() - - try { - delete this->impl; + // Keep a local reference so impl stays alive while we access it, even if + // this destructor is invoked from within the runner thread itself (via a + // task callback that triggers transport teardown). + std::shared_ptr localImpl = this->impl; + if (localImpl) { + shutdown(); + // Only join from an external thread; a self-join would deadlock or be + // a no-op depending on the platform, and the thread is still running + // up the call-stack when the destructor is called re-entrantly. + if (localImpl->thread != NULL && + Thread::currentThread() != localImpl->thread.get()) { + localImpl->thread->join(); + } + if (localImpl->thread != NULL) { + localImpl->thread.reset(NULL); + } + } } AMQ_CATCHALL_NOTHROW() + // impl shared_ptr released here; the CompositeTaskRunnerImpl memory is freed + // only once every local copy (including those held by run()/iterate()) is gone. } //////////////////////////////////////////////////////////////////////////////// @@ -191,30 +202,35 @@ void CompositeTaskRunner::wakeup() { //////////////////////////////////////////////////////////////////////////////// void CompositeTaskRunner::run() { + // Capture a local shared_ptr so impl stays alive for the entire lifetime of + // this thread function, even if ~CompositeTaskRunner() releases its reference + // re-entrantly from within a task callback. + std::shared_ptr localImpl = this->impl; + try { while (true) { // Check state with memory barrier - if (impl->state.load(std::memory_order_acquire) != TaskRunnerState::RUNNING) { + if (localImpl->state.load(std::memory_order_acquire) != TaskRunnerState::RUNNING) { break; } - synchronized(&impl->mutex) { - impl->pending.store(false, std::memory_order_release); + synchronized(&localImpl->mutex) { + localImpl->pending.store(false, std::memory_order_release); } if (!this->iterate()) { // wait to be notified. - synchronized(&impl->mutex) { + synchronized(&localImpl->mutex) { // Double-check state before waiting - if (impl->state.load(std::memory_order_acquire) != TaskRunnerState::RUNNING) { + if (localImpl->state.load(std::memory_order_acquire) != TaskRunnerState::RUNNING) { break; } // Use timed wait to periodically check state - while (!impl->pending.load(std::memory_order_acquire) && - impl->state.load(std::memory_order_acquire) == TaskRunnerState::RUNNING) { - impl->mutex.wait(100); // 100ms timeout + while (!localImpl->pending.load(std::memory_order_acquire) && + localImpl->state.load(std::memory_order_acquire) == TaskRunnerState::RUNNING) { + localImpl->mutex.wait(100); // 100ms timeout } } } @@ -223,12 +239,12 @@ void CompositeTaskRunner::run() { AMQ_CATCHALL_NOTHROW() // Mark as stopped with memory barrier - impl->state.store(TaskRunnerState::STOPPED, std::memory_order_release); + localImpl->state.store(TaskRunnerState::STOPPED, std::memory_order_release); std::atomic_thread_fence(std::memory_order_seq_cst); // Notify any waiting threads - synchronized(&impl->mutex) { - impl->mutex.notifyAll(); + synchronized(&localImpl->mutex) { + localImpl->mutex.notifyAll(); } } @@ -257,21 +273,34 @@ void CompositeTaskRunner::removeTask(CompositeTask* task) { //////////////////////////////////////////////////////////////////////////////// bool CompositeTaskRunner::iterate() { - synchronized(&impl->tasks) { + // Capture a local shared_ptr so impl remains valid even if task->iterate() + // triggers a re-entrant call to ~CompositeTaskRunner() on this same thread + // (e.g. via InactivityMonitor::onException() → transport teardown chain). + std::shared_ptr localImpl = this->impl; + + synchronized(&localImpl->tasks) { - for (int i = 0; i < impl->tasks.size(); ++i) { - CompositeTask* task = impl->tasks.pop(); + for (int i = 0; i < localImpl->tasks.size(); ++i) { + CompositeTask* task = localImpl->tasks.pop(); if (task != NULL) { if (task->isPending()) { task->iterate(); - impl->tasks.addLast(task); + + // task->iterate() may have caused ~CompositeTaskRunner() to run + // on this thread. localImpl keeps impl alive, but if we are + // shutting down we must not touch the task list further. + if (localImpl->state.load(std::memory_order_acquire) != TaskRunnerState::RUNNING) { + return false; + } + + localImpl->tasks.addLast(task); // Always return true, so that we check again for any of // the other tasks that might now be pending. return true; } else { - impl->tasks.addLast(task); + localImpl->tasks.addLast(task); } } } diff --git a/activemq-cpp/src/main/activemq/threads/CompositeTaskRunner.h b/activemq-cpp/src/main/activemq/threads/CompositeTaskRunner.h index 528e1e908..5263cf5cf 100644 --- a/activemq-cpp/src/main/activemq/threads/CompositeTaskRunner.h +++ b/activemq-cpp/src/main/activemq/threads/CompositeTaskRunner.h @@ -27,6 +27,7 @@ #include #include #include +#include namespace activemq { namespace threads { @@ -44,7 +45,7 @@ namespace threads { public decaf::lang::Runnable { private: - CompositeTaskRunnerImpl* impl; + std::shared_ptr impl; private: diff --git a/activemq-cpp/src/main/decaf/internal/net/tcp/TcpSocket.cpp b/activemq-cpp/src/main/decaf/internal/net/tcp/TcpSocket.cpp index 3c2b6f35f..3b49c5592 100644 --- a/activemq-cpp/src/main/decaf/internal/net/tcp/TcpSocket.cpp +++ b/activemq-cpp/src/main/decaf/internal/net/tcp/TcpSocket.cpp @@ -994,41 +994,41 @@ int TcpSocket::read(unsigned char* buffer, int size, int offset, int length) { asio::error_code ec; std::size_t bytesRead = 0; - if (this->impl->soTimeout > 0) { - AMQ_LOG_DEBUG("TcpSocket", "read() async with timeout=" << this->impl->soTimeout << " length=" << length); - // Async read with timeout - // Use shared_ptr for synchronization state to prevent use-after-free if lambda executes after timeout - struct ReadState { - std::mutex mutex; - std::condition_variable cv; - bool complete; - asio::error_code error; - std::size_t bytes; - ReadState() : complete(false), bytes(0) {} - }; - auto state = std::make_shared(); - - this->impl->socket->async_read_some( - asio::buffer(buffer + offset, length), - [state](const asio::error_code& error, std::size_t bytes) { - AMQ_LOG_DEBUG("TcpSocket", "async_read_some callback: error=" << error.message() << " bytes=" << bytes); - { - std::lock_guard lock(state->mutex); - state->error = error; - state->bytes = bytes; - state->complete = true; - } - state->cv.notify_one(); + // Use shared_ptr for synchronization state to prevent use-after-free if lambda executes + // after the waiting thread has returned (e.g., on timeout or cancellation). + struct ReadState { + std::mutex mutex; + std::condition_variable cv; + bool complete; + asio::error_code error; + std::size_t bytes; + ReadState() : complete(false), bytes(0) {} + }; + auto state = std::make_shared(); + + this->impl->socket->async_read_some( + asio::buffer(buffer + offset, length), + [state](const asio::error_code& error, std::size_t bytes) { + AMQ_LOG_DEBUG("TcpSocket", "async_read_some callback: error=" << error.message() << " bytes=" << bytes); + { + std::lock_guard lock(state->mutex); + state->error = error; + state->bytes = bytes; + state->complete = true; } - ); + state->cv.notify_one(); + } + ); + if (this->impl->soTimeout > 0) { + AMQ_LOG_DEBUG("TcpSocket", "read() async with timeout=" << this->impl->soTimeout << " length=" << length); // Wait with timeout std::unique_lock lock(state->mutex); if (!state->cv.wait_for(lock, std::chrono::milliseconds(this->impl->soTimeout), [&state]{ return state->complete; })) { AMQ_LOG_DEBUG("TcpSocket", "read() TIMEOUT after " << this->impl->soTimeout << "ms, cancelling"); - // Timeout - cancel operation but don't wait for completion - // The lambda will still execute but state will be kept alive by shared_ptr + // Timeout - cancel operation but don't wait for completion. + // The lambda will still execute but state will be kept alive by shared_ptr. this->impl->socket->cancel(); throw SocketTimeoutException(__FILE__, __LINE__, "Read timed out"); } @@ -1042,8 +1042,8 @@ int TcpSocket::read(unsigned char* buffer, int size, int offset, int length) { throw IOException(__FILE__, __LINE__, "The connection is closed"); } - // If operation was cancelled (e.g., due to timeout or close), we should have already thrown - // If we reach here with operation_aborted, it's a race condition - treat as timeout + // If operation was cancelled (e.g., due to timeout or close), we should have already thrown. + // If we reach here with operation_aborted, it's a race condition - treat as timeout. if (ec == asio::error::operation_aborted) { if (isClosed()) { throw IOException(__FILE__, __LINE__, "The connection is closed"); @@ -1051,14 +1051,27 @@ int TcpSocket::read(unsigned char* buffer, int size, int offset, int length) { throw SocketTimeoutException(__FILE__, __LINE__, "Read timed out"); } } else { - // Blocking read - read_some() blocks until SOME data is available (not necessarily all requested) - // This matches the behavior of APR's apr_socket_recv() in the original Apache ActiveMQ-CPP - bytesRead = this->impl->socket->read_some( - asio::buffer(buffer + offset, length), ec); - - // Warn if we got 0 bytes without EOF - this shouldn't normally happen with blocking reads - if (bytesRead == 0 && !ec) { - AMQ_LOG_DEBUG("TcpSocket", "WARNING: read_some returned 0 bytes with no error"); + AMQ_LOG_DEBUG("TcpSocket", "read() async blocking (polling) length=" << length); + // "Blocking" read implemented via async I/O with periodic close-check polling. + // Synchronous read_some() cannot be safely interrupted when socket->close() is called + // concurrently from the transport teardown path (undefined behaviour per POSIX/ASIO + // threading rules on shared objects). Using async + condition variable ensures the + // reader thread wakes within ~100 ms of the socket being closed. + std::unique_lock lock(state->mutex); + while (!state->complete) { + state->cv.wait_for(lock, std::chrono::milliseconds(100)); + if (!state->complete && isClosed()) { + // socket->close() has already cancelled the pending async op. + // Throw immediately - 'state' is kept alive by the lambda's shared_ptr + // capture, so the eventual operation_aborted callback is safe to execute. + throw IOException(__FILE__, __LINE__, "The connection is closed"); + } + } + ec = state->error; + bytesRead = state->bytes; + + if (ec == asio::error::operation_aborted || isClosed()) { + throw IOException(__FILE__, __LINE__, "The connection is closed"); } } From 386c218fa29b3fb3ee604f5a43cab6bc7aae89ae Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Fri, 20 Feb 2026 20:26:47 +0700 Subject: [PATCH 17/25] Update SecureRandomImpl to use BCryptGenRandom for improved cryptographic security; modify CMakeLists.txt to link with bcrypt library Signed-off-by: blackb1rd --- activemq-cpp/src/main/CMakeLists.txt | 2 +- activemq-cpp/src/main/decaf/CMakeLists.txt | 2 +- .../security/windows/SecureRandomImpl.cpp | 91 +++---------------- .../security/windows/SecureRandomImpl.h | 13 +-- 4 files changed, 16 insertions(+), 92 deletions(-) diff --git a/activemq-cpp/src/main/CMakeLists.txt b/activemq-cpp/src/main/CMakeLists.txt index 8e619c80a..35c8aa516 100644 --- a/activemq-cpp/src/main/CMakeLists.txt +++ b/activemq-cpp/src/main/CMakeLists.txt @@ -757,7 +757,7 @@ if(WIN32) AMQCPP_DLL ) endif() - target_link_libraries(neoactivemq-cpp PRIVATE ws2_32) + target_link_libraries(neoactivemq-cpp PRIVATE ws2_32 bcrypt) target_compile_definitions(neoactivemq-cpp PRIVATE _WIN32_WINNT=0x0601) endif() diff --git a/activemq-cpp/src/main/decaf/CMakeLists.txt b/activemq-cpp/src/main/decaf/CMakeLists.txt index 12e97f3f3..b998e0b2c 100644 --- a/activemq-cpp/src/main/decaf/CMakeLists.txt +++ b/activemq-cpp/src/main/decaf/CMakeLists.txt @@ -55,7 +55,7 @@ if(WIN32) if(AMQCPP_SHARED_LIB) set_target_properties(decaf PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS ON) endif() - target_link_libraries(decaf PRIVATE ws2_32) + target_link_libraries(decaf PRIVATE ws2_32 bcrypt) target_compile_definitions(decaf PRIVATE _WIN32_WINNT=0x0601) endif() diff --git a/activemq-cpp/src/main/decaf/internal/security/windows/SecureRandomImpl.cpp b/activemq-cpp/src/main/decaf/internal/security/windows/SecureRandomImpl.cpp index 335d17a73..a3e4a924b 100644 --- a/activemq-cpp/src/main/decaf/internal/security/windows/SecureRandomImpl.cpp +++ b/activemq-cpp/src/main/decaf/internal/security/windows/SecureRandomImpl.cpp @@ -21,84 +21,30 @@ #include #include #include -#include - -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0500 #include -#include +#include using namespace decaf; using namespace decaf::lang; using namespace decaf::lang::exceptions; -using namespace decaf::util; using namespace decaf::security; using namespace decaf::internal; using namespace decaf::internal::security; -//////////////////////////////////////////////////////////////////////////////// -namespace decaf { -namespace internal { -namespace security { - - class SRNGData { - private: - - SRNGData( const SRNGData& ); - SRNGData operator= ( const SRNGData& ); - - public: - - std::unique_ptr random; - - SRNGData() : random() { - } - - }; - -}}} - //////////////////////////////////////////////////////////////////////////////// SecureRandomImpl::SecureRandomImpl() { - - this->config = new SRNGData(); - - try{ - - HCRYPTPROV provider; - int result = CryptAcquireContext( &provider, NULL, NULL, PROV_DSS, CRYPT_VERIFYCONTEXT ); - - // Defaults to the Decaf version. - if( result == 0 ) { - this->config->random.reset( new Random() ); - } else { - CryptReleaseContext( provider, 0 ); - } - } - DECAF_CATCH_RETHROW( Exception ) - DECAF_CATCHALL_THROW( Exception ) } //////////////////////////////////////////////////////////////////////////////// SecureRandomImpl::~SecureRandomImpl() { - try{ - delete this->config; - } - DECAF_CATCH_NOTHROW( Exception ) - DECAF_CATCHALL_NOTHROW() } //////////////////////////////////////////////////////////////////////////////// void SecureRandomImpl::providerSetSeed( const unsigned char* seed, int size ) { - - // Only seed the default random, the other sources don't need a seed. - if( this->config->random.get() != NULL ) { - - for( int i = 0; i < size; i++ ) { - this->config->random->setSeed( (long long)seed[i] ); - } - } + // BCryptGenRandom uses the OS CSPRNG and does not require external seeding. + (void)seed; + (void)size; } //////////////////////////////////////////////////////////////////////////////// @@ -114,30 +60,15 @@ void SecureRandomImpl::providerNextBytes( unsigned char* bytes, int numBytes ) { __FILE__, __LINE__, "Number of bytes to read was negative: %d", numBytes ); } - if( this->config->random.get() == NULL ) { - - HCRYPTPROV provider; - - int result; - - result = CryptAcquireContext( &provider, NULL, NULL, PROV_DSS, CRYPT_VERIFYCONTEXT ); - - if ( result == 0 ) { - throw RuntimeException( - __FILE__, __LINE__, "Failed to acquire the system cryptographic provider." ); - } - - result = CryptGenRandom( provider, numBytes, bytes ); - - if( result == 0 ) { - throw RuntimeException( - __FILE__, __LINE__, "Failed to get random bytes from the cryptographic provider." ); - } + if( numBytes == 0 ) { + return; + } - CryptReleaseContext( provider, 0 ); + NTSTATUS status = BCryptGenRandom( NULL, bytes, (ULONG)numBytes, BCRYPT_USE_SYSTEM_PREFERRED_RNG ); - } else { - this->config->random->nextBytes( bytes, numBytes ); + if( !BCRYPT_SUCCESS( status ) ) { + throw RuntimeException( + __FILE__, __LINE__, "BCryptGenRandom failed with NTSTATUS: 0x%08X", (unsigned int)status ); } } diff --git a/activemq-cpp/src/main/decaf/internal/security/windows/SecureRandomImpl.h b/activemq-cpp/src/main/decaf/internal/security/windows/SecureRandomImpl.h index a1f562c91..6d3545914 100644 --- a/activemq-cpp/src/main/decaf/internal/security/windows/SecureRandomImpl.h +++ b/activemq-cpp/src/main/decaf/internal/security/windows/SecureRandomImpl.h @@ -26,13 +26,10 @@ namespace decaf { namespace internal { namespace security { - class SRNGData; - /** - * Secure Random Number Generator for Windows based platforms that attempts to obtain - * secure bytes with high entropy from known sources. If the platform does not have - * a source of secure bytes then the platform random number generator is used if one - * exists otherwise the Decaf RNG is used as a last resort. + * Secure Random Number Generator for Windows based platforms that uses + * BCryptGenRandom to obtain cryptographically secure random bytes from the + * OS-preferred algorithm provider. * * @since 1.0 */ @@ -42,10 +39,6 @@ namespace security { SecureRandomImpl( const SecureRandomImpl& ); SecureRandomImpl& operator= ( const SecureRandomImpl& ); - private: - - SRNGData* config; - public: SecureRandomImpl(); From 727c117b36e3e10bf0aacfcfd5dda0d2bb8da375 Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Fri, 20 Feb 2026 22:37:07 +0700 Subject: [PATCH 18/25] Increase sleep duration in TimerTest for improved reliability in macOS CI scheduling Signed-off-by: blackb1rd --- activemq-cpp/src/test/decaf/util/TimerTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activemq-cpp/src/test/decaf/util/TimerTest.cpp b/activemq-cpp/src/test/decaf/util/TimerTest.cpp index 9afa100ed..48492f64a 100644 --- a/activemq-cpp/src/test/decaf/util/TimerTest.cpp +++ b/activemq-cpp/src/test/decaf/util/TimerTest.cpp @@ -923,7 +923,7 @@ TEST_F(TimerTest, testSchedule_TimerTask_Long_Long) { testTask->setIncrementCount( true ); t->schedule( testTask, 100, 200 ); // at least 4 times try { - Thread::sleep( 1200 ); // Allowed more room for error + Thread::sleep( 2000 ); // Allowed more room for error (increased for macOS CI scheduling latency) } catch( InterruptedException& e ) { } ASSERT_TRUE(timerCounter.get() >= 24) << (std::string( "Multiple tasks should have incremented counter 24 times not " ) + @@ -1049,7 +1049,7 @@ TEST_F(TimerTest, testSchedule_TimerTask_Long_Long2) { testTask->setIncrementCount( true ); t->schedule( testTask, 100, 200 ); // at least 4 times try { - Thread::sleep( 1200 ); // Allowed more room for error + Thread::sleep( 2000 ); // Allowed more room for error (increased for macOS CI scheduling latency) } catch( InterruptedException& e ) { } ASSERT_TRUE(timerCounter.get() >= 24) << (std::string( "Multiple tasks should have incremented counter 24 times not " ) + From 634567c7a0b131434f077fe0547e0721f66c50d9 Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Sat, 21 Feb 2026 00:27:13 +0700 Subject: [PATCH 19/25] Update ReentrantReadWriteLockTest to use LONG_DELAY_MS for improved test reliability Signed-off-by: blackb1rd --- .../decaf/util/concurrent/locks/ReentrantReadWriteLockTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activemq-cpp/src/test/decaf/util/concurrent/locks/ReentrantReadWriteLockTest.cpp b/activemq-cpp/src/test/decaf/util/concurrent/locks/ReentrantReadWriteLockTest.cpp index 89028e0f2..13794a689 100644 --- a/activemq-cpp/src/test/decaf/util/concurrent/locks/ReentrantReadWriteLockTest.cpp +++ b/activemq-cpp/src/test/decaf/util/concurrent/locks/ReentrantReadWriteLockTest.cpp @@ -1635,7 +1635,7 @@ namespace { virtual void run() { try { lock->writeLock().lock(); - cond->awaitNanos(ReentrantReadWriteLockTest::SHORT_DELAY_MS * 2 * 1000000); + cond->awaitNanos((long long)ReentrantReadWriteLockTest::LONG_DELAY_MS * 1000000LL); lock->writeLock().unlock(); test->threadShouldThrow(); } catch(InterruptedException& success) { From a617f5cbd2e9ca0f270f1851d320fd608418e6da Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Sat, 21 Feb 2026 22:46:05 +0700 Subject: [PATCH 20/25] Increase sleep duration in TimerTest for improved reliability in macOS CI scheduling Signed-off-by: blackb1rd --- activemq-cpp/src/test/decaf/util/TimerTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activemq-cpp/src/test/decaf/util/TimerTest.cpp b/activemq-cpp/src/test/decaf/util/TimerTest.cpp index 48492f64a..4859ff8d6 100644 --- a/activemq-cpp/src/test/decaf/util/TimerTest.cpp +++ b/activemq-cpp/src/test/decaf/util/TimerTest.cpp @@ -1027,7 +1027,7 @@ TEST_F(TimerTest, testSchedule_TimerTask_Long_Long2) { testTask.reset( new TimerTestTask( &report, &this->timerCounter, &this->gsync ) ); t->schedule( testTask, 100, 100 ); try { - Thread::sleep( 400 ); + Thread::sleep( 1000 ); // Increased for macOS CI scheduling latency } catch( InterruptedException& e ) { } ASSERT_TRUE(report.wasRun.get() >= 2) << ("TimerTask.run() method should have been called at least twice (" + From 534c850837cd0af469d0801e70877983e0608239 Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Sun, 22 Feb 2026 00:19:01 +0700 Subject: [PATCH 21/25] Refactor Gate class to use shared_ptr for CountDownLatch, improving memory management and preventing use-after-free issues Signed-off-by: blackb1rd --- .../src/test/decaf/lang/ArrayPointerTest.cpp | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/activemq-cpp/src/test/decaf/lang/ArrayPointerTest.cpp b/activemq-cpp/src/test/decaf/lang/ArrayPointerTest.cpp index 6a454af5d..c12833a50 100755 --- a/activemq-cpp/src/test/decaf/lang/ArrayPointerTest.cpp +++ b/activemq-cpp/src/test/decaf/lang/ArrayPointerTest.cpp @@ -24,6 +24,7 @@ #include #include +#include #include using namespace std; @@ -454,8 +455,8 @@ namespace { class Gate { private: - CountDownLatch* enterLatch; - CountDownLatch* leaveLatch; + std::shared_ptr enterLatch; + std::shared_ptr leaveLatch; Mutex mutex; bool closed; @@ -466,12 +467,12 @@ namespace { public: - Gate() : enterLatch(NULL), leaveLatch(NULL), mutex(), closed(true) {} + Gate() : enterLatch(), leaveLatch(), mutex(), closed(true) {} virtual ~Gate() {} void open(int count) { - leaveLatch = new CountDownLatch(count); - enterLatch = new CountDownLatch(count); + leaveLatch = std::make_shared(count); + enterLatch = std::make_shared(count); mutex.lock(); closed = false; mutex.notifyAll(); @@ -491,13 +492,19 @@ namespace { } void leave() { - leaveLatch->countDown(); + // Capture a local shared_ptr before calling countDown(). This prevents a + // use-after-free: countDown() unparks the awaiting thread, which may call + // close() and reset leaveLatch before doReleaseShared() finishes. The local + // copy keeps the CountDownLatch (and its SynchronizerState) alive until + // countDown() returns. + std::shared_ptr l = leaveLatch; + l->countDown(); } void close() { leaveLatch->await(); - delete leaveLatch; - delete enterLatch; + leaveLatch.reset(); + enterLatch.reset(); } }; From 542096d5e79ba7d6adb1ff55d32951d18b8445ec Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Sun, 22 Feb 2026 00:23:36 +0700 Subject: [PATCH 22/25] Increase sleep duration in TimerTest for improved reliability in macOS CI scheduling Signed-off-by: blackb1rd --- activemq-cpp/src/test/decaf/util/TimerTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/activemq-cpp/src/test/decaf/util/TimerTest.cpp b/activemq-cpp/src/test/decaf/util/TimerTest.cpp index 4859ff8d6..840318e35 100644 --- a/activemq-cpp/src/test/decaf/util/TimerTest.cpp +++ b/activemq-cpp/src/test/decaf/util/TimerTest.cpp @@ -901,7 +901,7 @@ TEST_F(TimerTest, testSchedule_TimerTask_Long_Long) { testTask = new TimerTestTask( &report, &this->timerCounter, &this->gsync ); t->schedule( testTask, 100, 100 ); try { - Thread::sleep( 400 ); + Thread::sleep( 1000 ); // Increased for macOS CI scheduling latency } catch( InterruptedException& e ) { } ASSERT_TRUE(report.wasRun.get() >= 2) << ("TimerTask.run() method should have been called at least twice (" + From 8e9ed26abb87411a03d90895e9d960d68431b218 Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Sun, 22 Feb 2026 17:03:43 +0700 Subject: [PATCH 23/25] Increase sleep duration in SchedulerTest for improved test reliability Signed-off-by: blackb1rd --- activemq-cpp/src/test/activemq/threads/SchedulerTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/activemq-cpp/src/test/activemq/threads/SchedulerTest.cpp b/activemq-cpp/src/test/activemq/threads/SchedulerTest.cpp index 90be71b9f..63f8b3c0d 100644 --- a/activemq-cpp/src/test/activemq/threads/SchedulerTest.cpp +++ b/activemq-cpp/src/test/activemq/threads/SchedulerTest.cpp @@ -171,9 +171,9 @@ TEST_F(SchedulerTest, testExecuteAfterDelay) { CounterTask task; scheduler.executeAfterDelay(&task, 500, false); ASSERT_TRUE(task.getCount() == 0); - Thread::sleep(600); + Thread::sleep(2000); ASSERT_EQ(1, task.getCount()); - Thread::sleep(600); + Thread::sleep(2000); ASSERT_EQ(1, task.getCount()); } From df417030814029664ffe9424252c1da2787c43ae Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Sun, 22 Feb 2026 21:39:27 +0700 Subject: [PATCH 24/25] Increase sleep duration in SchedulerTest for improved test reliability Signed-off-by: blackb1rd --- .../src/test/activemq/threads/SchedulerTest.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/activemq-cpp/src/test/activemq/threads/SchedulerTest.cpp b/activemq-cpp/src/test/activemq/threads/SchedulerTest.cpp index 63f8b3c0d..3f8b78712 100644 --- a/activemq-cpp/src/test/activemq/threads/SchedulerTest.cpp +++ b/activemq-cpp/src/test/activemq/threads/SchedulerTest.cpp @@ -103,11 +103,11 @@ TEST_F(SchedulerTest, testExecutePeriodically) { CounterTask* task = new CounterTask(); scheduler.executePeriodically(task, 500); ASSERT_TRUE(task->getCount() == 0); - Thread::sleep(600); + Thread::sleep(2000); ASSERT_TRUE(task->getCount() >= 1); - Thread::sleep(600); + Thread::sleep(2000); ASSERT_TRUE(task->getCount() >= 2); - ASSERT_TRUE(task->getCount() < 5); + ASSERT_TRUE(task->getCount() < 15); } { @@ -137,11 +137,11 @@ TEST_F(SchedulerTest, testSchedualPeriodically) { CounterTask* task = new CounterTask(); scheduler.schedualPeriodically(task, 400); ASSERT_TRUE(task->getCount() == 0); - Thread::sleep(600); + Thread::sleep(2000); ASSERT_TRUE(task->getCount() >= 1); - Thread::sleep(600); + Thread::sleep(2000); ASSERT_TRUE(task->getCount() >= 2); - ASSERT_TRUE(task->getCount() < 5); + ASSERT_TRUE(task->getCount() < 15); } { From a3fa4ce7ac63a2ee733a54524683bc30e8f9b875 Mon Sep 17 00:00:00 2001 From: blackb1rd Date: Mon, 23 Feb 2026 00:11:10 +0700 Subject: [PATCH 25/25] Increase wait duration in TimerTest for improved test reliability Signed-off-by: blackb1rd --- activemq-cpp/src/test/decaf/util/TimerTest.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/activemq-cpp/src/test/decaf/util/TimerTest.cpp b/activemq-cpp/src/test/decaf/util/TimerTest.cpp index 840318e35..dc23d0039 100644 --- a/activemq-cpp/src/test/decaf/util/TimerTest.cpp +++ b/activemq-cpp/src/test/decaf/util/TimerTest.cpp @@ -307,12 +307,12 @@ TEST_F(TimerTest, testCancel) { t->schedule( testTask, 100, 100 ); synchronized( &this->gsync ) { try { - this->gsync.wait( 200 ); - this->gsync.wait( 200 ); - this->gsync.wait( 200 ); - this->gsync.wait( 200 ); - this->gsync.wait( 200 ); - this->gsync.wait( 200 ); + this->gsync.wait( 500 ); + this->gsync.wait( 500 ); + this->gsync.wait( 500 ); + this->gsync.wait( 500 ); + this->gsync.wait( 500 ); + this->gsync.wait( 500 ); } catch( InterruptedException& e ) {} }