RocketChat/Rocket.Chat

View on GitHub
.github/workflows/ci-test-e2e.yml

Summary

Maintainability
Test Coverage
name: Tests E2E

on:
  workflow_call:
    inputs:
      node-version:
        required: true
        type: string
      lowercase-repo:
        required: true
        type: string
      rc-dockerfile:
        required: true
        type: string
      rc-docker-tag:
        required: true
        type: string
      rc-dockerfile-alpine:
        required: true
        type: string
      rc-docker-tag-alpine:
        required: true
        type: string
      gh-docker-tag:
        required: true
        type: string
      enterprise-license:
        type: string
      transporter:
        type: string
      mongodb-version:
        default: "['4.4', '6.0']"
        required: false
        type: string
      release:
        required: true
        type: string
      shard:
        default: '[1]'
        required: false
        type: string
      total-shard:
        default: 1
        required: false
        type: number
      retries:
        default: 0
        required: false
        type: number
      type:
        required: true
        type: string
      db-watcher-disabled:
        default: 'false'
        required: false
        type: string
    secrets:
      CR_USER:
        required: true
      CR_PAT:
        required: true
      QASE_API_TOKEN:
        required: false
      REPORTER_ROCKETCHAT_URL:
        required: false
      REPORTER_ROCKETCHAT_API_KEY:
        required: false
      CODECOV_TOKEN:
        required: false
      REPORTER_JIRA_ROCKETCHAT_API_KEY:
        required: false

env:
  MONGO_URL: mongodb://localhost:27017/rocketchat?replicaSet=rs0&directConnection=true
  TOOL_NODE_FLAGS: ${{ vars.TOOL_NODE_FLAGS }}
  LOWERCASE_REPOSITORY: ${{ inputs.lowercase-repo }}
  DOCKER_TAG: ${{ inputs.gh-docker-tag }}

