Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ci(workflows): Add code coverage reporting for v2 #6884

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 213 additions & 8 deletions .github/workflows/cypress-tests-runner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ jobs:
run: |
LOCAL_ADMIN_API_KEY=$(yq '.secrets.admin_api_key' ${TOML_PATH})
echo "CYPRESS_ADMINAPIKEY=${LOCAL_ADMIN_API_KEY}" >> $GITHUB_ENV

- name: Install mold linker
if: ${{ runner.os == 'Linux' && env.RUN_TESTS == 'true' }}
uses: rui314/setup-mold@v1
Expand All @@ -170,13 +170,6 @@ jobs:
tool: sccache
checksum: true

- name: Install cargo-nextest
if: ${{ env.RUN_TESTS == 'true' }}
uses: taiki-e/[email protected]
with:
tool: cargo-nextest
checksum: true

- name: Install Diesel CLI
if: ${{ env.RUN_TESTS == 'true' }}
uses: baptiste0928/[email protected]
Expand Down Expand Up @@ -261,3 +254,215 @@ jobs:
path: |
cypress-tests/cypress/reports/
retention-days: 1

runner_v2:
name: Run Cypress tests on v2 and generate coverage report
runs-on: ubuntu-latest
env:
CODECOV_FILE: "lcov.info"

services:
redis:
image: "public.ecr.aws/docker/library/redis:alpine"
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379
postgres:
image: "public.ecr.aws/docker/library/postgres:alpine"
env:
POSTGRES_USER: db_user
POSTGRES_PASSWORD: db_pass
POSTGRES_DB: hyperswitch_db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

steps:
- name: Skip tests for PRs from forks
shell: bash
if: ${{ env.RUN_TESTS == 'false' }}
run: echo 'Skipping tests for PRs from forks'

- name: Checkout repository
if: ${{ env.RUN_TESTS == 'true' }}
uses: actions/checkout@v4

- name: Download Encrypted TOML from S3 and Decrypt
if: ${{ env.RUN_TESTS == 'true' }}
env:
AWS_ACCESS_KEY_ID: ${{ secrets.CONNECTOR_CREDS_AWS_ACCESS_KEY_ID }}
AWS_REGION: ${{ secrets.CONNECTOR_CREDS_AWS_REGION }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.CONNECTOR_CREDS_AWS_SECRET_ACCESS_KEY }}
CONNECTOR_AUTH_PASSPHRASE: ${{ secrets.CONNECTOR_AUTH_PASSPHRASE }}
CONNECTOR_CREDS_S3_BUCKET_URI: ${{ secrets.CONNECTOR_CREDS_S3_BUCKET_URI}}
DESTINATION_FILE_NAME: "creds.json.gpg"
S3_SOURCE_FILE_NAME: "aa328308-b34e-41b7-a590-4fe45cfe7991.json.gpg"
shell: bash
run: |
mkdir -p ".github/secrets" ".github/test"

aws s3 cp "${CONNECTOR_CREDS_S3_BUCKET_URI}/${S3_SOURCE_FILE_NAME}" ".github/secrets/${DESTINATION_FILE_NAME}"
gpg --quiet --batch --yes --decrypt --passphrase="${CONNECTOR_AUTH_PASSPHRASE}" --output ".github/test/creds.json" ".github/secrets/${DESTINATION_FILE_NAME}"

- name: Set paths in env
if: ${{ env.RUN_TESTS == 'true' }}
shell: bash
run: |
echo "CYPRESS_CONNECTOR_AUTH_FILE_PATH=${{ github.workspace }}/.github/test/creds.json" >> $GITHUB_ENV

- name: Fetch keys
if: ${{ env.RUN_TESTS == 'true' }}
env:
TOML_PATH: "./config/development.toml"
run: |
LOCAL_ADMIN_API_KEY=$(yq '.secrets.admin_api_key' ${TOML_PATH})
echo "CYPRESS_ADMINAPIKEY=${LOCAL_ADMIN_API_KEY}" >> $GITHUB_ENV

- name: Install mold linker
if: ${{ runner.os == 'Linux' && env.RUN_TESTS == 'true' }}
uses: rui314/setup-mold@v1
with:
make-default: true

- name: Install Rust
if: ${{ env.RUN_TESTS == 'true' }}
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable 2 weeks ago
components: llvm-tools-preview

- name: Install sccache
if: ${{ env.RUN_TESTS == 'true' }}
uses: taiki-e/[email protected]
with:
tool: sccache
checksum: true

- name: Install Diesel CLI
if: ${{ env.RUN_TESTS == 'true' }}
uses: baptiste0928/[email protected]
with:
crate: diesel_cli
features: postgres
args: --no-default-features

- name: Install grcov
if: ${{ env.RUN_TESTS == 'true' }}
uses: taiki-e/[email protected]
with:
tool: grcov
checksum: true

- name: Install Just
if: ${{ env.RUN_TESTS == 'true' }}
uses: taiki-e/[email protected]
with:
tool: just
checksum: true

