name: Run Integration Tests
concurrency:
  group: Run-Integration-Tests-${{ github.workflow }}-${{ github.head_ref || github.event.workflow_run.head_branch || github.run_id }}
  cancel-in-progress: true

on:
  merge_group:
  pull_request:
    branches:
      - main
      - 'release/**'

env:
  OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}

jobs:
  integration-tests:
    # See https://runs-on.com/runners/linux/
    runs-on: [runs-on,runner=8cpu-linux-x64,ram=32,"run-id=${{ github.run_id }}"]
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_TOKEN }}

      # NOTE: we don't need to build the Web Docker image since it's not used
      # during the IT for now. We have a separate action to verify it builds 
      # succesfully
      - name: Pull Web Docker image
        run: |
          docker pull danswer/danswer-web-server:latest
          docker tag danswer/danswer-web-server:latest danswer/danswer-web-server:it

      - name: Build Backend Docker image
        uses: ./.github/actions/custom-build-and-push
        with:
          context: ./backend
          file: ./backend/Dockerfile
          platforms: linux/amd64
          tags: danswer/danswer-backend:it
          cache-from: type=registry,ref=danswer/danswer-backend:it
          cache-to: |
            type=registry,ref=danswer/danswer-backend:it,mode=max
            type=inline

      - name: Build Model Server Docker image
        uses: ./.github/actions/custom-build-and-push
        with:
          context: ./backend
          file: ./backend/Dockerfile.model_server
          platforms: linux/amd64
          tags: danswer/danswer-model-server:it
          cache-from: type=registry,ref=danswer/danswer-model-server:it
          cache-to: |
            type=registry,ref=danswer/danswer-model-server:it,mode=max
            type=inline

      - name: Build integration test Docker image
        uses: ./.github/actions/custom-build-and-push
        with:
          context: ./backend
          file: ./backend/tests/integration/Dockerfile
          platforms: linux/amd64
          tags: danswer/integration-test-runner:it
          cache-from: type=registry,ref=danswer/integration-test-runner:it
          cache-to: |
            type=registry,ref=danswer/integration-test-runner:it,mode=max
            type=inline

      - name: Start Docker containers
        run: |
          cd deployment/docker_compose
          ENABLE_PAID_ENTERPRISE_EDITION_FEATURES=true \
          AUTH_TYPE=basic \
          REQUIRE_EMAIL_VERIFICATION=false \
          DISABLE_TELEMETRY=true \
          IMAGE_TAG=it \
          docker compose -f docker-compose.dev.yml -p danswer-stack up -d
        id: start_docker

      - name: Wait for service to be ready
        run: |
          echo "Starting wait-for-service script..."
          
          docker logs -f danswer-stack-api_server-1 &

          start_time=$(date +%s)
          timeout=300  # 5 minutes in seconds
          
          while true; do
            current_time=$(date +%s)
            elapsed_time=$((current_time - start_time))
            
            if [ $elapsed_time -ge $timeout ]; then
              echo "Timeout reached. Service did not become ready in 5 minutes."
              exit 1
            fi
            
            # Use curl with error handling to ignore specific exit code 56
            response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/health || echo "curl_error")
            
            if [ "$response" = "200" ]; then
              echo "Service is ready!"
              break
            elif [ "$response" = "curl_error" ]; then
              echo "Curl encountered an error, possibly exit code 56. Continuing to retry..."
            else
              echo "Service not ready yet (HTTP status $response). Retrying in 5 seconds..."
            fi
            
            sleep 5
          done
          echo "Finished waiting for service."

      - name: Run integration tests
        run: |
          echo "Running integration tests..."
          docker run --rm --network danswer-stack_default \
            -e POSTGRES_HOST=relational_db \
            -e POSTGRES_USER=postgres \
            -e POSTGRES_PASSWORD=password \
            -e POSTGRES_DB=postgres \
            -e VESPA_HOST=index \
            -e REDIS_HOST=cache \
            -e API_SERVER_HOST=api_server \
            -e OPENAI_API_KEY=${OPENAI_API_KEY} \
            danswer/integration-test-runner:it
        continue-on-error: true
        id: run_tests

      - name: Check test results
        run: |
          if [ ${{ steps.run_tests.outcome }} == 'failure' ]; then
            echo "Integration tests failed. Exiting with error."
            exit 1
          else
            echo "All integration tests passed successfully."
          fi

      - name: Save Docker logs
        if: success() || failure()
        run: |
          cd deployment/docker_compose
          docker compose -f docker-compose.dev.yml -p danswer-stack logs > docker-compose.log
          mv docker-compose.log ${{ github.workspace }}/docker-compose.log
      
      - name: Upload logs
        if: success() || failure()
        uses: actions/upload-artifact@v3
        with:
          name: docker-logs
          path: ${{ github.workspace }}/docker-compose.log

      - name: Stop Docker containers
        run: |
          cd deployment/docker_compose
          docker compose -f docker-compose.dev.yml -p danswer-stack down -v