jobs:
  test:
    runs-on: ubuntu-20.04
    env:
      RC_DOCKERFILE: ${{ matrix.mongodb-version == '6.0' && inputs.rc-dockerfile-alpine || inputs.rc-dockerfile }}
      RC_DOCKER_TAG: ${{ matrix.mongodb-version == '6.0' && inputs.rc-docker-tag-alpine || inputs.rc-docker-tag }}

    strategy:
      fail-fast: false
      matrix:
        mongodb-version: ${{ fromJSON(inputs.mongodb-version) }}
        shard: ${{ fromJSON(inputs.shard) }}

    name: MongoDB ${{ matrix.mongodb-version }}${{ inputs.db-watcher-disabled == 'true' && ' [no watchers]' || '' }} (${{ matrix.shard }}/${{ inputs.total-shard }})${{ matrix.mongodb-version == '6.0' && ' - Alpine' || '' }}

    steps:
      - name: Collect Workflow Telemetry
        uses: catchpoint/workflow-telemetry-action@v2
        with:
          theme: dark
          job_summary: true
          comment_on_pr: false

      - name: Setup kernel limits
        run: |
          sudo sysctl -w net.ipv4.ip_local_port_range="500   65535"
          sudo sysctl -w net.ipv4.tcp_mem="383865   511820   2303190"

          echo fs.file-max=20000500 | sudo tee -a /etc/sysctl.conf
          echo fs.nr_open=20000500 | sudo tee -a /etc/sysctl.conf
          sudo sysctl -p

      - name: Login to GitHub Container Registry
        if: (github.event.pull_request.head.repo.full_name == github.repository || github.event_name == 'release' || github.ref == 'refs/heads/develop')
        uses: docker/login-action@v2
        with:
          registry: ghcr.io
          username: ${{ secrets.CR_USER }}
          password: ${{ secrets.CR_PAT }}

      - name: Launch MongoDB
        uses: supercharge/mongodb-github-action@v1.10.0
        with:
          mongodb-version: ${{ matrix.mongodb-version }}
          mongodb-replica-set: rs0

      - uses: actions/checkout@v4

      - name: Setup NodeJS
        uses: ./.github/actions/setup-node
        with:
          node-version: ${{ inputs.node-version }}
          cache-modules: true
          install: true
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

      - uses: rharkor/caching-for-turbo@v1.5

      - run: yarn build
      # if we are testing a PR from a fork, we need to build the docker image at this point
      - uses: ./.github/actions/build-docker
        if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository
        with:
          CR_USER: ${{ secrets.CR_USER }}
          CR_PAT: ${{ secrets.CR_PAT }}
          node-version: ${{ inputs.node-version }}
          # we already called the turbo cache at this point, so it should be false
          turbo-cache: false
          # the same reason we need to rebuild the docker image at this point is the reason we dont want to publish it
          publish-image: false
          setup: false
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

      - name: Start httpbin container and wait for it to be ready
        if: inputs.type == 'api'
        run: |
          docker run -d -p 10000:80 --name httpbin-container kennethreitz/httpbin
          i=0
          while [ $i -lt 10 ]; do
            if curl -s -o /dev/null http://localhost:10000; then
              echo "httpbin is running"
              break
            fi
            i=$((i + 1))
            sleep 5
          done
          if [ $i -eq 10 ]; then
            echo "Failed to verify httpbin is running"
            exit 1
          fi

      - name: Prepare code coverage directory
        if: inputs.release == 'ee'
        run: |
          mkdir -p /tmp/coverage
          chmod 777 /tmp/coverage

      - name: Start containers for CE
        if: inputs.release == 'ce'
        env:
          MONGO_URL: 'mongodb://host.docker.internal:27017/rocketchat?replicaSet=rs0&directConnection=true'
        run: |
          # when we are testing CE, we only need to start the rocketchat container
          docker compose -f docker-compose-ci.yml up -d rocketchat

      - name: Start containers for EE
        if: inputs.release == 'ee'
        env:
          MONGO_URL: 'mongodb://host.docker.internal:27017/rocketchat?replicaSet=rs0&directConnection=true'
          ENTERPRISE_LICENSE: ${{ inputs.enterprise-license }}
          TRANSPORTER: ${{ inputs.transporter }}
          COVERAGE_DIR: '/tmp/coverage'
          COVERAGE_REPORTER: 'lcov'
          DISABLE_DB_WATCHERS: ${{ inputs.db-watcher-disabled }}
        run: |
          docker compose -f docker-compose-ci.yml up -d

      - name: Cache Playwright binaries
        if: inputs.type == 'ui'
        uses: actions/cache@v3
        id: cache-playwright
        with:
          path: |
            ~/.cache/ms-playwright
          # This is the version of Playwright that we are using, if you are willing to upgrade, you should update this.
          key: playwright-1.40.1

      - name: Install Playwright
        if: inputs.type == 'ui' && steps.cache-playwright.outputs.cache-hit != 'true'
        working-directory: ./apps/meteor
        run: npx playwright install --with-deps

      - name: Wait for Rocket.Chat to start up
        uses: cygnetdigital/wait_for_response@v2.0.0
        with:
          url: 'http://localhost:3000/health'
          responseCode: '200'
          timeout: 60000
          interval: 1000

      - name: Wait services to start up
        if: inputs.release == 'ee'
        run: |
          docker ps

          until echo "$(docker compose -f docker-compose-ci.yml logs ddp-streamer-service)" | grep -q "NetworkBroker started successfully"; do
            echo "Waiting 'ddp-streamer' to start up"
            ((c++)) && ((c==10)) && docker compose -f docker-compose-ci.yml logs ddp-streamer-service && exit 1
            sleep 10
          done;

      - name: Remove unused Docker images
        run: docker system prune -af
      - name: E2E Test API
        if: inputs.type == 'api'
        working-directory: ./apps/meteor
        env:
          WEBHOOK_TEST_URL: 'http://host.docker.internal:10000'
          IS_EE: ${{ inputs.release == 'ee' && 'true' || '' }}
          COVERAGE_DIR: '/tmp/coverage'
          COVERAGE_REPORTER: 'lcovonly'
        run: |
          for i in $(seq 1 2); do
            npm run testapi && s=0 && break || s=$?

            docker compose -f ../../docker-compose-ci.yml logs --tail=100

            docker compose -f ../../docker-compose-ci.yml stop

            docker exec mongodb bash -c 'if command -v mongosh ; then mongosh --eval "use rocketchat" --eval "db.dropDatabase()" rocketchat; else mongo rocketchat --eval "db.dropDatabase()"; fi'

            NOW=$(date "+%Y-%m-%dT%H:%M:%S.000Z")

            docker compose -f ../../docker-compose-ci.yml restart

            until echo "$(docker compose -f ../../docker-compose-ci.yml logs rocketchat --since $NOW)" | grep -q "SERVER RUNNING"; do
              echo "Waiting Rocket.Chat to start up"
              ((c++)) && ((c==10)) && exit 1
              sleep 10
            done;
          done;
          docker compose -f ../../docker-compose-ci.yml stop

          ls -l $COVERAGE_DIR
          exit $s

      - name: E2E Test UI (${{ matrix.shard }}/${{ inputs.total-shard }})
        if: inputs.type == 'ui'
        env:
          E2E_COVERAGE: ${{ inputs.release == 'ee' && 'true' || '' }}
          IS_EE: ${{ inputs.release == 'ee' && 'true' || '' }}
          REPORTER_ROCKETCHAT_API_KEY: ${{ secrets.REPORTER_ROCKETCHAT_API_KEY }}
          REPORTER_ROCKETCHAT_URL: ${{ secrets.REPORTER_ROCKETCHAT_URL }}
          REPORTER_JIRA_ROCKETCHAT_API_KEY: ${{ secrets.REPORTER_JIRA_ROCKETCHAT_API_KEY }}
          REPORTER_ROCKETCHAT_REPORT: ${{ github.event.pull_request.draft != 'true' && 'true' || '' }}
          REPORTER_ROCKETCHAT_RUN: ${{ github.run_number }}
          REPORTER_ROCKETCHAT_BRANCH: ${{ github.ref }}
          REPORTER_ROCKETCHAT_DRAFT: ${{ github.event.pull_request.draft }}
          REPORTER_ROCKETCHAT_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
          REPORTER_ROCKETCHAT_AUTHOR: ${{ github.event.pull_request.user.login }}
          REPORTER_ROCKETCHAT_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
          REPORTER_ROCKETCHAT_PR: ${{ github.event.pull_request.number }}
          QASE_API_TOKEN: ${{ secrets.QASE_API_TOKEN }}
          QASE_REPORT: ${{ github.ref == 'refs/heads/develop' && 'true' || '' }}
          CI: true
          PLAYWRIGHT_RETRIES: ${{ inputs.retries }}
        working-directory: ./apps/meteor
        run: |
          yarn prepare
          yarn test:e2e --shard=${{ matrix.shard }}/${{ inputs.total-shard }}

      - name: Store playwright test trace
        if: inputs.type == 'ui' && always()
        uses: actions/upload-artifact@v4
        with:
          name: playwright-test-trace-${{ inputs.release }}-${{ matrix.mongodb-version }}-${{ matrix.shard }}
          path: ./apps/meteor/tests/e2e/.playwright*
          include-hidden-files: true

      - name: Show server logs if E2E test failed
        if: failure()
        run: docker compose -f docker-compose-ci.yml logs rocketchat

      - name: Extract e2e:ee:coverage
        if: inputs.type == 'ui' && inputs.release == 'ee'
        working-directory: ./apps/meteor
        run: yarn test:e2e:nyc

      - uses: codecov/codecov-action@v3
        if: inputs.type == 'ui' && inputs.release == 'ee'
        with:
          directory: ./apps/meteor
          flags: e2e
          verbose: true
          token: ${{ secrets.CODECOV_TOKEN }}

      - uses: codecov/codecov-action@v3
        if: inputs.type == 'api' && inputs.release == 'ee'
        with:
          directory: /tmp/coverage
          working-directory: .
          flags: e2e-api
          verbose: true
          token: ${{ secrets.CODECOV_TOKEN }}

      - name: Store e2e-api-ee-coverage
        if: inputs.type == 'api' && inputs.release == 'ee'
        uses: actions/upload-artifact@v4
        with:
          name: e2e-api-ee-coverage-${{ matrix.mongodb-version }}-${{ matrix.shard }}
          path: /tmp/coverage
          include-hidden-files: true

      - name: Store e2e-ee-coverage
        if: inputs.type == 'ui' && inputs.release == 'ee'
        uses: actions/upload-artifact@v4
        with:
          name: e2e-ee-coverage-${{ matrix.mongodb-version }}-${{ matrix.shard }}
          path: ./apps/meteor/coverage*
          include-hidden-files: true