name: Ruby Testing

on:
  push:
    branches-ignore:
      - 'dependabot/**'
      - 'renovate/**'
  pull_request:

env:
  BUNDLE_CLEAN: true
  BUNDLE_FROZEN: true

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      fail-fast: true
      matrix:
        mode:
          - production
          - test
    env:
      RAILS_ENV: ${{ matrix.mode }}
      BUNDLE_WITH: ${{ matrix.mode }}
      OTP_SECRET: precompile_placeholder
      SECRET_KEY_BASE: precompile_placeholder

    steps:
      - uses: actions/checkout@v4

      - name: Set up Ruby environment
        uses: ./.github/actions/setup-ruby

      - name: Set up Javascript environment
        uses: ./.github/actions/setup-javascript
        with:
          onlyProduction: 'true'

      - name: Precompile assets
        # Previously had set this, but it's not supported
        # export NODE_OPTIONS=--openssl-legacy-provider
        run: |-
          ./bin/rails assets:precompile

      - name: Archive asset artifacts
        run: |
          tar --exclude={"*.br","*.gz"} -zcf artifacts.tar.gz public/assets public/packs*

      - uses: actions/upload-artifact@v3
        if: matrix.mode == 'test'
        with:
          path: |-
            ./artifacts.tar.gz
          name: ${{ github.sha }}
          retention-days: 0

  test:
    runs-on: ubuntu-latest

    needs:
      - build

    services:
      postgres:
        image: postgres:14-alpine
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_USER: postgres
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432

      redis:
        image: redis:7-alpine
        options: >-
          --health-cmd "redis-cli ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 6379:6379

    env:
      DB_HOST: localhost
      DB_USER: postgres
      DB_PASS: postgres
      DISABLE_SIMPLECOV: ${{ matrix.ruby-version != '.ruby-version' }}
      RAILS_ENV: test
      ALLOW_NOPAM: true
      PAM_ENABLED: true
      PAM_DEFAULT_SERVICE: pam_test
      PAM_CONTROLLED_SERVICE: pam_test_controlled
      OIDC_ENABLED: true
      OIDC_SCOPE: read
      SAML_ENABLED: true
      CAS_ENABLED: true
      BUNDLE_WITH: 'pam_authentication test'
      GITHUB_RSPEC: ${{ matrix.ruby-version == '.ruby-version' && github.event.pull_request && 'true' }}

    strategy:
      fail-fast: false
      matrix:
        ruby-version:
          - '3.0'
          - '3.1'
          - '.ruby-version'
    steps:
      - uses: actions/checkout@v4

      - uses: actions/download-artifact@v3
        with:
          path: './'
          name: ${{ github.sha }}

      - name: Expand archived asset artifacts
        run: |
          tar xvzf artifacts.tar.gz

      - name: Set up Ruby environment
        uses: ./.github/actions/setup-ruby
        with:
          ruby-version: ${{ matrix.ruby-version}}
          additional-system-dependencies: ffmpeg imagemagick libpam-dev

      - name: Load database schema
        run: './bin/rails db:create db:schema:load db:seed'

      - run: bin/rspec

      - name: Upload coverage reports to Codecov
        if: matrix.ruby-version == '.ruby-version'
        uses: codecov/codecov-action@v3
        with:
          files: coverage/lcov/mastodon.lcov

  test-e2e:
    name: End to End testing
    runs-on: ubuntu-latest

    needs:
      - build

    services:
      postgres:
        image: postgres:14-alpine
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_USER: postgres
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432

      redis:
        image: redis:7-alpine
        options: >-
          --health-cmd "redis-cli ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 6379:6379

    env:
      DB_HOST: localhost
      DB_USER: postgres
      DB_PASS: postgres
      DISABLE_SIMPLECOV: true
      RAILS_ENV: test
      BUNDLE_WITH: test

    strategy:
      fail-fast: false
      matrix:
        ruby-version:
          - '3.0'
          - '3.1'
          - '.ruby-version'

    steps:
      - uses: actions/checkout@v4

      - uses: actions/download-artifact@v3
        with:
          path: './public'
          name: ${{ github.sha }}

      - name: Set up Ruby environment
        uses: ./.github/actions/setup-ruby
        with:
          ruby-version: ${{ matrix.ruby-version}}
          additional-system-dependencies: ffmpeg imagemagick

      - name: Set up Javascript environment
        uses: ./.github/actions/setup-javascript

      - name: Load database schema
        run: './bin/rails db:create db:schema:load db:seed'

      - run: bundle exec rake spec:system

      - name: Archive logs
        uses: actions/upload-artifact@v3
        if: failure()
        with:
          name: e2e-logs-${{ matrix.ruby-version }}
          path: log/

      - name: Archive test screenshots
        uses: actions/upload-artifact@v3
        if: failure()
        with:
          name: e2e-screenshots
          path: tmp/screenshots/

  test-search:
    name: Elastic Search integration testing
    runs-on: ubuntu-latest

    needs:
      - build

    services:
      postgres:
        image: postgres:14-alpine
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_USER: postgres
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432

      redis:
        image: redis:7-alpine
        options: >-
          --health-cmd "redis-cli ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 6379:6379

      search:
        image: ${{ matrix.search-image }}
        env:
          discovery.type: single-node
          xpack.security.enabled: false
        options: >-
          --health-cmd "curl http://localhost:9200/_cluster/health"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 10
        ports:
          - 9200:9200

    env:
      DB_HOST: localhost
      DB_USER: postgres
      DB_PASS: postgres
      DISABLE_SIMPLECOV: true
      RAILS_ENV: test
      BUNDLE_WITH: test
      ES_ENABLED: true
      ES_HOST: localhost
      ES_PORT: 9200

    strategy:
      fail-fast: false
      matrix:
        ruby-version:
          - '3.0'
          - '3.1'
          - '.ruby-version'
        search-image:
          - docker.elastic.co/elasticsearch/elasticsearch:7.17.13
        include:
          - ruby-version: '.ruby-version'
            search-image: docker.elastic.co/elasticsearch/elasticsearch:8.10.2

    steps:
      - uses: actions/checkout@v4

      - uses: actions/download-artifact@v3
        with:
          path: './public'
          name: ${{ github.sha }}

      - name: Set up Ruby environment
        uses: ./.github/actions/setup-ruby
        with:
          ruby-version: ${{ matrix.ruby-version}}
          additional-system-dependencies: ffmpeg imagemagick

      - name: Set up Javascript environment
        uses: ./.github/actions/setup-javascript

      - name: Load database schema
        run: './bin/rails db:create db:schema:load db:seed'

      - run: bin/rspec --tag search

      - name: Archive logs
        uses: actions/upload-artifact@v3
        if: failure()
        with:
          name: test-search-logs-${{ matrix.ruby-version }}
          path: log/

      - name: Archive test screenshots
        uses: actions/upload-artifact@v3
        if: failure()
        with:
          name: test-search-screenshots
          path: tmp/screenshots/