name: test

on:
  push:
    branches:
      - integration
      - '**-ci'
      - '**-cig'
  pull_request:
    branches:
      - integration
      - '**-ci'
      - '**-cig'

jobs:
  test:
    runs-on: ubuntu-22.04

    strategy:
      # Let all the jobs run to completion even if one fails
      fail-fast: false

      # The first jobs should be the canaries in the coal mine, i.e. the most likely to fail if there are problems in the code. They
      # should also be a good mix of unit, integration, and documentation tests.
      #
      # In general tests should be ordered from slowest to fastest. This does not make a difference for testing a single commit, but
      # when multiple commits are being tested it is best to have the slowest jobs first so that as jobs become available they will
      # tackle the slowest tests first.
      matrix:
        include:
          # All tests (without coverage or valgrind) for 32-bit
          - param: test --vm=d11 --param=no-performance --param=no-coverage --param=no-valgrind

          # Debian/Ubuntu documentation
          - param: doc --vm=u22

          # All integration tests
          - param: test --vm=u22 --param=build-package --param=module=integration

          # All unit tests with coverage, backtrace and alternate timezone
          - param: test --vm=u22 --param=c-only --param=no-valgrind --param=tz=America/New_York

          # All unit tests with valgrind (disable coverage and backtrace for performance)
          - param: test --vm=u22 --param=c-only --param=no-coverage --param=no-back-trace

          # All unit tests on the newest gcc available
          - param: test --vm=f42 --param=c-only --param=no-valgrind --param=no-coverage --param=no-performance

          # All unit tests on musl libc
          - param: test --vm=a321 --param=c-only --param=no-coverage --param=no-performance

          # RHEL documentation
          - param: doc --vm=rh8

          # All integration tests
          - param: test --vm=rh8 --param=module=integration

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          path: pgbackrest

      - name: Run Test
        run: cd ${HOME?} && ${GITHUB_WORKSPACE?}/pgbackrest/test/ci.pl ${{matrix.param}} --param=build-max=2

      # Output the coverage report on failure in case the failure was caused by lack of coverage. This is not ideal since the report
      # needs to be copied from the log output into an HTML file where it can be viewed, but better than nothing.
      - name: Coverage Report
        if: failure()
        run: |
          cat ${GITHUB_WORKSPACE?}/pgbackrest/test/result/coverage/coverage.html

  # Unit tests on aarch64 with valgrind
  aarch64:
    runs-on: ubuntu-22.04-arm

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          path: pgbackrest

      - name: Run Test
        run: cd ${HOME?} && ${GITHUB_WORKSPACE?}/pgbackrest/test/ci.pl test --vm=u22 --param=c-only --param=no-coverage --param=no-back-trace --param=build-max=2

  # Basic tests on other architectures using emulation. The emulation is so slow that running all the unit tests would be too
  # expensive, but this at least shows that the build works and some of the more complex tests run. In particular, it is good to
  # test on one big-endian architecture to be sure that checksums are correct.
  arch:
    runs-on: ubuntu-24.04

    strategy:
      # Let all the jobs run to completion even if one fails
      fail-fast: false

      matrix:
        include:
          - arch: 'ppc64le'
          - arch: 's390x'

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          path: pgbackrest

      - name: Install
        run: |
          sudo apt-get update
          sudo DEBCONF_NONINTERACTIVE_SEEN=true DEBIAN_FRONTEND=noninteractive apt-get install -y perl sudo libxml-checker-perl libyaml-perl rsync zlib1g-dev libssl-dev libxml2-dev libpq-dev libyaml-dev pkg-config make gcc ccache meson git liblz4-dev liblz4-tool zstd libzstd-dev bzip2 libbz2-dev
          docker run --privileged --rm tonistiigi/binfmt --install all

      - name: Build VM
        run: ${GITHUB_WORKSPACE?}/pgbackrest/test/test.pl --vm-build --vm=u22 --vm-arch=${{matrix.arch}}

      - name: Run Test
        run: |
          ${GITHUB_WORKSPACE?}/pgbackrest/test/test.pl --vm=u22 --vm-arch=${{matrix.arch}} --no-valgrind --no-coverage --no-optimize --build-max=2 --module=command --test=backup
          ${GITHUB_WORKSPACE?}/pgbackrest/test/test.pl --vm=u22 --vm-arch=${{matrix.arch}} --no-valgrind --no-coverage --no-optimize --build-max=2 --module=postgres --test=interface

  # Run meson unity build to check for errors, unused functions, and externed functions
  unity:
    runs-on: ubuntu-24.04

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          path: pgbackrest

      - name: Install
        run: |
          sudo apt-get update
          DEBCONF_NONINTERACTIVE_SEEN=true DEBIAN_FRONTEND=noninteractive sudo apt-get install -y zlib1g-dev libssl-dev libxml2-dev libpq-dev libyaml-dev pkg-config meson liblz4-dev libzstd-dev libbz2-dev

      - name: Build
        run: |
          meson setup --unity=on -Dwerror=true build ${GITHUB_WORKSPACE?}/pgbackrest
          ninja -vC build

      - name: Check
        run: |
          diff ${GITHUB_WORKSPACE?}/pgbackrest/.github/workflows/symbol.out <(nm -gj --defined-only build/src/pgbackrest)

  # Check that code is correctly formatted
  code-format:
    runs-on: ubuntu-22.04

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          path: pgbackrest

      - name: Check
        run: |
          cd ${HOME?} && ${GITHUB_WORKSPACE?}/pgbackrest/test/ci.pl test --param=code-format-check

  codeql:
    runs-on: ubuntu-24.04

    permissions:
      actions: read
      contents: read
      security-events: write

    strategy:
      fail-fast: false
      matrix:
        language:
          - cpp

    steps:
      - name: Checkout Code
        uses: actions/checkout@v4

      - name: Install Packages
        run: sudo apt-get install -y --no-install-recommends libyaml-dev libbz2-dev meson

      - name: Initialize CodeQL
        uses: github/codeql-action/init@v3
        with:
          languages: ${{matrix.language}}

      - name: Build
        run: meson setup ${HOME?}/build ${GITHUB_WORKSPACE?} && ninja -C ${HOME?}/build

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v3