- name: Install Node.js
if: ${{ env.RUN_TESTS == 'true' }}
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install Cypress and dependencies
if: ${{ env.RUN_TESTS == 'true' }}
run: |
npm ci --prefix ./cypress-tests-v2

- name: Run database migrations
if: ${{ env.RUN_TESTS == 'true' }}
shell: bash
env:
DATABASE_URL: postgres://db_user:db_pass@localhost:5432/hyperswitch_db
run: just migrate_v2 run --locked-schema

- name: Insert card info into the database
if: ${{ env.RUN_TESTS == 'true' }}
run: |
PGPASSWORD=db_pass psql --host=localhost --port=5432 --username=db_user --dbname=hyperswitch_db --command "\copy cards_info FROM '.github/data/cards_info.csv' DELIMITER ',' CSV HEADER;"

- name: Build project
if: ${{ env.RUN_TESTS == 'true' }}
env:
RUSTFLAGS: "-Cinstrument-coverage"
run: just build_v2 --jobs 3

- name: Setup Local Server
if: ${{ env.RUN_TESTS == 'true' }}
env:
LLVM_PROFILE_FILE: "coverage.profraw"
run: |
# Start the server in the background
target/debug/router &

SERVER_PID=$!
echo "PID=${SERVER_PID}" >> $GITHUB_ENV

# Wait for the server to start in port 8080
COUNT=0
while ! nc -z localhost 8080; do
if [ $COUNT -gt 12 ]; then # Wait for up to 2 minutes (12 * 10 seconds)
echo "Server did not start within a reasonable time. Exiting."
kill ${SERVER_PID}
exit 1
else
COUNT=$((COUNT+1))
sleep 10
fi
done

- name: Run Cypress tests
if: ${{ env.RUN_TESTS == 'true' }}
env:
CYPRESS_BASEURL: "http://localhost:8080"
ROUTER__SERVER__WORKERS: 4
shell: bash -leuo pipefail {0}
continue-on-error: true
# We aren't specifying `command` and `jobs` arguments currently
run: scripts/execute_cypress.sh "" "" "cypress-tests-v2"

- name: Stop running server
if: ${{ env.RUN_TESTS == 'true' }} && always()
run: |
kill "${{ env.PID }}"

- name: Upload Cypress test results
if: env.RUN_TESTS == 'true' && failure()
uses: actions/upload-artifact@v4
with:
name: cypress-v2-test-results
path: |
cypress-tests-v2/cypress/reports/
retention-days: 1

# Notes:
# - The `router` process must be killed (using SIGINT/SIGTERM) to generate the `coverage.profraw` file, otherwise the coverage will only be generated for the buildscripts
# - Trying to generate branch coverage using "-Z coverage-options=branch" currently fails. Both grcov and cargo-llvm-cov crash when trying
# to process the generated `.profraw` files.
# - Explanation of ignore flags:
# - "*cargo*" : Exclude external crates from the generated `lcov.info` file
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would using *cargo* exclude paths like crates/router_env/src/cargo_workspace.rs in our repository as well? Ideally we'd want to include such paths in the coverage report.

This makes me wonder, should we consider passing something like --keep-only crates/* instead of --ignore, or are there anything outside of crates that we need included in the coverage report?

# - "target/*" : Exclude compile time generated .rs files, e.g. isodata.rs, chrono-tz/timezones.rs
# - "/*" : Exclude /Users/../rustlib/src/rust/library/core/src/panic.rs, /Users/../rustlib/src/rust/library/std/src/sys/thread_local/native/mod.rs etc.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The /Users paths are MacOS specific though, are they also needed on Linux (which is what CI runs on)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or, we can use $HOME instead? I missed these during my review...

- name: Process coverage report
if: ${{ env.RUN_TESTS == 'true' }}
run: |
grcov . --source-dir . --output-types lcov --output-path ${{ env.CODECOV_FILE }} --binary-path ./target/debug --ignore "*cargo*" --ignore "target/*" --ignore "/*"

- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
if: ${{ env.RUN_TESTS == 'true' }}
Comment on lines +457 to +464
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need coverage reports to be processed / uploaded for merge queue runs as well? If not, we'd have to tweak the if condition for both of these steps to not run on merge queue (but include the other conditions specified in RUN_TESTS).

with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ${{ env.CODECOV_FILE }}
disable_search: true
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ The single API to access payment ecosystems across 130+ countries</div>
<a href="https://github.com/juspay/hyperswitch/blob/main/LICENSE">
<img src="https://img.shields.io/badge/Made_in-Rust-orange" />
</a>
<!-- Uncomment when we reach >50% coverage -->
<!-- <a href="https://codecov.io/github/juspay/hyperswitch" >
<img src="https://codecov.io/github/juspay/hyperswitch/graph/badge.svg"/>
</a> -->
</p>
<p align="center">
<a href="https://www.linkedin.com/company/hyperswitch/">
Expand Down
Loading
Loading