# Reusable: unit + integration tests on all platforms name: Test on: workflow_call: inputs: skip_perf: description: 'Skip incremental perf tests (phases 2-7)' type: boolean default: true broad_platforms: description: 'Test the broad platform matrix (older glibc + extra OS versions) instead of the core set' type: boolean default: false permissions: contents: read jobs: # Emit the platform matrices as JSON. The CORE set is the default (fast, # unchanged); the BROAD set adds extra free runners (older glibc / # additional OS versions) for a wider "does it build everywhere" picture. setup-matrix: runs-on: ubuntu-latest timeout-minutes: 5 outputs: unix: ${{ steps.set.outputs.unix }} windows: ${{ steps.set.outputs.windows }} steps: - name: Compute matrices id: set env: BROAD: ${{ inputs.broad_platforms }} run: | CORE_UNIX='[ {"os":"ubuntu-latest","cc":"gcc","cxx":"g++"}, {"os":"ubuntu-24.04-arm","cc":"gcc","cxx":"g++"}, {"os":"macos-14","cc":"cc","cxx":"c++"}, {"os":"macos-15-intel","cc":"cc","cxx":"c++"} ]' # Broad matrix legs are REQUIRED gates (no optional/continue-on-error # escape hatches): the release dry run must be all-green, every platform. BROAD_UNIX='[ {"os":"ubuntu-22.04","cc":"gcc","cxx":"g++"}, {"os":"ubuntu-22.04-arm","cc":"gcc","cxx":"g++"}, {"os":"macos-15","cc":"cc","cxx":"c++"} ]' # Each Windows leg pins the msys2 environment + package arch to the # RUNNER architecture so the build is native, never emulated: # x86-64 runners -> CLANG64 (mingw-w64-clang-x86_64-*) # ARM64 runner -> CLANGARM64 (mingw-w64-clang-aarch64-*) # windows-11-arm previously used the x86-64 CLANG64 toolchain, so its # binary ran under Windows-on-ARM x86-64 emulation and ASan's function # interception crashed (interception_win: unhandled instruction). With # the native ARM64 toolchain ASan instruments native ARM64 code, so it # is a real (non-optional) gate, not a tolerated emulated-flake. CORE_WIN='[{"os":"windows-latest","msystem":"CLANG64","pkg":"x86_64"}]' BROAD_WIN='[{"os":"windows-2025","msystem":"CLANG64","pkg":"x86_64"},{"os":"windows-11-arm","msystem":"CLANGARM64","pkg":"aarch64"}]' if [ "$BROAD" = "true" ]; then UNIX=$(jq -cn --argjson a "$CORE_UNIX" --argjson b "$BROAD_UNIX" '$a + $b') WIN=$(jq -cn --argjson a "$CORE_WIN" --argjson b "$BROAD_WIN" '$a + $b') else UNIX=$(jq -cn --argjson a "$CORE_UNIX" '$a') WIN=$(jq -cn --argjson a "$CORE_WIN" '$a') fi echo "unix={\"include\":$UNIX}" >> "$GITHUB_OUTPUT" echo "windows={\"include\":$WIN}" >> "$GITHUB_OUTPUT" test-unix: needs: setup-matrix strategy: fail-fast: false matrix: ${{ fromJSON(needs.setup-matrix.outputs.unix) }} runs-on: ${{ matrix.os }} # Broad-only legs (extra OS versions) are informational: visible but # non-blocking, so a flaky/less-common runner can't block a release. continue-on-error: ${{ matrix.optional == true }} timeout-minutes: 240 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Install deps (Ubuntu) if: startsWith(matrix.os, 'ubuntu') run: sudo apt-get update && sudo apt-get install -y zlib1g-dev - name: Test run: scripts/test.sh CC=${{ matrix.cc }} CXX=${{ matrix.cxx }} env: CBM_SKIP_PERF: ${{ inputs.skip_perf && '1' || '' }} test-tsan: runs-on: ubuntu-latest timeout-minutes: 120 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - name: Install deps (Ubuntu) run: sudo apt-get update && sudo apt-get install -y clang zlib1g-dev - name: ThreadSanitizer tests run: make -f Makefile.cbm test-tsan CC=clang CXX=clang++ test-windows: needs: setup-matrix strategy: fail-fast: false matrix: ${{ fromJSON(needs.setup-matrix.outputs.windows) }} runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.optional == true }} timeout-minutes: 240 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2 with: msystem: ${{ matrix.msystem }} path-type: inherit install: >- mingw-w64-clang-${{ matrix.pkg }}-clang mingw-w64-clang-${{ matrix.pkg }}-compiler-rt mingw-w64-clang-${{ matrix.pkg }}-zlib make git - name: Test shell: msys2 {0} # AddressSanitizer is unavailable on native ARM64 Windows (LLVM ships no # libclang_rt.asan for aarch64-w64-windows-gnu) and cannot intercept the # system DLLs under x86-64 emulation either, so windows-11-arm runs the # native ARM64 build with SANITIZE= (no sanitizer) — still a real # functional gate. ASan/UBSan coverage comes from the other 9 legs, # including native-ARM Linux/macOS. x86-64 Windows keeps full sanitizers. run: scripts/test.sh CC=clang CXX=clang++ ${{ matrix.os == 'windows-11-arm' && 'SANITIZE=' || '' }} env: CBM_SKIP_PERF: ${{ inputs.skip_perf && '1' || '' }} # Windows product-surface regression guards. Distinct from test-windows above # (the sanitizer C suite): these drive a real product binary + embedded HTTP UI # over stdio / CLI / HTTP and fail if a Windows bug already fixed on main comes # back -- non-ASCII repo paths dropping definitions (#636/#357, fixed by #700), # the PreToolUse hook augmenter no-op on drive-letter cwd (#618, fixed by #619), # the UI directory picker not enumerating drives (#548, roots field), and non-ASCII # CLI arguments being mangled by the narrow-argv main() (#423/#20, fixed by the # wide-argv entrypoint that reads GetCommandLineW). test-windows-guards: runs-on: windows-latest timeout-minutes: 60 steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: msys2/setup-msys2@66cd2cce69caa17b53920067426061ca1de3a884 # v2 with: msystem: CLANG64 path-type: inherit install: >- mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-zlib make git - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "22" - name: Build product binary with embedded UI shell: msys2 {0} # --with-ui builds the frontend (npm) and embeds it, so the drive-picker # guard's HTTP UI is available. Functional gate only (no sanitizers). run: scripts/build.sh --with-ui CC=clang CXX=clang++ - name: Windows regression guards (#636/#357, #618, #548, #423/#20) shell: pwsh # -GuardsOnly runs the four green guards and gates on them. The runner sets # CBM_INDEX_SUPERVISOR=0 for determinism, but the non-ASCII CLI guard drops that # override so it exercises the real supervisor->worker spawn (where #423/#20's # second half lives); the other guards test path/hook/drive fixes in-process. run: ./scripts/test-windows.ps1 -GuardsOnly -Binary build/c/codebase-memory-mcp.exe