name: Testing

# Trigger on pushes, PRs (excluding documentation changes), and nightly.
on:
  push:
  pull_request:
  schedule:
    - cron: 0 0 * * * # daily at 00:00

permissions:
  contents: read

# Always force the use of Go modules
env:
  GO111MODULE: on

jobs:
  # Check generated protos match their source repos (optional for PRs).
  vet-proto:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4

      # Setup the environment.
      - name: Setup Go
        uses: actions/setup-go@v5
        with:
          go-version: '1.22'
          cache-dependency-path: "**/go.sum"

      # Run the vet-proto checks.
      - name: vet-proto
        run: ./scripts/vet-proto.sh -install && ./scripts/vet-proto.sh

  # Run the main gRPC-Go tests.
  tests:
    runs-on: ubuntu-latest
    timeout-minutes: 20
    strategy:
      fail-fast: false
      matrix:
        include:
          - type: vet
            goversion: '1.22'

          - type: extras
            goversion: '1.22'

          - type: tests
            goversion: '1.22'

          - type: tests
            goversion: '1.22'
            testflags: -race

          - type: tests
            goversion: '1.22'
            testflags: '-race -tags=buffer_pooling'

          - type: tests
            goversion: '1.22'
            goarch: 386

          - type: tests
            goversion: '1.22'
            goarch: arm64

          - type: tests
            goversion: '1.21'

          - type: tests
            goversion: '1.22'
            testflags: -race
            grpcenv: 'GRPC_EXPERIMENTAL_ENABLE_NEW_PICK_FIRST=true'

    steps:
      # Setup the environment.
      - name: Setup GOARCH
        if: matrix.goarch != ''
        run: echo "GOARCH=${{ matrix.goarch }}" >> $GITHUB_ENV

      - name: Setup qemu emulator
        if: matrix.goarch == 'arm64'
        # setup qemu-user-static emulator and register it with binfmt_misc so that aarch64 binaries
        # are automatically executed using qemu.
        run: docker run --rm --privileged multiarch/qemu-user-static:7.2.0-1 --reset --credential yes --persistent yes

      - name: Setup GRPC environment
        if: matrix.grpcenv != ''
        run: echo "${{ matrix.grpcenv }}" >> $GITHUB_ENV

      - name: Checkout repo
        uses: actions/checkout@v4

      - name: Setup Go
        uses: actions/setup-go@v5
        with:
          go-version: ${{ matrix.goversion }}
          cache-dependency-path: "**/*go.sum"

      # Only run vet for 'vet' runs.
      - name: Run vet.sh
        if: matrix.type == 'vet'
        run: ./scripts/vet.sh -install && ./scripts/vet.sh

      # Main tests run for everything except when testing "extras"
      # (where we run a reduced set of tests).
      - name: Run tests
        if: matrix.type == 'tests'
        run: |
          go version
          go test ${{ matrix.testflags }} -cpu 1,4 -timeout 7m google.golang.org/grpc/...
          cd "${GITHUB_WORKSPACE}"
          for MOD_FILE in $(find . -name 'go.mod' | grep -Ev '^\./go\.mod'); do
            pushd "$(dirname ${MOD_FILE})"
            go test ${{ matrix.testflags }} -cpu 1,4 -timeout 2m ./...
            popd
          done

      # Non-core gRPC tests (examples, interop, etc)
      - name: Run extras tests
        if: matrix.type == 'extras'
        run: |
          export TERM=${TERM:-xterm}
          go version
          echo -e "\n-- Running Examples --"
          examples/examples_test.sh
          echo -e "\n-- Running AdvancedTLS Examples --"
          security/advancedtls/examples/examples_test.sh
          echo -e "\n-- Running Interop Test --"
          interop/interop_test.sh
          echo -e "\n-- Running xDS E2E Test --"
          xds/internal/test/e2e/run.sh
          echo -e "\n-- Running protoc-gen-go-grpc test --"
          ./scripts/vet-proto.sh -install
          cmd/protoc-gen-go-grpc/protoc-gen-go-grpc_test.sh
