name: build-and-test description: Build YDB and run Tests inputs: log_suffix: required: true type: string test_label_regexp: required: false type: string aws_key_id: required: true type: string aws_key_value: required: true type: string testman_token: required: false type: string testman_url: required: false type: string testman_project_id: required: false type: string aws_bucket: required: true type: string aws_endpoint: required: true type: string run_unit_tests: required: true type: string run_functional_tests: required: true type: string runs: using: "composite" steps: - name: Init id: init shell: bash run: | rm -rf artifacts tmp test_reports mkdir -p artifacts tmp/pytest test_reports/pytest echo "WORKDIR=$(pwd)" >> $GITHUB_ENV echo "TESTREPDIR=$(pwd)/test_reports" >> $GITHUB_ENV echo "TMPDIR=$(pwd)/tmp" >> $GITHUB_ENV echo "PYTESTREPDIR=$(pwd)/test_reports/pytest/" >> $GITHUB_ENV echo "TESTMO_TOKEN=${{inputs.testman_token}}" >> $GITHUB_ENV echo "TESTMO_URL=${{inputs.testman_url}}" >> $GITHUB_ENV echo "ARTIFACTS_DIR=$(pwd)/artifacts" >> $GITHUB_ENV echo "SUMMARY_LINKS=$(mktemp)" >> $GITHUB_ENV echo "logfilename=${{inputs.log_suffix}}-ctest-stdout.gz" >> $GITHUB_OUTPUT echo "testfilterfile=$(pwd)/.github/config/muted_test.txt" >> $GITHUB_OUTPUT echo "testshardfilterfile=$(pwd)/.github/config/muted_shard.txt" >> $GITHUB_OUTPUT echo "functestfilterfile=$(pwd)/.github/config/muted_functest.txt" >> $GITHUB_OUTPUT echo "pytest-logfilename=${{inputs.log_suffix}}-pytest-stdout.log" >> $GITHUB_OUTPUT echo "PORT_SYNC_PATH=$(mktemp -d -p $(pwd)/tmp port-sync-XXXXXX)" >> $GITHUB_ENV - name: configure s3cmd shell: bash run: | cat < $TMPDIR/s3cfg [default] access_key = ${aws_key_id} secret_key = ${aws_secret_access_key} bucket_location = ru-central1 host_base = storage.yandexcloud.net host_bucket = %(bucket)s.storage.yandexcloud.net EOF echo "S3CMD_CONFIG=$TMPDIR/s3cfg" >> $GITHUB_ENV echo "S3_BUCKET_PATH=s3://${{ inputs.aws_bucket }}/${{ github.repository }}/${{github.workflow}}/${{ github.run_id }}/${{inputs.log_suffix}}/" >> $GITHUB_ENV echo "S3_URL_PREFIX=${{inputs.aws_endpoint}}/${{inputs.aws_bucket}}/${{ github.repository }}/${{github.workflow}}/${{github.run_id}}/${{inputs.log_suffix}}" >> $GITHUB_ENV env: aws_key_id: ${{inputs.AWS_KEY_ID }} aws_secret_access_key: ${{inputs.AWS_KEY_VALUE}} - name: Install Node required for Testmo CLI uses: actions/setup-node@v3 with: node-version: 19 - name: Install Testmo CLI shell: bash run: npm install -g @testmo/testmo-cli - name: Test history run create id: th if: inputs.testman_token shell: bash env: PR_NUMBER: ${{ github.event.number }} run: | RUN_URL="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" BRANCH_TAG="$GITHUB_REF_NAME" ARCH="${{ runner.arch == 'X64' && 'x86-64' || runner.arch == 'ARM64' && 'arm64' || 'unknown' }}" LOG_SUFFIX="${{ inputs.log_suffix }}" TESTMO_SOURCE="cmake-${ARCH}" if [ ! -z "${LOG_SUFFIX}" ]; then TESTMO_SOURCE="${TESTMO_SOURCE}-${LOG_SUFFIX/_/-}" fi case $GITHUB_EVENT_NAME in workflow_dispatch) TESTMO_RUN_NAME="${{ github.run_id }} manual" EXTRA_TAG="manual" ;; pull_request | pull_request_target) TESTMO_RUN_NAME="${{ github.run_id }} PR #${PR_NUMBER}" EXTRA_TAG="pr" BRANCH_TAG="" ;; schedule) TESTMO_RUN_NAME="${{ github.run_id }} schedule" EXTRA_TAG="schedule" ;; *) TESTMO_RUN_NAME="${{ github.run_id }}" EXTRA_TAG="" ;; esac testmo automation:resources:add-link --name build --url $RUN_URL --resources testmo.json testmo automation:resources:add-field --name git-sha --type string --value ${GITHUB_SHA:0:7} --resources testmo.json RUN_ID=$( testmo automation:run:create --instance "$TESTMO_URL" --project-id ${{inputs.testman_project_id}} \ --name "$TESTMO_RUN_NAME" --source "$TESTMO_SOURCE" --resources testmo.json \ --tags "$BRANCH_TAG" --tags "$EXTRA_TAG" ) echo "runid=${RUN_ID}" >> $GITHUB_OUTPUT echo "TEST_HISTORY_URL=${TESTMO_URL}/automation/runs/view/${RUN_ID}" >> $GITHUB_ENV - name: Print test history link shell: bash run: | echo "10 [Test history](${TEST_HISTORY_URL})" >> $SUMMARY_LINKS - name: set environment variables required by some tests shell: bash run: | echo "PSQL_BINARY=/usr/bin/psql" >> $GITHUB_ENV - name: Run unit tests id: ctest if: inputs.run_unit_tests == 'true' shell: bash run: | cd $WORKDIR/../build/ydb echo "20 [Unittest log]($S3_URL_PREFIX/${{steps.init.outputs.logfilename}})" >> $SUMMARY_LINKS # Sed removes coloring from the output GTEST_OUTPUT="xml:$TESTREPDIR/unittests/" Y_UNITTEST_OUTPUT="xml:$TESTREPDIR/unittests/" \ ctest -j28 --timeout 1200 --force-new-ctest-process --output-on-failure \ --output-junit $TESTREPDIR/suites/ctest_report.xml \ -L '${{inputs.test_label_regexp}}' -E "${CTEST_SKIP_SHARDS:-}" | \ sed -u -e 's/\x1b\[[0-9;]*m//g' | \ tee >(gzip --stdout > $ARTIFACTS_DIR/${{steps.init.outputs.logfilename}}) | \ grep --line-buffered -E '(Test\s*#.*\*\*\*|\[FAIL\])|.*tests passed,.*tests failed out of' | \ tee $WORKDIR/short.log || ( RC=$? if [ $RC == 8 ]; then echo "ctest returned TEST_ERRORS, recovering.." else exit $RC fi ) - name: archive unitest reports (orig) if: inputs.run_unit_tests == 'true' shell: bash run: | tar -C $TESTREPDIR/ -czf $ARTIFACTS_DIR/xml_orig.tar.gz . - name: postprocess xml reports if: inputs.run_unit_tests == 'true' shell: bash run: | echo "::group::extract-logs" mkdir $ARTIFACTS_DIR/logs/ .github/scripts/tests/attach-logs.py \ --url-prefix $S3_URL_PREFIX/logs/ \ --ctest-report $TESTREPDIR/suites/ctest_report.xml \ --junit-reports-path $TESTREPDIR/unittests/ \ --decompress \ $ARTIFACTS_DIR/${{steps.init.outputs.logfilename}} \ $ARTIFACTS_DIR/logs/ echo "::endgroup::" echo "::group::junit-postprocess" .github/scripts/tests/junit-postprocess.py \ --filter-file ${{steps.init.outputs.testfilterfile}} \ $TESTREPDIR/unittests/ echo "::endgroup::" echo "::group::ctest-postprocess" .github/scripts/tests/ctest-postprocess.py \ --filter-file ${{steps.init.outputs.testshardfilterfile}} \ --decompress \ $ARTIFACTS_DIR/${{steps.init.outputs.logfilename}} \ $TESTREPDIR/suites/ctest_report.xml tar -C $TESTREPDIR/ -czf $ARTIFACTS_DIR/reports.tar.gz . echo "90 [XML reports archive]($S3_URL_PREFIX/reports.tar.gz)" >> $SUMMARY_LINKS echo "::endgroup::" - name: sync test results to s3 if: always() && inputs.run_unit_tests == 'true' shell: bash run: | echo "::group::s3-sync" s3cmd sync -P --no-progress --stats --no-check-md5 -P $ARTIFACTS_DIR/ $S3_BUCKET_PATH echo "::endgroup::" - name: Unit test history upload results if: always() && inputs.run_unit_tests == 'true' && inputs.testman_token shell: bash run: | testmo automation:run:submit-thread \ --instance "$TESTMO_URL" --run-id ${{steps.th.outputs.runid}} \ --results "$TESTREPDIR/unittests/*.xml" testmo automation:run:submit-thread \ --exec-suppress \ --instance "$TESTMO_URL" --run-id ${{steps.th.outputs.runid}} \ --results "$TESTREPDIR/suites/*.xml" \ -- cat $WORKDIR/short.log - name: Run functional tests if: inputs.run_functional_tests == 'true' && (success() || failure()) shell: bash run: | export source_root=$WORKDIR export build_root=$WORKDIR/../build/ echo "30 [Functional test log]($S3_URL_PREFIX/${{steps.init.outputs.pytest-logfilename}})" >> $SUMMARY_LINKS source $WORKDIR/ydb/tests/oss/launch/prepare.sh rm -rf $ARTIFACTS_DIR/pytest/ mkdir $ARTIFACTS_DIR/pytest/ cd $WORKDIR/ydb/tests/functional/ pytest \ -p xdist -n 24 --dist worksteal \ --timeout_method signal \ -o junit_logging=log -o junit_log_passing_tests=False --junit-xml=$PYTESTREPDIR/pytest.xml \ -ra --tb=no --show-capture=no \ --github-repo $GITHUB_REPOSITORY --github-ref $GITHUB_SHA \ --source-root $source_root \ --build-root $build_root \ --output-dir $TMPDIR/pytest/ \ . | tee $ARTIFACTS_DIR/${{steps.init.outputs.pytest-logfilename}} || { RC=$? if [ $RC == 1 ]; then echo "pytest: tests were collected and run but some of the tests failed" else exit $RC fi; } # --artifacts-dir $ARTIFACTS_DIR/pytest/ \ # --artifacts-url $S3_URL_PREFIX/pytest/ \ - name: postprocess functional test reports if: always() && inputs.run_functional_tests == 'true' shell: bash run: | echo "::group::junit-postprocess" # append orig pytest reports if [ -f "$ARTIFACTS_DIR/xml_orig.tar.gz" ]; then echo "add pytest to xml_orig.tar.gz" gzip -d $ARTIFACTS_DIR/xml_orig.tar.gz tar -C $TESTREPDIR/ -rvf $ARTIFACTS_DIR/xml_orig.tar pytest gzip -v $ARTIFACTS_DIR/xml_orig.tar fi .github/scripts/tests/pytest-postprocess.py \ --filter-file ${{ steps.init.outputs.functestfilterfile }} \ $PYTESTREPDIR/ # make archive again with pytest reports tar -C $TESTREPDIR/ -czf $ARTIFACTS_DIR/reports.tar.gz . ls -la $ARTIFACTS_DIR/reports.tar.gz echo "::endgroup::" - name: Functional tests history upload results if: always() && inputs.run_functional_tests == 'true' && inputs.testman_token shell: bash run: | testmo automation:run:submit-thread \ --instance "$TESTMO_URL" --run-id ${{steps.th.outputs.runid}} \ --results "$PYTESTREPDIR/*.xml" \ -- cat $ARTIFACTS_DIR/${{steps.init.outputs.pytest-logfilename}} - name: Test history run complete if: always() && inputs.testman_token shell: bash run: | testmo automation:run:complete --instance "$TESTMO_URL" --run-id ${{steps.th.outputs.runid}} - name: write tests summary if: always() shell: bash env: GITHUB_TOKEN: ${{ github.token }} run: | cat $SUMMARY_LINKS | python3 -c 'import sys; print(" | ".join([v for _, v in sorted([l.strip().split(" ", 1) for l in sys.stdin], key=lambda a: (int(a[0]), a))]))' >> $GITHUB_STEP_SUMMARY mkdir $ARTIFACTS_DIR/summary/ .github/scripts/tests/generate-summary.py \ --summary-out-path $ARTIFACTS_DIR/summary/ \ --summary-url-prefix $S3_URL_PREFIX/summary/ \ --test-history-url $TEST_HISTORY_URL \ "Unittests" unittest.html $TESTREPDIR/unittests \ "Unittest binary runs" ctest.html $TESTREPDIR/suites \ "Functional tests" functional.html $PYTESTREPDIR - name: sync test results to s3 if: always() shell: bash run: | echo "::group::s3-sync" s3cmd sync -P --no-progress --stats --no-check-md5 -P $ARTIFACTS_DIR/ $S3_BUCKET_PATH echo "::endgroup::" - name: finish shell: bash run: | .github/scripts/tests/fail-checker.py $TESTREPDIR/unittests/ $TESTREPDIR/suites/ $PYTESTREPDIR/