name: Daily
on:
  pull_request:
    types: [opened, synchronize, reopened, labeled]
    branches:
      # any PR to a release branch.
      - "[0-9].[0-9]"
      - "unstable"
    paths-ignore:
      - '**/*.md'
      - '**/00-RELEASENOTES'
      - '**/COPYING'
  schedule:
    - cron: "0 0 * * *"
  workflow_dispatch:
    inputs:
      skipjobs:
        description: "jobs to skip (delete the ones you wanna keep, do not leave empty)"
        default: "valgrind,sanitizer,tls,freebsd,macos,alpine,32bit,iothreads,ubuntu,rpm-distros,malloc,specific,fortify,reply-schema,arm,s390x,lttng"
      skiptests:
        description: "tests to skip (delete the ones you wanna keep, do not leave empty)"
        default: "valkey,modules,sentinel,cluster,unittest,large-memory"
      test_args:
        description: "extra test arguments; use valgrind_test instead of --single for targeted valgrind runs"
        default: ""
      valgrind_test:
        description: "single test file or directory to run in valgrind jobs instead of the full shards"
        default: ""
      cluster_test_args:
        description: "extra cluster / sentinel test arguments"
        default: ""
      use_repo:
        description: "repo owner and name"
        default: "valkey-io/valkey"
      use_git_ref:
        description: "git branch or sha to use"
        default: "unstable"
  workflow_call:
    inputs:
      skipjobs:
        description: "jobs to skip (delete the ones you wanna keep, do not leave empty)"
        required: false
        type: string
        default: ""
      skiptests:
        description: "tests to skip (delete the ones you wanna keep, do not leave empty)"
        required: false
        type: string
        default: ""
      test_args:
        description: "extra test arguments; use valgrind_test instead of --single for targeted valgrind runs"
        required: false
        type: string
        default: ""
      valgrind_test:
        description: "single test file or directory to run in valgrind jobs instead of the full shards"
        required: false
        type: string
        default: ""
      cluster_test_args:
        description: "extra cluster / sentinel test arguments"
        required: false
        type: string
        default: ""
      use_repo:
        description: "repo owner and name"
        required: false
        type: string
        default: "valkey-io/valkey"
      use_git_ref:
        description: "git branch or sha to use"
        required: false
        type: string
        default: "unstable"
