name: Coverage Check description: "Run FastDeploy Unit Tests and Coverage" on: workflow_call: inputs: DOCKER_IMAGE: description: "Build Images" required: true type: string default: "ccr-2vdh3abv-pub.cnc.bj.baidubce.com/paddlepaddle/paddleqa:cuda126-py310" FASTDEPLOY_ARCHIVE_URL: description: "URL of the compressed FastDeploy code archive." required: true type: string FASTDEPLOY_WHEEL_URL: description: "URL of the FastDeploy Wheel." required: true type: string CACHE_DIR: description: "Cache Dir Use" required: false type: string default: "" MODEL_CACHE_DIR: description: "Cache Dir Use" required: false type: string default: "" secrets: github-token: required: true jobs: check_cov_skip: uses: ./.github/workflows/check-bypass.yml secrets: github-token: ${{ secrets.github-token }} with: workflow-name: coverage run_tests_with_coverage: runs-on: [self-hosted, GPU-h1z1-2Cards] timeout-minutes: 90 needs: check_cov_skip if: needs.check_cov_skip.outputs.can-skip != 'true' outputs: diff_cov_file_url: ${{ steps.cov_upload.outputs.diff_cov_file_url }} unittest_failed_url: ${{ steps.cov_upload.outputs.unittest_failed_url }} diff_cov_result_json_url: ${{ steps.cov_upload.outputs.diff_cov_result_json_url }} steps: - name: Code Prepare shell: bash env: docker_image: ${{ inputs.DOCKER_IMAGE }} fd_archive_url: ${{ inputs.FASTDEPLOY_ARCHIVE_URL }} run: | set -x REPO="https://github.com/${{ github.repository }}.git" FULL_REPO="${{ github.repository }}" REPO_NAME="${FULL_REPO##*/}" BASE_BRANCH="${{ github.base_ref }}" docker pull ${docker_image} # Clean the repository directory before starting docker run --rm --net=host -v $(pwd):/workspace -w /workspace \ -e "REPO_NAME=${REPO_NAME}" \ ${docker_image} /bin/bash -c ' if [ -d ${REPO_NAME} ]; then echo "Directory ${REPO_NAME} exists, removing it..." rm -rf ${REPO_NAME}* fi ' wget -q ${fd_archive_url} tar -xf FastDeploy.tar.gz rm -rf FastDeploy.tar.gz cd FastDeploy git config --global user.name "FastDeployCI" git config --global user.email "fastdeploy_ci@example.com" git log -n 3 --oneline - name: Run FastDeploy Unit Tests and Coverage shell: bash env: docker_image: ${{ inputs.DOCKER_IMAGE }} fd_wheel_url: ${{ inputs.FASTDEPLOY_WHEEL_URL }} CACHE_DIR: ${{ inputs.CACHE_DIR }} BASE_REF: ${{ github.event.pull_request.base.ref }} MODEL_CACHE_DIR: ${{ inputs.MODEL_CACHE_DIR }} IS_PR: ${{ github.event_name == 'pull_request' }} run: | if [[ "$IS_PR" == "true" ]]; then echo "Running on PR" else echo "Not a PR" fi runner_name="${{ runner.name }}" CARD_ID=$(echo "${runner_name}" | awk -F'-' '{print $NF}') DEVICES=$(echo "$CARD_ID" | fold -w1 | paste -sd,) DEVICE_PORT=$(echo "$DEVICES" | cut -d',' -f1) FLASK_PORT=$((42068 + DEVICE_PORT * 100)) FD_API_PORT=$((42088 + DEVICE_PORT * 100)) FD_ENGINE_QUEUE_PORT=$((42058 + DEVICE_PORT * 100)) FD_METRICS_PORT=$((42078 + DEVICE_PORT * 100)) FD_CACHE_QUEUE_PORT=$((42098 + DEVICE_PORT * 100)) echo "Test ENV Parameter:" echo "=========================================================" echo "FLASK_PORT=${FLASK_PORT}" echo "FD_API_PORT=${FD_API_PORT}" echo "FD_ENGINE_QUEUE_PORT=${FD_ENGINE_QUEUE_PORT}" echo "FD_METRICS_PORT=${FD_METRICS_PORT}" echo "FD_CACHE_QUEUE_PORT=${FD_CACHE_QUEUE_PORT}" echo "DEVICES=${DEVICES}" echo "=========================================================" CACHE_DIR="${CACHE_DIR:-$(dirname "$(dirname "${{ github.workspace }}")")}" echo "CACHE_DIR is set to ${CACHE_DIR}" if [ ! -f "${CACHE_DIR}/gitconfig" ]; then touch "${CACHE_DIR}/gitconfig" fi PORTS=($FLASK_PORT $FD_API_PORT $FD_ENGINE_QUEUE_PORT $FD_METRICS_PORT $FD_CACHE_QUEUE_PORT) LOG_FILE="./port_cleanup_$(date +%Y%m%d_%H%M%S).log" echo "==== LOG_FILE is ${LOG_FILE} ====" echo "==== PORT CLEAN BEFORE TASK RUN ====" | tee -a $LOG_FILE for port in "${PORTS[@]}"; do PIDS=$(lsof -t -i :$port || true) if [ -n "$PIDS" ]; then echo "Port $port is occupied by PID(s): $PIDS" | tee -a $LOG_FILE echo "$PIDS" | xargs -r kill -9 echo "Port $port cleared" | tee -a $LOG_FILE else echo "Port $port is free" | tee -a $LOG_FILE fi done echo "==== PORT CLEAN COMPLETE ====" | tee -a $LOG_FILE echo "=========================================================" echo "Ensuring no stale container named ${runner_name} ..." if [ "$(docker ps -a -q -f name=${runner_name})" ]; then echo "Removing stale container: ${runner_name}" docker rm -f ${runner_name} || true fi docker run --rm --net=host \ --name ${runner_name} \ --cap-add=SYS_PTRACE --shm-size=64G \ -v $(pwd):/workspace -w /workspace \ -v "${CACHE_DIR}/gitconfig:/etc/gitconfig:ro" \ -v "${CACHE_DIR}/.cache:/root/.cache" \ -v "${CACHE_DIR}/ConfigDir:/root/.config" \ -v "${MODEL_CACHE_DIR}:/ModelData:ro" \ -e "MODEL_PATH=/ModelData" \ -e "FD_API_PORT=${FD_API_PORT}" \ -e "FD_ENGINE_QUEUE_PORT=${FD_ENGINE_QUEUE_PORT}" \ -e "FD_METRICS_PORT=${FD_METRICS_PORT}" \ -e "FLASK_PORT=${FLASK_PORT}" \ -e "FD_CACHE_QUEUE_PORT=${FD_CACHE_QUEUE_PORT}" \ -e TZ="Asia/Shanghai" \ -e "fd_wheel_url=${fd_wheel_url}" \ -e "BASE_REF=${BASE_REF}" \ -e "IS_PR=${IS_PR}" \ --gpus "\"device=${DEVICES}\"" ${docker_image} /bin/bash -c ' git config --global --add safe.directory /workspace/FastDeploy cd FastDeploy git diff origin/${BASE_REF}..HEAD --unified=0 > diff.txt # python -m pip install --pre paddlepaddle-gpu -i https://www.paddlepaddle.org.cn/packages/nightly/cu126/ python -m pip install paddlepaddle-gpu==3.3.0.dev20251012 -i https://www.paddlepaddle.org.cn/packages/nightly/cu126/ pip config set global.extra-index-url https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple python -m pip install -r scripts/unittest_requirement.txt python -m pip install ${fd_wheel_url} rm -rf fastdeploy # coverage subprocess use python -m pip install ${fd_wheel_url} --no-deps --target=/workspace/FastDeploy export PYTHONPATH=/workspace/FastDeploy/ if [ -d "tests/plugins" ]; then cd tests/plugins python setup.py install cd ../.. else echo "Warning: tests/plugins directory not found, skipping setup.py install" fi export COVERAGE_FILE=/workspace/FastDeploy/coveragedata/.coverage export COVERAGE_RCFILE=/workspace/FastDeploy/scripts/.coveragerc TEST_EXIT_CODE=0 bash scripts/coverage_run.sh || TEST_EXIT_CODE=8 echo "TEST_EXIT_CODE=${TEST_EXIT_CODE}" >> exit_code.env coverage combine coveragedata/ || echo "No data to combine" coverage report coverage xml -o python_coverage_all.xml COVERAGE_EXIT_CODE=0 if [[ "$IS_PR" == "true" ]]; then diff-cover python_coverage_all.xml --diff-file=diff.txt --fail-under=80 --json-report diff_coverage.json || COVERAGE_EXIT_CODE=9 python scripts/generate_diff_coverage_xml.py diff.txt python_coverage_all.xml else echo "Not a PR, skipping diff-cover" fi echo "COVERAGE_EXIT_CODE=${COVERAGE_EXIT_CODE}" >> exit_code.env ' if [ -f FastDeploy/exit_code.env ]; then cat FastDeploy/exit_code.env >> $GITHUB_ENV fi - name: Upload unit resule and diff coverage to bos id: cov_upload shell: bash run: | cd FastDeploy commit_id=${{ github.event.pull_request.head.sha }} pr_num=${{ github.event.pull_request.number }} target_path=paddle-github-action/PR/FastDeploy/${pr_num}/${commit_id}/SM${compile_arch//,/_} wget -q --no-proxy --no-check-certificate https://paddle-qa.bj.bcebos.com/CodeSync/develop/PaddlePaddle/PaddleTest/tools/bos_tools.py -O bos_tools.py push_file=$(realpath bos_tools.py) python -m pip install bce-python-sdk==0.9.29 diff_cov_file="diff_coverage.xml" if [ -f ${diff_cov_file} ];then python ${push_file} ${diff_cov_file} ${target_path}/CoverageData target_path_stripped="${target_path#paddle-github-action/}" DIFF_COV_FILE_URL=https://paddle-github-action.bj.bcebos.com/${target_path_stripped}/CoverageData/${diff_cov_file} echo "diff_cov_file_url=${DIFF_COV_FILE_URL}" >> $GITHUB_OUTPUT echo "diff_cov_file_url=${DIFF_COV_FILE_URL}" >> $GITHUB_ENV fi diff_cov_result_json="diff_coverage.json" if [ -f ${diff_cov_result_json} ];then python ${push_file} ${diff_cov_result_json} ${target_path}/CoverageData target_path_stripped="${target_path#paddle-github-action/}" DIFF_COV_JSON_URL=https://paddle-github-action.bj.bcebos.com/${target_path_stripped}/CoverageData/${diff_cov_result_json} echo "diff_cov_result_json_url=${DIFF_COV_JSON_URL}" >> $GITHUB_OUTPUT echo "diff_cov_result_json_url=${DIFF_COV_JSON_URL}" >> $GITHUB_ENV fi unittest_result="failed_tests.log" if [ -s ${unittest_result} ];then python ${push_file} ${unittest_result} ${target_path}/UnitTestResult target_path_stripped="${target_path#paddle-github-action/}" UNIT_TEST_RESULT_URL=https://paddle-github-action.bj.bcebos.com/${target_path_stripped}/UnitTestResult/${unittest_result} echo "unittest_failed_url=${UNIT_TEST_RESULT_URL}" >> $GITHUB_OUTPUT echo "unittest_failed_url=${UNIT_TEST_RESULT_URL}" >> $GITHUB_ENV fi - name: Check Unit Test Success shell: bash run: | cd FastDeploy if [ "$TEST_EXIT_CODE" -eq 8 ]; then filename=$(basename "$unittest_failed_url") if [ -z "${unittest_failed_url}" ]; then echo "No diff unit failed file URL provided." else rm -rf "${filename}" wget -O ${filename} ${unittest_failed_url} || echo "Download unittest file failed, but continuing..." fi echo "Unit tests failed (exit code 8)" if [ -f "${filename}" ];then echo "Failed test cases:" cat "${filename}" fi exit "$TEST_EXIT_CODE" fi echo "All tests passed" - name: Verify Code Coverage Threshold (80%) if: ${{ github.event_name == 'pull_request' }} shell: bash run: | cd FastDeploy if [ "$COVERAGE_EXIT_CODE" -eq 9 ]; then echo "Coverage generation failed (exit code 9)" filename=$(basename "$diff_cov_result_json_url") if [ -z "${diff_cov_result_json_url}" ]; then echo "No diff cov result file URL provided." else rm -rf "${filename}" wget -O ${filename} ${diff_cov_result_json_url} || echo "Download cov json file failed, but continuing..." fi if [ -f "${filename}" ];then echo "Failed test cases:" if command -v jq >/dev/null 2>&1; then jq . "${filename}" else cat "${filename}" fi fi exit "$COVERAGE_EXIT_CODE" fi echo "coverage passed" exit 0 diff_coverage_report: needs: run_tests_with_coverage if: always() runs-on: ubuntu-latest env: fd_archive_url: ${{ inputs.FASTDEPLOY_ARCHIVE_URL }} steps: - name: coverage diff file download shell: bash env: diff_cov_file_url: ${{ needs.run_tests_with_coverage.outputs.diff_cov_file_url }} run: | wget ${fd_archive_url} tar -xf FastDeploy.tar.gz cd FastDeploy if [ -z "${diff_cov_file_url}" ]; then echo "No diff coverage file URL provided." exit 0 fi wget "${diff_cov_file_url}" -O ./diff_coverage.xml || echo "Download cov file failed, but continuing..." - name: Upload diff coverage report if: ${{ needs.run_tests_with_coverage.outputs.diff_cov_file_url != null && needs.run_tests_with_coverage.outputs.diff_cov_file_url != '' }} uses: codecov/codecov-action@v5 with: files: ./FastDeploy/diff_coverage.xml name: python diff coverage verbose: true disable_search: true commit_parent: false flags: diff