concurrency:
  group: daily-${{ github.head_ref || inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
  cancel-in-progress: ${{ github.event_name != 'pull_request' || github.event.action != 'labeled' }}
permissions:
  contents: read
  pull-requests: read
jobs:
  test-ubuntu-jemalloc:
    runs-on: ubuntu-latest
    # pull_request gate breakdown:
    # 1) (base != unstable) OR PR currently has run-extra-tests.
    # 2) Exclude all labeled events, except unstable + newly added run-extra-tests.
    # 3) release branches run on opened/reopened/synchronize, never label-only events.
    # 4) unstable runs when run-extra-tests is added, and on later code updates while it remains.
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'ubuntu')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: Install gtest
        run: sudo apt-get install pkg-config libgtest-dev libgmock-dev
      - name: make
        run: make all-with-unit-tests SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: sudo apt-get install tcl8.6 tclx
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: unittest
        if: true && !contains(github.event.inputs.skiptests, 'unittest')
        run: |
          if [ -f ./src/unit/valkey-unit-gtests ]; then
            make test-unit accurate=1
          elif [ -f ./src/valkey-unit-tests ]; then
            ./src/valkey-unit-tests --accurate
          fi
      - name: install Redis OSS 6.2 server for compatibility testing
        run: |
          cd tests/tmp
          wget https://download.redis.io/releases/redis-6.2.14.tar.gz
          tar -xvf redis-6.2.14.tar.gz
      - name: make Redis OSS 6.2 server
        run: |
          cd tests/tmp/redis-6.2.14
          make
      - name: backward compatibility tests with OSS Redis 6.2
        run: |
          sudo apt-get install tcl8.6 tclx
          ./runtest --verbose --tags compatible-redis --dump-logs --other-server-path tests/tmp/redis-6.2.14/src/redis-server
      - name: install Redis OSS 7.0 server for compatibility testing
        run: |
          cd tests/tmp
          wget https://download.redis.io/releases/redis-7.0.15.tar.gz
          tar -xvf redis-7.0.15.tar.gz
      - name: make Redis OSS 7.0 server
        run: |
          cd tests/tmp/redis-7.0.15
          make
      - name: backward compatibility tests with OSS Redis 7.0
        run: |
          sudo apt-get install tcl8.6 tclx
          ./runtest --verbose --tags compatible-redis --dump-logs --other-server-path tests/tmp/redis-7.0.15/src/redis-server
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-ubuntu-arm:
    runs-on: ubuntu-24.04-arm
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      (!contains(github.event.inputs.skipjobs, 'ubuntu') || !contains(github.event.inputs.skipjobs, 'arm'))
    timeout-minutes: 14400
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: Install gtest
        run: sudo apt-get install pkg-config libgtest-dev libgmock-dev
      - name: make
        run: make all-with-unit-tests SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: sudo apt-get install tcl8.6 tclx
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: unittest
        if: true && !contains(github.event.inputs.skiptests, 'unittest')
        run: |
          if [ -f ./src/unit/valkey-unit-gtests ]; then
            make test-unit accurate=1
          elif [ -f ./src/valkey-unit-tests ]; then
            ./src/valkey-unit-tests --accurate
          fi
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-s390x:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'unstable') ||
        (github.event_name == 'pull_request_target' && github.event.label.name == 'run-extra-tests')) &&
      !contains(github.event.inputs.skipjobs, 's390x')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ ((github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && (inputs.use_repo || github.event.inputs.use_repo)) || github.repository }}
          ref: ${{ ((github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call') && (inputs.use_git_ref || github.event.inputs.use_git_ref)) || github.ref }}
      - name: Build and test on s390x (big endian)
        uses: uraimo/run-on-arch-action@d94c13912ea685de38fccc1109385b83fd79427d # v3.0.1
        with:
          arch: s390x
          distro: ubuntu_latest
          githubToken: ${{ github.token }}
          run: |
            apt-get update
            apt-get install -y build-essential pkg-config libgtest-dev libgmock-dev python3
            make all-with-unit-tests SERVER_CFLAGS='-Werror'
            if [ -f ./src/unit/valkey-unit-gtests ]; then
              make test-unit
            elif [ -f ./src/valkey-unit-tests ]; then
              ./src/valkey-unit-tests
            else
              echo "No unit-test binary was produced"
              exit 1
            fi
  test-ubuntu-jemalloc-fortify:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'fortify')
    container: ubuntu:plucky
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - name: Build libbacktrace
        run: |
          apt-get update && apt-get install -y make gcc-13 git cmake g++ python3
          update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-13 100
          cd libbacktrace && ./configure && make && make install
      - name: Install build dependencies
        run: apt-get install -y pkg-config libgtest-dev libgmock-dev libzstd-dev
      - name: make
        run: make all-with-unit-tests CC=gcc OPT=-O3 SERVER_CFLAGS='-Werror -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3' BUILD_ZSTD=yes USE_LIBBACKTRACE=yes
      - name: testprep
        run: apt-get install -y tcl8.6 tclx procps
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: unittest
        if: true && !contains(github.event.inputs.skiptests, 'unittest')
        run: |
          if [ -f ./src/unit/valkey-unit-gtests ]; then
            make test-unit accurate=1
          elif [ -f ./src/valkey-unit-tests ]; then
            ./src/valkey-unit-tests --accurate
          fi
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-ubuntu-libc-malloc:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'malloc')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: make
        run: make MALLOC=libc SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: sudo apt-get install tcl8.6 tclx
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-ubuntu-no-malloc-usable-size:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'malloc')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: make
        run: make MALLOC=libc CFLAGS=-DNO_MALLOC_USABLE_SIZE SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: sudo apt-get install tcl8.6 tclx
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-ubuntu-32bit:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, '32bit')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - name: Build libbacktrace
        run: |
          sudo apt-get update && sudo apt-get install libc6-dev-i386 g++-multilib
          cd libbacktrace && ./configure && make && sudo make install
      - name: Install gtest
        run: |
          sudo apt-get update
          sudo apt-get install libgtest-dev
          mkdir -p /tmp/gtest32
          cd /tmp/gtest32
          cmake -B build32 \
              -DCMAKE_BUILD_TYPE=Release \
              -DCMAKE_C_FLAGS="-m32" \
              -DCMAKE_CXX_FLAGS="-m32" \
              -DCMAKE_EXE_LINKER_FLAGS="-m32" \
              /usr/src/googletest
          cmake --build build32 --parallel
          sudo cp build32/lib/*.a /usr/lib32/
          cd $GITHUB_WORKSPACE
      - name: make
        run: |
          make 32bit SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes \
            GTEST_CFLAGS="-I/usr/src/googletest/googletest/include -I/usr/src/googletest/googlemock/include" \
            GTEST_LIBS="/usr/lib32/libgtest.a /usr/lib32/libgmock.a"
      - name: testprep
        run: sudo apt-get install tcl8.6 tclx
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: |
          make -C tests/modules 32bit # the script below doesn't have an argument, we must build manually ahead of time
          CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: unittest
        if: true && !contains(github.event.inputs.skiptests, 'unittest')
        run: |
          if [ -f ./src/unit/valkey-unit-gtests ]; then
            make test-unit accurate=1 \
              GTEST_CFLAGS="-I/usr/src/googletest/googletest/include -I/usr/src/googletest/googlemock/include" \
              GTEST_LIBS="/usr/lib32/libgtest.a /usr/lib32/libgmock.a"
          elif [ -f ./src/valkey-unit-tests ]; then
            ./src/valkey-unit-tests --accurate
          fi
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-ubuntu-tls:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'tls')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: Install Zstandard
        run: sudo apt-get update && sudo apt-get install -y libzstd-dev
      - name: make
        run: make BUILD_TLS=yes BUILD_ZSTD=yes SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: |
          sudo apt-get install tcl8.6 tclx tcl-tls
          ./utils/gen-test-certs.sh
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: |
          ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --dump-logs --tls ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: |
          CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs --tls ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: |
          ./runtest-sentinel --failures-output test-failures/sentinel.json --tls ${{github.event.inputs.cluster_test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-ubuntu-tls-no-tls:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'tls')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: make
        run: make BUILD_TLS=yes SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: |
          sudo apt-get install tcl8.6 tclx tcl-tls
          ./utils/gen-test-certs.sh
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: |
          ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: |
          CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: |
          ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-ubuntu-io-threads:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'iothreads')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: make
        run: make SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: sudo apt-get install tcl8.6 tclx
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest --io-threads --accurate --failures-output test-failures/valkey.json --verbose --tags network --dump-logs ${{github.event.inputs.test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-ubuntu-tls-io-threads:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'tls') && !contains(github.event.inputs.skipjobs, 'iothreads')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: Install Zstandard
        run: sudo apt-get update && sudo apt-get install -y libzstd-dev
      - name: make
        run: make BUILD_TLS=yes BUILD_ZSTD=yes SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: |
          sudo apt-get install tcl8.6 tclx tcl-tls
          ./utils/gen-test-certs.sh
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: |
          ./runtest --io-threads --tls --accurate --failures-output test-failures/valkey.json --verbose --tags network --dump-logs ${{github.event.inputs.test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-ubuntu-reclaim-cache:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'specific')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: make
        run: make SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: "sudo apt-get install vmtouch\nmkdir /tmp/master \nmkdir /tmp/slave\n"
      - name: warm up
        run: |
          ./src/valkey-server --daemonize yes --logfile /dev/null
          ./src/valkey-benchmark -n 1 > /dev/null
          ./src/valkey-cli save | grep OK > /dev/null
          vmtouch -v ./dump.rdb > /dev/null
      - name: test
        run: |
          echo "test SAVE doesn't increase cache"
          CACHE0=$(grep -w file /sys/fs/cgroup/memory.stat | awk '{print $2}')
          echo "$CACHE0"
          ./src/valkey-server --daemonize yes --logfile /dev/null --dir /tmp/master --port 8080 --repl-diskless-sync no --pidfile /tmp/master/valkey.pid --rdbcompression no --enable-debug-command yes
          sleep 1 # wait for server startup
          ./src/valkey-cli -p 8080 debug populate 10000 k 102400
          ./src/valkey-server --daemonize yes --logfile /dev/null --dir /tmp/slave --port 8081 --repl-diskless-load disabled --rdbcompression no
          sleep 1 # wait for server startup
          ./src/valkey-cli -p 8080 save > /dev/null
          VMOUT=$(vmtouch -v /tmp/master/dump.rdb)
          echo $VMOUT
          grep -q " 0%" <<< $VMOUT
          CACHE=$(grep -w file /sys/fs/cgroup/memory.stat | awk '{print $2}')
          echo "$CACHE"
          if [ "$(( $CACHE-$CACHE0 ))" -gt "8000000" ]; then exit 1; fi
          echo "test replication doesn't increase cache"
          ./src/valkey-cli -p 8081 REPLICAOF 127.0.0.1 8080 > /dev/null
          while [ $(./src/valkey-cli -p 8081 info replication | grep "master_link_status:down") ]; do sleep 1; done;
          sleep 1 # wait for the completion of cache reclaim bio
          VMOUT=$(vmtouch -v /tmp/master/dump.rdb)
          echo $VMOUT
          grep -q " 0%" <<< $VMOUT
          VMOUT=$(vmtouch -v /tmp/slave/dump.rdb)
          echo $VMOUT
          grep -q " 0%" <<< $VMOUT
          CACHE=$(grep -w file /sys/fs/cgroup/memory.stat | awk '{print $2}')
          echo "$CACHE"
          if [ "$(( $CACHE-$CACHE0 ))" -gt "8000000" ]; then exit 1; fi

          echo "test reboot doesn't increase cache"
          PID=$(cat /tmp/master/valkey.pid)
          kill -15 $PID
          while [ -x /proc/${PID} ]; do sleep 1; done
          ./src/valkey-server --daemonize yes --logfile /dev/null --dir /tmp/master --port 8080
          sleep 1 # wait for server startup
          while [ $(./src/valkey-cli -p 8080 info persistence | grep "loading:1") ]; do sleep 1; done;
          sleep 1 # wait for the completion of cache reclaim bio
          VMOUT=$(vmtouch -v /tmp/master/dump.rdb)
          echo $VMOUT
          grep -q " 0%" <<< $VMOUT
          CACHE=$(grep -w file /sys/fs/cgroup/memory.stat | awk '{print $2}')
          echo "$CACHE"
          if [ "$(( $CACHE-$CACHE0 ))" -gt "8000000" ]; then exit 1; fi
  test-valgrind-test:
    name: test-valgrind-test (${{ matrix.shard }})
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'unstable' && github.event.action != 'labeled')) &&
      !contains(github.event.inputs.skipjobs, 'valgrind') && !contains(github.event.inputs.skiptests, 'valkey')
    timeout-minutes: 1440
    strategy:
      fail-fast: false
      matrix:
        shard: ${{ fromJSON(inputs.valgrind_test && '["targeted"]' || '["unit", "cluster", "integration-type"]') }}
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: Install Zstandard
        run: sudo apt-get update && sudo apt-get install -y libzstd-dev
      - name: make
        run: make valgrind SERVER_CFLAGS='-Werror' BUILD_ZSTD=yes USE_LIBBACKTRACE=yes
      - name: testprep
        run: |
          sudo apt-get update
          sudo apt-get install tcl8.6 tclx valgrind -y
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        env:
          VALGRIND_TEST: ${{ inputs.valgrind_test }}
        run: |
          shard_args=()
          case "${{ matrix.shard }}" in
            unit) shard_args=(--single tests/unit) ;;
            cluster) shard_args=(--single tests/unit/cluster) ;;
            integration-type) shard_args=(--single tests/integration --single tests/unit/type) ;;
            targeted) shard_args=(--single "$VALGRIND_TEST") ;;
          esac
          ./runtest --valgrind --no-latency --failures-output test-failures/valkey.json --verbose --clients 1 --timeout 2400 --dump-logs "${shard_args[@]}" ${{github.event.inputs.test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}-${{ matrix.shard }}
  test-valgrind-misc:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'unstable' && github.event.action != 'labeled')) &&
      !contains(github.event.inputs.skipjobs, 'valgrind') && !(contains(github.event.inputs.skiptests, 'modules') && contains(github.event.inputs.skiptests, 'unittest'))
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: Install build dependencies
        run: sudo apt-get install pkg-config libgtest-dev libgmock-dev libzstd-dev
      - name: make
        run: make valgrind all-with-unit-tests SERVER_CFLAGS='-Werror' BUILD_ZSTD=yes USE_LIBBACKTRACE=yes
      - name: testprep
        run: |
          sudo apt-get update
          sudo apt-get install tcl8.6 tclx valgrind -y
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --valgrind --no-latency --failures-output test-failures/moduleapi.json --verbose --clients 1 --timeout 2400 --dump-logs ${{github.event.inputs.test_args}}
      - name: unittest
        if: true && !contains(github.event.inputs.skiptests, 'unittest')
        run: |
          if [ -f ./src/unit/valkey-unit-gtests ]; then
            ./deps/gtest-parallel/gtest-parallel valgrind -- --track-origins=yes --suppressions=./src/valgrind.sup --show-reachable=no --show-possibly-lost=no --leak-check=full --log-file=err.%p.txt ./src/unit/valkey-unit-gtests --valgrind
            if grep -qlE '0x[0-9A-Fa-f]+:' err.*.txt 2>/dev/null; then grep -lE '0x[0-9A-Fa-f]+:' err.*.txt | xargs cat; exit 1; fi
          elif [ -f ./src/valkey-unit-tests ]; then
            valgrind --track-origins=yes --suppressions=./src/valgrind.sup --show-reachable=no --show-possibly-lost=no --leak-check=full --log-file=err.txt ./src/valkey-unit-tests --valgrind
            if grep -q 0x err.txt; then cat err.txt; exit 1; fi
          fi
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-valgrind-no-malloc-usable-size-test:
    name: test-valgrind-no-malloc-usable-size-test (${{ matrix.shard }})
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'unstable' && github.event.action != 'labeled')) &&
      !contains(github.event.inputs.skipjobs, 'valgrind') && !contains(github.event.inputs.skiptests, 'valkey')
    timeout-minutes: 1440
    strategy:
      fail-fast: false
      matrix:
        shard: ${{ fromJSON(inputs.valgrind_test && '["targeted"]' || '["unit", "cluster", "integration-type"]') }}
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: make
        run: make valgrind CFLAGS="-DNO_MALLOC_USABLE_SIZE" SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: |
          sudo apt-get update
          sudo apt-get install tcl8.6 tclx valgrind -y
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        env:
          VALGRIND_TEST: ${{ inputs.valgrind_test }}
        run: |
          shard_args=()
          case "${{ matrix.shard }}" in
            unit) shard_args=(--single tests/unit) ;;
            cluster) shard_args=(--single tests/unit/cluster) ;;
            integration-type) shard_args=(--single tests/integration --single tests/unit/type) ;;
            targeted) shard_args=(--single "$VALGRIND_TEST") ;;
          esac
          ./runtest --valgrind --no-latency --failures-output test-failures/valkey.json --verbose --clients 1 --timeout 2400 --dump-logs "${shard_args[@]}" ${{github.event.inputs.test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}-${{ matrix.shard }}
  test-valgrind-no-malloc-usable-size-misc:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'unstable' && github.event.action != 'labeled')) &&
      !contains(github.event.inputs.skipjobs, 'valgrind') && !(contains(github.event.inputs.skiptests, 'modules') && contains(github.event.inputs.skiptests, 'unittest'))
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: Install gtest
        run: sudo apt-get install pkg-config libgtest-dev libgmock-dev
      - name: make
        run: make valgrind all-with-unit-tests CFLAGS="-DNO_MALLOC_USABLE_SIZE" SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: |
          sudo apt-get update
          sudo apt-get install tcl8.6 tclx valgrind -y
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --valgrind --no-latency --failures-output test-failures/moduleapi.json --verbose --clients 1 --timeout 2400 --dump-logs ${{github.event.inputs.test_args}}
      - name: unittest
        if: true && !contains(github.event.inputs.skiptests, 'unittest')
        run: |
          if [ -f ./src/unit/valkey-unit-gtests ]; then
            ./deps/gtest-parallel/gtest-parallel valgrind -- --track-origins=yes --suppressions=./src/valgrind.sup --show-reachable=no --show-possibly-lost=no --leak-check=full --log-file=err.%p.txt ./src/unit/valkey-unit-gtests --valgrind
            if grep -qlE '0x[0-9A-Fa-f]+:' err.*.txt 2>/dev/null; then grep -lE '0x[0-9A-Fa-f]+:' err.*.txt | xargs cat; exit 1; fi
          elif [ -f ./src/valkey-unit-tests ]; then
            valgrind --track-origins=yes --suppressions=./src/valgrind.sup --show-reachable=no --show-possibly-lost=no --leak-check=full --log-file=err.txt ./src/valkey-unit-tests --valgrind
            if grep -q 0x err.txt; then cat err.txt; exit 1; fi
          fi
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-sanitizer-address:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'sanitizer')
    timeout-minutes: 1440
    strategy:
      fail-fast: false
      matrix:
        compiler: [gcc, clang]
    env:
      CC: ${{ matrix.compiler }}
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: Install gtest
        run: sudo apt-get install pkg-config libgtest-dev libgmock-dev
      - name: make
        run: make all-with-unit-tests OPT=-O3 SANITIZER=address SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: |
          sudo apt-get update
          sudo apt-get install tcl8.6 tclx -y
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest --accurate --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: unittest
        if: true && !contains(github.event.inputs.skiptests, 'unittest')
        run: |
          if [ -f ./src/unit/valkey-unit-gtests ]; then
            make test-unit
          elif [ -f ./src/valkey-unit-tests ]; then
            ./src/valkey-unit-tests
          fi
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}-${{ matrix.compiler }}
  # Large-memory tests with sanitizers require 10-14GB RAM due to ASAN/UBSAN overhead.
  # GitHub-hosted runners for public repos provide 16GB (ubuntu-latest).
  # These tests are borderline - monitoring memory usage to determine if they can run reliably.
  test-sanitizer-address-large-memory:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'sanitizer') &&
      !contains(github.event.inputs.skiptests, 'large-memory')
    timeout-minutes: 1440
    strategy:
      fail-fast: false
      matrix:
        compiler: [gcc, clang]
    env:
      CC: ${{ matrix.compiler }}
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - name: Log runner memory
        run: free -h
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install gtest
        run: sudo apt-get install pkg-config libgtest-dev libgmock-dev
      - name: make
        run: make all-with-unit-tests OPT=-O3 SANITIZER=address SERVER_CFLAGS='-Werror'
      - name: testprep
        run: |
          sudo apt-get update
          sudo apt-get install tcl8.6 tclx -y
      - name: Start memory monitor
        run: |
          # Track minimum free memory to detect OOM risk
          (while true; do
            FREE=$(awk '/MemAvailable/ {print $2}' /proc/meminfo)
            echo "$FREE" >> /tmp/memfree.log
            sleep 5
          done) &
          echo $! > /tmp/memmon.pid
      - name: unittest
        if: true && !contains(github.event.inputs.skiptests, 'unittest')
        run: |
          if [ -f ./src/unit/valkey-unit-gtests ]; then
            make test-unit large_memory=1
          elif [ -f ./src/valkey-unit-tests ]; then
            ./src/valkey-unit-tests --large-memory
          fi
      - name: large memory tests
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest --accurate --failures-output test-failures/valkey.json --verbose --dump-logs --clients 1 --large-memory --tags large-memory ${{github.event.inputs.test_args}}
      - name: large memory module api tests
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs --clients 1 --large-memory --tags large-memory ${{github.event.inputs.test_args}}
      - name: Memory usage summary
        if: always()
        run: |
          kill $(cat /tmp/memmon.pid) 2>/dev/null || true
          echo "=== Memory Summary ==="
          printf "Total RAM: %.1fGB\n" $(awk '/MemTotal/ {print $2/1024/1024}' /proc/meminfo)
          if [ -f /tmp/memfree.log ]; then
            MIN_FREE=$(sort -n /tmp/memfree.log | head -1)
            printf "Minimum free memory: %.1fGB\n" $(echo "$MIN_FREE/1024/1024" | bc -l)
          fi
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}-${{ matrix.compiler }}
  test-sanitizer-undefined:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'sanitizer')
    timeout-minutes: 1440
    strategy:
      fail-fast: false
      matrix:
        compiler: [gcc, clang]
    env:
      CC: ${{ matrix.compiler }}
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: Install gtest
        run: sudo apt-get install pkg-config libgtest-dev libgmock-dev
      - name: make
        run: make all-with-unit-tests OPT=-O3 SANITIZER=undefined SERVER_CFLAGS='-Werror' LUA_DEBUG=yes USE_LIBBACKTRACE=yes # we (ab)use this flow to also check Lua C API violations
      - name: testprep
        run: |
          sudo apt-get update
          sudo apt-get install tcl8.6 tclx -y
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest --accurate --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: unittest
        if: true && !contains(github.event.inputs.skiptests, 'unittest')
        run: |
          if [ -f ./src/unit/valkey-unit-gtests ]; then
            make test-unit accurate=1
          elif [ -f ./src/valkey-unit-tests ]; then
            ./src/valkey-unit-tests --accurate
          fi
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}-${{ matrix.compiler }}
  # Large-memory tests with sanitizers require 10-14GB RAM due to ASAN/UBSAN overhead.
  # GitHub-hosted runners for public repos provide 16GB (ubuntu-latest).
  # These tests are borderline - monitoring memory usage to determine if they can run reliably.
  test-sanitizer-undefined-large-memory:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'sanitizer') &&
      !contains(github.event.inputs.skiptests, 'large-memory')
    timeout-minutes: 1440
    strategy:
      fail-fast: false
      matrix:
        compiler: [gcc, clang]
    env:
      CC: ${{ matrix.compiler }}
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - name: Log runner memory
        run: free -h
      - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install gtest
        run: sudo apt-get install pkg-config libgtest-dev libgmock-dev
      - name: make
        run: make all-with-unit-tests OPT=-O3 SANITIZER=undefined SERVER_CFLAGS='-Werror' LUA_DEBUG=yes
      - name: testprep
        run: |
          sudo apt-get update
          sudo apt-get install tcl8.6 tclx -y
      - name: Start memory monitor
        run: |
          # Track minimum free memory to detect OOM risk
          (while true; do
            FREE=$(awk '/MemAvailable/ {print $2}' /proc/meminfo)
            echo "$FREE" >> /tmp/memfree.log
            sleep 5
          done) &
          echo $! > /tmp/memmon.pid
      - name: unittest
        if: true && !contains(github.event.inputs.skiptests, 'unittest')
        run: |
          if [ -f ./src/unit/valkey-unit-gtests ]; then
            make test-unit accurate=1 large_memory=1
          elif [ -f ./src/valkey-unit-tests ]; then
            ./src/valkey-unit-tests --accurate --large-memory
          fi
      - name: large memory tests
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest --accurate --failures-output test-failures/valkey.json --verbose --dump-logs --clients 1 --large-memory --tags large-memory ${{github.event.inputs.test_args}}
      - name: large memory module api tests
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs --clients 1 --large-memory --tags large-memory ${{github.event.inputs.test_args}}
      - name: Memory usage summary
        if: always()
        run: |
          kill $(cat /tmp/memmon.pid) 2>/dev/null || true
          echo "=== Memory Summary ==="
          printf "Total RAM: %.1fGB\n" $(awk '/MemTotal/ {print $2/1024/1024}' /proc/meminfo)
          if [ -f /tmp/memfree.log ]; then
            MIN_FREE=$(sort -n /tmp/memfree.log | head -1)
            printf "Minimum free memory: %.1fGB\n" $(echo "$MIN_FREE/1024/1024" | bc -l)
          fi
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}-${{ matrix.compiler }}
  test-sanitizer-force-defrag:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'sanitizer')
    timeout-minutes: 1440
    strategy:
      fail-fast: false
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: Install gtest
        run: sudo apt-get install pkg-config libgtest-dev libgmock-dev
      - name: make
        run: make all-with-unit-tests OPT=-O3 SANITIZER=address DEBUG_FORCE_DEFRAG=yes USE_JEMALLOC=no SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: |
          sudo apt-get update
          sudo apt-get install tcl8.6 tclx -y
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest --accurate --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: unittest
        if: true && !contains(github.event.inputs.skiptests, 'unittest')
        run: |
          if [ -f ./src/unit/valkey-unit-gtests ]; then
            make test-unit
          elif [ -f ./src/valkey-unit-tests ]; then
            ./src/valkey-unit-tests
          fi
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-ubuntu-lttng:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'lttng')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - name: Build libbacktrace
        run: |
          sudo apt-get update && sudo apt-get install lttng-tools lttng-modules-dkms liblttng-ust-dev
          cd libbacktrace && ./configure && make && sudo make install
      - name: make
        run: make -j4 USE_LTTNG=yes USE_LIBBACKTRACE=yes
      - name: testprep
        run: sudo apt-get install tcl8.6 tclx
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-rpm-distros-jemalloc:
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'rpm-distros')
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: test-almalinux8-jemalloc
            container: almalinux:8
            install_epel: true
          - name: test-almalinux9-jemalloc
            container: almalinux:9
            install_epel: true
          - name: test-centosstream9-jemalloc
            container: quay.io/centos/centos:stream9
            install_epel: true
          - name: test-fedoralatest-jemalloc
            container: fedora:latest
          - name: test-fedorarawhide-jemalloc
            container: fedora:rawhide
    name: ${{ matrix.name }}
    runs-on: ubuntu-latest
    container: ${{ matrix.container }}
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install EPEL
        if: matrix.install_epel
        run: dnf -y install epel-release
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - name: Build libbacktrace
        run: |
          dnf -y install gcc make procps-ng which /usr/bin/kill /usr/bin/awk
          cd libbacktrace && ./configure && make && make install
      - name: make
        run: make -j SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: dnf -y install tcl tcltls
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ matrix.name }}
  test-rpm-distros-tls-module:
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'tls')
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: test-almalinux8-tls-module
            container: almalinux:8
            install_epel: true
          - name: test-almalinux9-tls-module
            container: almalinux:9
            install_epel: true
          - name: test-centosstream9-tls-module
            container: quay.io/centos/centos:stream9
            install_epel: true
          - name: test-fedoralatest-tls-module
            container: fedora:latest
          - name: test-fedorarawhide-tls-module
            container: fedora:rawhide
    name: ${{ matrix.name }}
    runs-on: ubuntu-latest
    container: ${{ matrix.container }}
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install EPEL
        if: matrix.install_epel
        run: dnf -y install epel-release
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - name: Build libbacktrace
        run: |
          dnf -y install make gcc openssl-devel openssl procps-ng which /usr/bin/kill /usr/bin/awk
          cd libbacktrace && ./configure && make && make install
      - name: make
        run: make -j BUILD_TLS=module SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: |
          dnf -y install tcl tcltls
          ./utils/gen-test-certs.sh
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: |
          ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --dump-logs --tls-module ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: |
          CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs --tls-module ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: |
          ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ matrix.name }}
  test-rpm-distros-tls-module-no-tls:
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' && github.event.pull_request.base.ref != 'unstable' && github.event.action != 'labeled')) &&
      !contains(github.event.inputs.skipjobs, 'tls')
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: test-almalinux8-tls-module-no-tls
            container: almalinux:8
            install_epel: true
          - name: test-almalinux9-tls-module-no-tls
            container: almalinux:9
            install_epel: true
          - name: test-centosstream9-tls-module-no-tls
            container: quay.io/centos/centos:stream9
            install_epel: true
          - name: test-fedoralatest-tls-module-no-tls
            container: fedora:latest
          - name: test-fedorarawhide-tls-module-no-tls
            container: fedora:rawhide
    name: ${{ matrix.name }}
    runs-on: ubuntu-latest
    container: ${{ matrix.container }}
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install EPEL
        if: matrix.install_epel
        run: dnf -y install epel-release
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - name: Build libbacktrace
        run: |
          dnf -y install make gcc openssl-devel openssl procps-ng which /usr/bin/kill /usr/bin/awk
          cd libbacktrace && ./configure && make && make install
      - name: make
        run: make -j BUILD_TLS=module SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: testprep
        run: |
          dnf -y install tcl tcltls
          ./utils/gen-test-certs.sh
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: |
          ./runtest --accurate --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: |
          CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: |
          ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ matrix.name }}
  test-macos-latest:
    runs-on: macos-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'macos') && !(contains(github.event.inputs.skiptests, 'valkey') && contains(github.event.inputs.skiptests, 'modules'))
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: make
        run: make SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --clients 1 --no-latency --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --clients 1 --no-latency --dump-logs ${{github.event.inputs.test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-macos-latest-sentinel:
    runs-on: macos-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'macos') && !contains(github.event.inputs.skiptests, 'sentinel')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: make
        run: make SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-macos-latest-cluster:
    runs-on: macos-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'macos') && !contains(github.event.inputs.skiptests, 'cluster')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: make
        run: make SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
  build-old-macos-versions:
    strategy:
      fail-fast: false
      matrix:
        os: [macos-14]
    runs-on: ${{ matrix.os }}
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'macos')
    timeout-minutes: 1440
    steps:
      - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0
        with:
          xcode-version: latest
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: make
        run: make SERVER_CFLAGS='-Werror' USE_LIBBACKTRACE=yes
  test-freebsd:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'freebsd')
    timeout-minutes: 1440
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: test
        uses: cross-platform-actions/action@39a2a80642eca0947594ad03e4355dc3d28c617a # v0.32.0
        with:
          operating_system: freebsd
          environment_variables: MAKE
          version: 13.2
          shell: bash
          run: |
            sudo pkg install -y bash gmake lang/tcl86 lang/tclX
            gmake
            ./runtest --failures-output test-failures/valkey.json --single unit/keyspace --single unit/auth --single unit/networking --single unit/protocol
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-alpine-jemalloc:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'alpine')
    container: alpine:latest
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - name: Build libbacktrace
        run: |
          apk add build-base git zstd-dev zstd-static
          cd libbacktrace && ./configure && make && make install
      - name: make
        run: make SERVER_CFLAGS='-Werror' BUILD_ZSTD=yes USE_LIBBACKTRACE=yes
      - name: testprep
        run: apk add tcl procps tclx
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-alpine-libc-malloc:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'alpine')
    container: alpine:latest
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - name: Build libbacktrace
        run: |
          apk add build-base git
          cd libbacktrace && ./configure && make && make install
      - name: make
        run: make SERVER_CFLAGS='-Werror' USE_JEMALLOC=no CFLAGS=-DUSE_MALLOC_USABLE_SIZE USE_LIBBACKTRACE=yes
      - name: testprep
        run: apk add tcl procps tclx
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest ${{ github.event_name != 'pull_request' && '--accurate' || '' }} --failures-output test-failures/valkey.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json ${{github.event.inputs.cluster_test_args}}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  test-alpine-32bit:
    runs-on: ubuntu-latest
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'alpine') &&
      !contains(github.event.inputs.skipjobs, '32bit')
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Run 32-bit Alpine tests
        env:
          RUN_ACCURATE: ${{ github.event_name != 'pull_request' && '--accurate' || '' }}
          SKIPTESTS: ${{ github.event.inputs.skiptests }}
          TEST_ARGS: ${{ github.event.inputs.test_args }}
          CLUSTER_TEST_ARGS: ${{ github.event.inputs.cluster_test_args }}
        run: |
          docker run --rm \
            --platform linux/386 \
            -v "$PWD:/src" \
            -w /src \
            -e RUN_ACCURATE \
            -e SKIPTESTS \
            -e TEST_ARGS \
            -e CLUSTER_TEST_ARGS \
            i386/alpine:latest \
            sh -euxc '
              apk add --no-cache bash build-base git gtest-dev linux-headers procps python3 tcl tclx

              rm -rf libbacktrace
              git clone https://github.com/ianlancetaylor/libbacktrace.git libbacktrace
              cd libbacktrace
              git checkout b9e40069c0b47a722286b94eb5231f7f05c08713
              ./configure
              make -j$(nproc)
              make install
              cd /src

              make SERVER_CFLAGS="-Werror" USE_LIBBACKTRACE=yes 32bit

              case "${SKIPTESTS:-}" in
                *valkey*) ;;
                *) ./runtest ${RUN_ACCURATE:-} --failures-output test-failures/valkey.json --verbose --dump-logs ${TEST_ARGS:-} ;;
              esac

              case "${SKIPTESTS:-}" in
                *modules*) ;;
                *)
                  make -C tests/modules 32bit
                  CFLAGS="-Werror" ./runtest-moduleapi --failures-output test-failures/moduleapi.json --verbose --dump-logs ${TEST_ARGS:-}
                  ;;
              esac

              case "${SKIPTESTS:-}" in
                *sentinel*) ;;
                *) ./runtest-sentinel --failures-output test-failures/sentinel.json ${CLUSTER_TEST_ARGS:-} ;;
              esac
            '
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}

  reply-schemas-validator:
    runs-on: ubuntu-latest
    timeout-minutes: 1440
    if: |
      (github.event_name == 'workflow_call' || github.event_name == 'workflow_dispatch' ||
        (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey') ||
        (github.event_name == 'pull_request' &&
          (github.event.pull_request.base.ref != 'unstable' ||
            contains(github.event.pull_request.labels.*.name, 'run-extra-tests')) &&
          (github.event.action != 'labeled' ||
            (github.event.pull_request.base.ref == 'unstable' && github.event.label.name == 'run-extra-tests'))
        )) &&
      !contains(github.event.inputs.skipjobs, 'reply-schema')
    steps:
      - name: prep
        if: github.event_name == 'workflow_dispatch' || github.event_name == 'workflow_call'
        run: |
          echo "GITHUB_REPOSITORY=${{inputs.use_repo || github.event.inputs.use_repo}}" >> $GITHUB_ENV
          echo "GITHUB_HEAD_REF=${{inputs.use_git_ref || github.event.inputs.use_git_ref}}" >> $GITHUB_ENV
          echo "skipjobs: ${{github.event.inputs.skipjobs}}"
          echo "skiptests: ${{github.event.inputs.skiptests}}"
          echo "test_args: ${{github.event.inputs.test_args}}"
          echo "cluster_test_args: ${{github.event.inputs.cluster_test_args}}"
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ${{ inputs.use_repo || github.event.inputs.use_repo || github.repository }}
          ref: ${{ inputs.use_git_ref || github.event.inputs.use_git_ref || github.ref }}
      - name: Install libbacktrace
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          repository: ianlancetaylor/libbacktrace
          ref: b9e40069c0b47a722286b94eb5231f7f05c08713
          path: libbacktrace
      - run: cd libbacktrace && ./configure && make && sudo make install
      - name: make
        run: make SERVER_CFLAGS='-Werror -DLOG_REQ_RES' USE_LIBBACKTRACE=yes
      - name: testprep
        run: sudo apt-get install tcl8.6 tclx
      - name: test
        if: true && !contains(github.event.inputs.skiptests, 'valkey')
        run: ./runtest --failures-output test-failures/valkey.json --log-req-res --no-latency --dont-clean --force-resp3 --tags -slow --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: module api test
        if: true && !contains(github.event.inputs.skiptests, 'modules')
        run: CFLAGS='-Werror' ./runtest-moduleapi --failures-output test-failures/moduleapi.json --log-req-res --no-latency --dont-clean --force-resp3 --dont-pre-clean --verbose --dump-logs ${{github.event.inputs.test_args}}
      - name: sentinel tests
        if: true && !contains(github.event.inputs.skiptests, 'sentinel')
        run: ./runtest-sentinel --failures-output test-failures/sentinel.json --log-req-res --dont-clean --force-resp3 ${{github.event.inputs.cluster_test_args}}
      - name: Install Python dependencies
        uses: py-actions/py-dependency-install@30aa0023464ed4b5b116bd9fbdab87acf01a484e # v4.1.0
        with:
          path: "./utils/req-res-validator/requirements.txt"
      - name: validator
        run: ./utils/req-res-log-validator.py --verbose --fail-missing-reply-schemas ${{ (!contains(github.event.inputs.skiptests, 'valkey') && !contains(github.event.inputs.skiptests, 'module') && !contains(github.event.inputs.skiptests, 'sentinel') && !contains(github.event.inputs.skiptests, 'cluster')) && (inputs.test_args || github.event.inputs.test_args || '') == '' && (inputs.cluster_test_args || github.event.inputs.cluster_test_args || '') == '' && '--fail-commands-not-all-hit' || '' }}
      - name: Upload test failures
        if: always()
        uses: ./.github/actions/upload-test-failures
        with:
          job-name: ${{ github.job }}
  consolidate-test-failures:
    runs-on: ubuntu-latest
    if: |
      always() &&
      (github.event_name == 'workflow_dispatch' ||
      (github.event_name == 'schedule' && github.repository == 'valkey-io/valkey'))
    permissions:
      actions: write
    needs:
      - test-ubuntu-jemalloc
      - test-ubuntu-arm
      - test-ubuntu-jemalloc-fortify
      - test-ubuntu-libc-malloc
      - test-ubuntu-no-malloc-usable-size
      - test-ubuntu-32bit
      - test-ubuntu-tls
      - test-ubuntu-tls-no-tls
      - test-ubuntu-io-threads
      - test-ubuntu-tls-io-threads
      - test-valgrind-test
      - test-valgrind-misc
      - test-valgrind-no-malloc-usable-size-test
      - test-valgrind-no-malloc-usable-size-misc
      - test-sanitizer-address
      - test-sanitizer-address-large-memory
      - test-sanitizer-undefined
      - test-sanitizer-undefined-large-memory
      - test-sanitizer-force-defrag
      - test-ubuntu-lttng
      - test-rpm-distros-jemalloc
      - test-rpm-distros-tls-module
      - test-rpm-distros-tls-module-no-tls
      - test-macos-latest
      - test-macos-latest-sentinel
      - test-macos-latest-cluster
      - test-freebsd
      - test-alpine-jemalloc
      - test-alpine-libc-malloc
      - test-alpine-32bit
      - reply-schemas-validator
    steps:
      - name: Download all failures
        uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
        with:
          pattern: test-failures-*
          path: individual-failures
          merge-multiple: false

      - name: Merge into single file
        id: merge
        run: |
          python3 << 'EOF'
          import json, glob, os

          merged = {}
          damaged = []

          # Every field the Tcl writers emit for a failure. A file can parse as
          # JSON yet still be damaged: a run killed mid-write can leave a null or
          # a half-built object in the list. Those publish as real failures the
          # detector then reads as empty, so the entry shape is checked too, not
          # just the list around it.
          REQUIRED_FAILURE_FIELDS = ("test_name", "test_file", "status", "error")

          def invalid_entry_reason(entry, index):
              """Why *entry* is not a usable failure object, or None if it is."""
              if not isinstance(entry, dict):
                  return f"entry {index} is {type(entry).__name__}, expected an object"
              missing = [f for f in REQUIRED_FAILURE_FIELDS if f not in entry]
              if missing:
                  return f"entry {index} is missing {', '.join(missing)}"
              nonstring = [
                  f for f in REQUIRED_FAILURE_FIELDS
                  if not isinstance(entry[f], str)
              ]
              if nonstring:
                  return f"entry {index} has non-string {', '.join(nonstring)}"
              return None

          for job_dir in sorted(glob.glob("individual-failures/test-failures-*")):
              job_name = os.path.basename(job_dir).replace("test-failures-", "")
              merged[job_name] = {}

              for suite_file in glob.glob(os.path.join(job_dir, "*.json")):
                  suite_name = os.path.splitext(os.path.basename(suite_file))[0]
                  # Read each suite independently. A damaged file (a job killed
                  # mid-write, a truncated upload) must not abort the merge: the
                  # artifact carries every other job's failures too.
                  try:
                      with open(suite_file, encoding="utf-8") as f:
                          data = json.load(f)
                  except (OSError, ValueError) as exc:
                      damaged.append(f"{job_name}/{suite_name}: {exc}")
                      print(f"{job_name}/{suite_name}: unreadable, skipped ({exc})")
                      continue
                  # A suite file is a list of failures. Anything else parses but
                  # has no length, so treat it as damaged rather than letting it
                  # raise past this loop and lose the whole artifact.
                  if not isinstance(data, list):
                      reason = f"expected a JSON list, got {type(data).__name__}"
                      damaged.append(f"{job_name}/{suite_name}: {reason}")
                      print(f"{job_name}/{suite_name}: unreadable, skipped ({reason})")
                      continue
                  entry_reasons = [
                      r for r in (
                          invalid_entry_reason(e, i) for i, e in enumerate(data)
                      ) if r
                  ]
                  if entry_reasons:
                      reason = "; ".join(entry_reasons)
                      damaged.append(f"{job_name}/{suite_name}: {reason}")
                      print(f"{job_name}/{suite_name}: unreadable, skipped ({reason})")
                      continue
                  merged[job_name][suite_name] = data
                  count = len(data)
                  if count:
                      print(f"{job_name}/{suite_name}: {count} failure(s)")
                  else:
                      print(f"{job_name}/{suite_name}: no failures")

          with open("all-test-failures.json", "w") as f:
              json.dump(merged, f, indent=2)

          if damaged:
              # Record the loss for the step that fails this job after the
              # upload. The artifact is still worth publishing because it holds
              # every readable job's failures, but it is incomplete, so the job
              # must not report success.
              print(f"::error::{len(damaged)} suite file(s) could not be read "
                    f"and are missing from the artifact: {'; '.join(damaged)}")
              with open("consolidation-damage.txt", "w") as f:
                  f.write("\n".join(damaged))

          # Signal damage to later steps so the per-job artifacts that fed the
          # merge are kept for inspection rather than deleted.
          step_output = os.environ.get("GITHUB_OUTPUT")
          if step_output:
              with open(step_output, "a") as f:
                  f.write(f"damaged={'true' if damaged else 'false'}\n")
          EOF

      - name: Upload consolidated failures
        uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
        with:
          name: all-test-failures
          path: all-test-failures.json
          retention-days: 30

      # Skip the cleanup when a suite file was damaged, so the per-job
      # artifacts survive for inspection. The parse-error string alone is not
      # enough to reconstruct a file killed mid-write or truncated on upload.
      - name: Delete individual artifacts
        if: steps.merge.outputs.damaged != 'true'
        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
        with:
          script: |
            const artifacts = await github.paginate(
              github.rest.actions.listWorkflowRunArtifacts,
              {
                owner: context.repo.owner,
                repo: context.repo.repo,
                run_id: context.runId,
              },
              (response) => response.data
            );

            for (const artifact of artifacts) {
              if (artifact.name.startsWith('test-failures-')) {
                console.log(`Deleting: ${artifact.name}`);
                await github.rest.actions.deleteArtifact({
                  owner: context.repo.owner,
                  repo: context.repo.repo,
                  artifact_id: artifact.id,
                });
              }
            }
            console.log('Done. Individual artifacts deleted.');

      # Last step, so the consolidated artifact is published and any healthy
      # per-job artifacts are cleaned up first. An artifact missing some suites
      # must not leave this job green.
      - name: Fail if any suite file was unreadable
        run: |
          if [ -f consolidation-damage.txt ]; then
            echo "Suite files missing from the artifact:"
            cat consolidation-damage.txt
            exit 1
          fi
  notify-about-job-results:
    runs-on: ubuntu-latest
    if: always() && github.event_name == 'schedule' && github.repository == 'valkey-io/valkey'
    needs:
      - test-ubuntu-jemalloc
      - test-ubuntu-arm
      - test-s390x
      - test-ubuntu-jemalloc-fortify
      - test-ubuntu-libc-malloc
      - test-ubuntu-no-malloc-usable-size
      - test-ubuntu-32bit
      - test-ubuntu-tls
      - test-ubuntu-tls-no-tls
      - test-ubuntu-io-threads
      - test-ubuntu-tls-io-threads
      - test-ubuntu-reclaim-cache
      - test-valgrind-test
      - test-valgrind-misc
      - test-valgrind-no-malloc-usable-size-test
      - test-valgrind-no-malloc-usable-size-misc
      - test-sanitizer-address
      - test-sanitizer-address-large-memory
      - test-sanitizer-undefined
      - test-sanitizer-undefined-large-memory
      - test-sanitizer-force-defrag
      - test-ubuntu-lttng
      - test-rpm-distros-jemalloc
      - test-rpm-distros-tls-module
      - test-rpm-distros-tls-module-no-tls
      - test-macos-latest
      - test-macos-latest-sentinel
      - test-macos-latest-cluster
      - build-old-macos-versions
      - test-freebsd
      - test-alpine-jemalloc
      - test-alpine-libc-malloc
      - test-alpine-32bit
      - reply-schemas-validator
      - consolidate-test-failures
    steps:
      - name: Collect job status
        run: |
          FAILED_JOBS=()
          NEEDS_JSON='${{ toJSON(needs) }}'
          JOBS=($(echo "$NEEDS_JSON" | jq 'keys' | tr -d '[] ,'))
          for JOB in ${JOBS[@]}; do
            JOB_RESULT=$(echo "$NEEDS_JSON" | jq ".[$JOB][\"result\"]" | tr -d '"')
            if [ $JOB_RESULT = "failure" ]; then
              FAILED_JOBS+=($JOB)
            fi
          done

          if [[ ${#FAILED_JOBS[@]} -ne 0 ]]; then
            echo "FAILED_JOBS=${FAILED_JOBS[@]}" >> $GITHUB_ENV
            echo "STATUS=failure" >> $GITHUB_ENV
          else
            echo "STATUS=success" >> $GITHUB_ENV
          fi
      - name: Notify about results
        uses: ravsamhq/notify-slack-action@042f29088bb3bdbda5b4ff7b4818466a277fa8f7 # v2.5.0
        with:
          status: ${{ env.STATUS }}
          notify_when: "failure"
          notification_title: "Daily test run <${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}}|Failure>"
          message_format: ":fire: Tests failed: ${{ env.FAILED_JOBS }}"
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_NOTIFICATIONS_WEBHOOK_URL }}
