From 322e285aa42641257336d48cd05c0bf376066141 Mon Sep 17 00:00:00 2001 From: Anurag Thakur Date: Tue, 17 Dec 2024 16:33:58 +0530 Subject: [PATCH 1/6] ci(workflows): Add code coverage reporting for v2 --- .github/workflows/cypress-tests-runner.yml | 211 ++++++- cypress-tests-v2/package-lock.json | 657 ++++++++++++++++----- justfile | 18 + scripts/execute_cypress_v2.sh | 188 ++++++ 4 files changed, 907 insertions(+), 167 deletions(-) create mode 100755 scripts/execute_cypress_v2.sh diff --git a/.github/workflows/cypress-tests-runner.yml b/.github/workflows/cypress-tests-runner.yml index bc83c2388f7e..a4843bc2a01a 100644 --- a/.github/workflows/cypress-tests-runner.yml +++ b/.github/workflows/cypress-tests-runner.yml @@ -20,6 +20,7 @@ env: RUN_TESTS: ${{ ((github.event_name == 'pull_request') && (github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name)) || (github.event_name == 'merge_group')}} DEBUG: cypress:cli RUST_MIN_STACK: 10485760 + CODECOV_FILE: "lcov.info" jobs: formatter: @@ -149,7 +150,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 @@ -170,13 +171,6 @@ jobs: tool: sccache checksum: true - - name: Install cargo-nextest - if: ${{ env.RUN_TESTS == 'true' }} - uses: taiki-e/install-action@v2.41.10 - with: - tool: cargo-nextest - checksum: true - - name: Install Diesel CLI if: ${{ env.RUN_TESTS == 'true' }} uses: baptiste0928/cargo-install@v3.1.1 @@ -261,3 +255,204 @@ 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 + + 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: "6f8289a9-6da0-433b-8a24-18d4d7257b7f.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: clippy llvm-tools-preview + + - name: Install sccache + if: ${{ env.RUN_TESTS == 'true' }} + uses: taiki-e/install-action@v2.41.10 + with: + tool: sccache + checksum: true + + - name: Install Diesel CLI + if: ${{ env.RUN_TESTS == 'true' }} + uses: baptiste0928/cargo-install@v3.1.1 + with: + crate: diesel_cli + features: postgres + args: --no-default-features + + - name: Install grcov + if: ${{ env.RUN_TESTS == 'true' }} + uses: baptiste0928/cargo-install@v3.1.1 + with: + crate: grcov + + - name: Install Just + if: ${{ env.RUN_TESTS == 'true' }} + uses: taiki-e/install-action@v2.41.10 + 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 + run: | + scripts/execute_cypress_v2.sh + + - 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 + + - 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' }} + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ${{ env.CODECOV_FILE }} + disable_search: true \ No newline at end of file diff --git a/cypress-tests-v2/package-lock.json b/cypress-tests-v2/package-lock.json index cac88cab055b..644b9c9faedc 100644 --- a/cypress-tests-v2/package-lock.json +++ b/cypress-tests-v2/package-lock.json @@ -29,9 +29,9 @@ } }, "node_modules/@cypress/request": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.6.tgz", - "integrity": "sha512-fi0eVdCOtKu5Ed6+E8mYxUF6ZTFJDZvHogCBelM0xVXmrDEkyM22gRArQzq1YcHPm1V47Vf/iAD+WgVdUlJCGg==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.7.tgz", + "integrity": "sha512-LzxlLEMbBOPYB85uXrDqvD4MgcenjRBLIns3zyhx7vTPj/0u2eQhzXvPiGcaJrV38Q9dbkExWp6cOHPJ+EtFYg==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -48,7 +48,7 @@ "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "6.13.0", + "qs": "6.13.1", "safe-buffer": "^5.1.2", "tough-cookie": "^5.0.0", "tunnel-agent": "^0.6.0", @@ -79,6 +79,128 @@ "ms": "^2.1.1" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@types/fs-extra": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", @@ -101,13 +223,13 @@ } }, "node_modules/@types/node": { - "version": "22.5.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.4.tgz", - "integrity": "sha512-FDuKUJQm/ju9fT/SeX/6+gBzoPzlVCzfzmGkwKvRHQVxi4BntVbyIwf6a4Xn62mrvndLiml6z/UBXIdEVjQLXg==", + "version": "22.10.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.2.tgz", + "integrity": "sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==", "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.19.2" + "undici-types": "~6.20.0" } }, "node_modules/@types/sinonjs__fake-timers": { @@ -118,9 +240,9 @@ "license": "MIT" }, "node_modules/@types/sizzle": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.8.tgz", - "integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==", + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.9.tgz", + "integrity": "sha512-xzLEyKB50yqCUPUJkIsrVvoWNfFUbIZI+RspLWt8u+tIW/BetMBZtgV2LY/2o+tYH8dRvQ+eoPf3NdhQCcLE2w==", "dev": true, "license": "MIT" }, @@ -460,18 +582,29 @@ "node": ">=6" } }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", + "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", "dev": true, "license": "MIT", "dependencies": { - "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", + "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -568,9 +701,9 @@ } }, "node_modules/ci-info": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.0.0.tgz", - "integrity": "sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.1.0.tgz", + "integrity": "sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==", "dev": true, "funding": [ { @@ -729,7 +862,7 @@ "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { @@ -742,9 +875,9 @@ } }, "node_modules/cypress": { - "version": "13.16.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.16.0.tgz", - "integrity": "sha512-g6XcwqnvzXrqiBQR/5gN+QsyRmKRhls1y5E42fyOvsmU7JuY+wM6uHJWj4ZPttjabzbnRvxcik2WemR8+xT6FA==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.17.0.tgz", + "integrity": "sha512-5xWkaPurwkIljojFidhw8lFScyxhtiFHl/i/3zov+1Z5CmY4t9tjIdvSXfu82Y3w7wt0uR9KkucbhkVvJZLQSA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -882,9 +1015,9 @@ "license": "MIT" }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, "license": "MIT", "dependencies": { @@ -913,24 +1046,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -951,6 +1066,29 @@ "node": ">=0.3.1" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT", + "peer": true + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -994,14 +1132,11 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.4" - }, "engines": { "node": ">= 0.4" } @@ -1016,6 +1151,19 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -1057,7 +1205,7 @@ "dev": true, "license": "MIT", "dependencies": { - "cross-spawn": "^7.0.6", + "cross-spawn": "^7.0.0", "get-stream": "^5.0.0", "human-signals": "^1.1.1", "is-stream": "^2.0.0", @@ -1194,6 +1342,38 @@ "flat": "cli.js" } }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -1286,17 +1466,22 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.6.tgz", + "integrity": "sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==", "dev": true, "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "dunder-proto": "^1.0.0", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -1342,22 +1527,22 @@ } }, "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", "peer": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": ">=12" + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1377,6 +1562,23 @@ "node": ">= 6" } }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/global-dirs": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", @@ -1394,13 +1596,13 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.1.3" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1423,36 +1625,10 @@ "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", "engines": { @@ -1716,6 +1892,23 @@ "dev": true, "license": "MIT" }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -1973,6 +2166,24 @@ "loose-envify": "cli.js" } }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC", + "peer": true + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -2037,10 +2248,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "peer": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mocha": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", - "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.0.1.tgz", + "integrity": "sha512-+3GkODfsDG71KSCQhc4IekSW+ItCK/kiez1Z28ksWvYhKXV/syxMlerR/sC7whDp7IyreZ4YxceMLdTs5hQE8A==", "dev": true, "license": "MIT", "peer": true, @@ -2052,7 +2274,7 @@ "diff": "^5.2.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", - "glob": "^8.1.0", + "glob": "^10.4.5", "he": "^1.2.0", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", @@ -2071,7 +2293,7 @@ "mocha": "bin/mocha.js" }, "engines": { - "node": ">= 14.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/mocha/node_modules/escape-string-regexp": { @@ -2447,9 +2669,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.8.tgz", - "integrity": "sha512-TcJPw+9RV9dibz1hHUzlLVy8N4X9TnwirAjrU08Juo6BNKggzVfP2ZJ/3ZUSq15Xl5i85i+Z89XBO90pB2PghQ==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.9.tgz", + "integrity": "sha512-Aooyr6MXU6HpvvWXKoVoXwKMs/KyVakWwg7xQfv5/S/RIgJMy0Ifa45H9qqYy7pTCszrHzP21Uk4PZq2HpEM8Q==", "dev": true, "funding": [ { @@ -2500,9 +2722,9 @@ } }, "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz", + "integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==", "dev": true, "license": "MIT", "engines": { @@ -2615,6 +2837,14 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2645,6 +2875,24 @@ "node": ">=8" } }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "peer": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -2684,9 +2932,9 @@ } }, "node_modules/prettier": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", + "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", "dev": true, "license": "MIT", "bin": { @@ -2753,9 +3001,9 @@ } }, "node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.13.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.1.tgz", + "integrity": "sha512-EJPeIn0CYrGu+hli1xilKAPXODtJ12T0sP63Ijx2/khC2JtuaN3JyNIpvmnkmaEtha9ocbG4A4cMcr+TvqvwQg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -2917,24 +3165,6 @@ "dev": true, "license": "ISC" }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -2959,16 +3189,73 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -3040,6 +3327,23 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -3053,6 +3357,21 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -3128,22 +3447,22 @@ "license": "MIT" }, "node_modules/tldts": { - "version": "6.1.59", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.59.tgz", - "integrity": "sha512-472ilPxsRuqBBpn+KuRBHJvZhk6tTo4yTVsmODrLBNLwRYJPkDfMEHivgNwp5iEl+cbrZzzRtLKRxZs7+QKkRg==", + "version": "6.1.69", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.69.tgz", + "integrity": "sha512-Oh/CqRQ1NXNY7cy9NkTPUauOWiTro0jEYZTioGbOmcQh6EC45oribyIMJp0OJO3677r13tO6SKdWoGZUx2BDFw==", "dev": true, "license": "MIT", "dependencies": { - "tldts-core": "^6.1.59" + "tldts-core": "^6.1.69" }, "bin": { "tldts": "bin/cli.js" } }, "node_modules/tldts-core": { - "version": "6.1.59", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.59.tgz", - "integrity": "sha512-EiYgNf275AQyVORl8HQYYe7rTVnmLb4hkWK7wAk/12Ksy5EiHpmUmTICa4GojookBPC8qkLMBKKwCmzNA47ZPQ==", + "version": "6.1.69", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.69.tgz", + "integrity": "sha512-nygxy9n2PBUFQUtAXAc122gGo+04/j5qr5TGQFZTHafTKYvmARVXt2cA5rgero2/dnXUfkdPtiJoKmrd3T+wdA==", "dev": true, "license": "MIT" }, @@ -3195,9 +3514,9 @@ } }, "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true, "license": "0BSD" }, @@ -3235,9 +3554,9 @@ } }, "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true, "license": "MIT" }, @@ -3345,6 +3664,26 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/justfile b/justfile index 43fca4afc893..eeb465152c33 100644 --- a/justfile +++ b/justfile @@ -64,6 +64,24 @@ check_v2 *FLAGS: cargo check {{ check_flags }} --no-default-features --features "${FEATURES}" -- {{ FLAGS }} set +x +build_v2 *FLAGS: + #! /usr/bin/env bash + set -euo pipefail + + FEATURES="$(cargo metadata --all-features --format-version 1 --no-deps | \ + jq -r ' + [ .packages[] | select(.name == "router") | .features | keys[] # Obtain features of `router` package + | select( any( . ; test("(([a-z_]+)_)?v2") ) ) ] # Select v2 features + | join(",") # Construct a comma-separated string of features for passing to `cargo` + ')" + + set -x + cargo build --package router --bin router --no-default-features --features "${FEATURES}" {{ FLAGS }} + set +x + +alias bb := build_v2 + + run_v2: #! /usr/bin/env bash set -euo pipefail diff --git a/scripts/execute_cypress_v2.sh b/scripts/execute_cypress_v2.sh new file mode 100755 index 000000000000..bcd6664e59f0 --- /dev/null +++ b/scripts/execute_cypress_v2.sh @@ -0,0 +1,188 @@ +#! /usr/bin/env bash + +set -euo pipefail + +# Initialize tmp_file globally +tmp_file="" + +# Define arrays for services, etc. +# Read service arrays from environment variables +read -r -a payments <<< "${PAYMENTS_CONNECTORS[@]:-}" +read -r -a payouts <<< "${PAYOUTS_CONNECTORS[@]:-}" +read -r -a payment_method_list <<< "${PAYMENT_METHOD_LIST[@]:-}" +read -r -a routing <<< "${ROUTING[@]:-}" + +# Define arrays +connector_map=() +failed_connectors=() + +# Define an associative array to map environment variables to service names +declare -A services=( + ["PAYMENTS_CONNECTORS"]="payments" + ["PAYOUTS_CONNECTORS"]="payouts" + ["PAYMENT_METHOD_LIST"]="payment_method_list" + ["ROUTING"]="routing" +) + +# Function to print messages in color +function print_color() { + # Input params + local color="$1" + local message="$2" + + # Define colors + local reset='\033[0m' + local red='\033[0;31m' + local green='\033[0;32m' + local yellow='\033[0;33m' + + # Use indirect reference to get the color value + echo -e "${!color}${message}${reset}" +} +export -f print_color + +# Function to check if a command exists +function command_exists() { + command -v "$1" > /dev/null 2>&1 +} + +# Function to read service arrays from environment variables +function read_service_arrays() { + # Loop through the associative array and check if each service is exported + for var in "${!services[@]}"; do + if [[ -n "${!var+x}" ]]; then + connector_map+=("${services[$var]}") + else + print_color "yellow" "Environment variable ${var} is not set. Skipping..." + fi + done +} + +# Function to execute Cypress tests +function execute_test() { + if [[ $# -lt 3 ]]; then + print_color "red" "ERROR: Insufficient arguments provided to execute_test." + exit 1 + fi + + local connector="$1" + local service="$2" + local tmp_file="$3" + + print_color "yellow" "Executing tests for ${service} with connector ${connector}..." + + export REPORT_NAME="${service}_${connector}_report" + + if ! CYPRESS_CONNECTOR="$connector" npm run "cypress:$service"; then + echo "${service}-${connector}" >> "${tmp_file}" + fi +} +export -f execute_test + +# Function to run tests +function run_tests() { + local jobs="${1:-1}" + tmp_file=$(mktemp) + + # Ensure temporary file is removed on script exit + trap 'cleanup' EXIT + + for service in "${connector_map[@]}"; do + declare -n connectors="$service" + + if [[ ${#connectors[@]} -eq 0 ]]; then + # Service-level test (e.g., payment-method-list or routing) + [[ $service == "payment_method_list" ]] && service="payment-method-list" + + echo "Running ${service} tests without connectors..." + export REPORT_NAME="${service}_report" + + if ! npm run "cypress:${service}"; then + echo "${service}" >> "${tmp_file}" + fi + else + # Connector-specific tests (e.g., payments or payouts) + print_color "yellow" "Running tests for service: '${service}' with connectors: [${connectors[*]}] in batches of ${jobs}..." + + # Execute tests in parallel + printf '%s\n' "${connectors[@]}" | parallel --jobs "${jobs}" execute_test {} "${service}" "${tmp_file}" + fi + done + + # Collect failed connectors + if [[ -s "${tmp_file}" ]]; then + failed_connectors=($(< "${tmp_file}")) + print_color "red" "One or more connectors failed to run:" + printf '%s\n' "${failed_connectors[@]}" + exit 1 + else + print_color "green" "Cypress tests execution successful!" + fi +} + +# Function to check and install dependencies +function check_dependencies() { + # parallel and npm are mandatory dependencies. exit the script if not found. + local dependencies=("parallel" "npm") + + for cmd in "${dependencies[@]}"; do + if ! command_exists "$cmd"; then + print_color "red" "ERROR: ${cmd^} is not installed!" + exit 1 + else + print_color "green" "${cmd^} is installed already!" + + if [[ ${cmd} == "npm" ]]; then + npm ci || { + print_color "red" "Command \`npm ci\` failed!" + exit 1 + } + fi + fi + done +} + +# Cleanup function to handle exit +function cleanup() { + print_color "yellow" "Cleaning up..." + if [[ -d "cypress-tests" ]]; then + cd - + fi + + if [[ -n "${tmp_file}" && -f "${tmp_file}" ]]; then + rm -f "${tmp_file}" + fi +} + +# Main function +function main() { + local command="${1:-}" + local jobs="${2:-5}" + + # Ensure script runs from 'cypress-tests' directory + if [[ "$(basename "$PWD")" != "cypress-tests-v2" ]]; then + print_color "yellow" "Changing directory to 'cypress-tests-v2'..." + cd cypress-tests-v2 || { + print_color "red" "ERROR: Directory 'cypress-tests-v2' not found!" + exit 1 + } + fi + + check_dependencies + read_service_arrays + + case "$command" in + --parallel | -p) + print_color "yellow" "WARNING: Running Cypress tests in parallel is more resource-intensive!" + # At present, parallel execution is restricted to not run out of memory + # But can be scaled up by passing the value as an argument + run_tests "$jobs" + ;; + *) + run_tests 1 + ;; + esac +} + +# Execute the main function with passed arguments +main "$@" From 336eceb7eaf2211b5352f323e05b185128b81da6 Mon Sep 17 00:00:00 2001 From: Anurag Thakur Date: Thu, 26 Dec 2024 21:35:12 +0530 Subject: [PATCH 2/6] Add documentation on generating code coverage locally --- docs/CONTRIBUTING.md | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index feed9b9cb660..61db1a028a29 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -223,6 +223,52 @@ unstable features: cargo +nightly fmt ``` +### Code Coverage + +We value well tested code. You should try to add tests for the code you add. + +For generating code coverage, follow the following steps: + +- Make sure `grcov` and `llvm-tools-preview` are installed + +- Build the project with the `-Cinstrument-coverage` flag: + + ```shell + RUSTFLAGS="-Cinstrument-coverage" cargo build --bin=router --package=router + ``` + + Several `.profraw` files will be generated. + +- Run the project using: + ```shell + LLVM_PROFILE_FILE="coverage.profraw" target/debug/router + ``` + +- Open a separate terminal tab and run the cypress tests, following the README + +- After the tests have finished running, stop the `router` process using `Ctrl+C` + +- The generated `coverage.profraw` file will contain the code coverage data for `router` + +- Generate an html report from the data using: + ```shell + grcov . --source-dir . --output-type html --binary-path ./target/debug + ``` + +- A folder named `html` will be generated, containing the report. You can view it using: + ```shell + cd html && python3 -m http.server 8000 + ``` + +- You can delete the generated `.profraw` files using: + ```shell + rm **/*.profraw + ``` + +Note: +- It is necessary to stop the `router` process to generate the coverage file +- Branch coverage generation requires nightly and currently `grcov` crashes while trying to include branch coverage. (Checked using `--log-level` parameter in `grcov`) + ### Commits It is a recommended best practice to keep your changes as logically grouped as From a9ec8715ef8ca36670efcfc7a19e4f2574484c1e Mon Sep 17 00:00:00 2001 From: Anurag Thakur Date: Mon, 30 Dec 2024 16:19:37 +0530 Subject: [PATCH 3/6] Address review comments --- .github/workflows/cypress-tests-runner.yml | 12 +- docs/CONTRIBUTING.md | 23 ++- justfile | 2 - scripts/execute_cypress.sh | 11 +- scripts/execute_cypress_v2.sh | 188 --------------------- 5 files changed, 30 insertions(+), 206 deletions(-) delete mode 100755 scripts/execute_cypress_v2.sh diff --git a/.github/workflows/cypress-tests-runner.yml b/.github/workflows/cypress-tests-runner.yml index a4843bc2a01a..973ab4993b25 100644 --- a/.github/workflows/cypress-tests-runner.yml +++ b/.github/workflows/cypress-tests-runner.yml @@ -20,7 +20,6 @@ env: RUN_TESTS: ${{ ((github.event_name == 'pull_request') && (github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name)) || (github.event_name == 'merge_group')}} DEBUG: cypress:cli RUST_MIN_STACK: 10485760 - CODECOV_FILE: "lcov.info" jobs: formatter: @@ -259,6 +258,8 @@ jobs: runner_v2: name: Run Cypress tests on v2 and generate coverage report runs-on: ubuntu-latest + env: + CODECOV_FILE: "lcov.info" services: redis: @@ -336,7 +337,7 @@ jobs: uses: dtolnay/rust-toolchain@master with: toolchain: stable 2 weeks ago - components: clippy llvm-tools-preview + components: llvm-tools-preview - name: Install sccache if: ${{ env.RUN_TESTS == 'true' }} @@ -355,9 +356,10 @@ jobs: - name: Install grcov if: ${{ env.RUN_TESTS == 'true' }} - uses: baptiste0928/cargo-install@v3.1.1 + uses: taiki-e/install-action@v2.41.10 with: - crate: grcov + tool: grcov + checksum: true - name: Install Just if: ${{ env.RUN_TESTS == 'true' }} @@ -428,7 +430,7 @@ jobs: shell: bash -leuo pipefail {0} continue-on-error: true run: | - scripts/execute_cypress_v2.sh + scripts/execute_cypress.sh "" "" "cypress-tests-v2" - name: Stop running server if: ${{ env.RUN_TESTS == 'true' }} && always() diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 61db1a028a29..9b7b6790e3c8 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -225,42 +225,51 @@ cargo +nightly fmt ### Code Coverage -We value well tested code. You should try to add tests for the code you add. +We appreciate well-tested code, so feel free to add tests when you can. -For generating code coverage, follow the following steps: +To generate code coverage using the cypress tests, follow these steps: - Make sure `grcov` and `llvm-tools-preview` are installed + ```shell + rustup install llvm-tools-preview + cargo install grcov + ``` + - Build the project with the `-Cinstrument-coverage` flag: ```shell RUSTFLAGS="-Cinstrument-coverage" cargo build --bin=router --package=router ``` - Several `.profraw` files will be generated. + Several `.profraw` files will be generated. (Due to the execution of build scripts) + +- Execute the binary: -- Run the project using: ```shell LLVM_PROFILE_FILE="coverage.profraw" target/debug/router ``` -- Open a separate terminal tab and run the cypress tests, following the README +- Open a separate terminal tab and run the cypress tests, following the [README] - After the tests have finished running, stop the `router` process using `Ctrl+C` - The generated `coverage.profraw` file will contain the code coverage data for `router` -- Generate an html report from the data using: +- Generate an html report from the data: + ```shell grcov . --source-dir . --output-type html --binary-path ./target/debug ``` - A folder named `html` will be generated, containing the report. You can view it using: + ```shell cd html && python3 -m http.server 8000 ``` - You can delete the generated `.profraw` files using: + ```shell rm **/*.profraw ``` @@ -269,6 +278,8 @@ Note: - It is necessary to stop the `router` process to generate the coverage file - Branch coverage generation requires nightly and currently `grcov` crashes while trying to include branch coverage. (Checked using `--log-level` parameter in `grcov`) +[README]: /cypress-tests-v2/README.md + ### Commits It is a recommended best practice to keep your changes as logically grouped as diff --git a/justfile b/justfile index eeb465152c33..5a0d13396ba6 100644 --- a/justfile +++ b/justfile @@ -79,8 +79,6 @@ build_v2 *FLAGS: cargo build --package router --bin router --no-default-features --features "${FEATURES}" {{ FLAGS }} set +x -alias bb := build_v2 - run_v2: #! /usr/bin/env bash diff --git a/scripts/execute_cypress.sh b/scripts/execute_cypress.sh index 1f1219ee717c..8d93519b468c 100755 --- a/scripts/execute_cypress.sh +++ b/scripts/execute_cypress.sh @@ -158,12 +158,13 @@ function cleanup() { function main() { local command="${1:-}" local jobs="${2:-5}" + local test_dir="${3:-cypress-tests}" - # Ensure script runs from 'cypress-tests' directory - if [[ "$(basename "$PWD")" != "cypress-tests" ]]; then - print_color "yellow" "Changing directory to 'cypress-tests'..." - cd cypress-tests || { - print_color "red" "ERROR: Directory 'cypress-tests' not found!" + # Ensure script runs from the specified test directory (default: cypress-tests) + if [[ "$(basename "$PWD")" != "$(basename "$test_dir")" ]]; then + print_color "yellow" "Changing directory to '${test_dir}'..." + cd "${test_dir}" || { + print_color "red" "ERROR: Directory '${test_dir}' not found!" exit 1 } fi diff --git a/scripts/execute_cypress_v2.sh b/scripts/execute_cypress_v2.sh deleted file mode 100755 index bcd6664e59f0..000000000000 --- a/scripts/execute_cypress_v2.sh +++ /dev/null @@ -1,188 +0,0 @@ -#! /usr/bin/env bash - -set -euo pipefail - -# Initialize tmp_file globally -tmp_file="" - -# Define arrays for services, etc. -# Read service arrays from environment variables -read -r -a payments <<< "${PAYMENTS_CONNECTORS[@]:-}" -read -r -a payouts <<< "${PAYOUTS_CONNECTORS[@]:-}" -read -r -a payment_method_list <<< "${PAYMENT_METHOD_LIST[@]:-}" -read -r -a routing <<< "${ROUTING[@]:-}" - -# Define arrays -connector_map=() -failed_connectors=() - -# Define an associative array to map environment variables to service names -declare -A services=( - ["PAYMENTS_CONNECTORS"]="payments" - ["PAYOUTS_CONNECTORS"]="payouts" - ["PAYMENT_METHOD_LIST"]="payment_method_list" - ["ROUTING"]="routing" -) - -# Function to print messages in color -function print_color() { - # Input params - local color="$1" - local message="$2" - - # Define colors - local reset='\033[0m' - local red='\033[0;31m' - local green='\033[0;32m' - local yellow='\033[0;33m' - - # Use indirect reference to get the color value - echo -e "${!color}${message}${reset}" -} -export -f print_color - -# Function to check if a command exists -function command_exists() { - command -v "$1" > /dev/null 2>&1 -} - -# Function to read service arrays from environment variables -function read_service_arrays() { - # Loop through the associative array and check if each service is exported - for var in "${!services[@]}"; do - if [[ -n "${!var+x}" ]]; then - connector_map+=("${services[$var]}") - else - print_color "yellow" "Environment variable ${var} is not set. Skipping..." - fi - done -} - -# Function to execute Cypress tests -function execute_test() { - if [[ $# -lt 3 ]]; then - print_color "red" "ERROR: Insufficient arguments provided to execute_test." - exit 1 - fi - - local connector="$1" - local service="$2" - local tmp_file="$3" - - print_color "yellow" "Executing tests for ${service} with connector ${connector}..." - - export REPORT_NAME="${service}_${connector}_report" - - if ! CYPRESS_CONNECTOR="$connector" npm run "cypress:$service"; then - echo "${service}-${connector}" >> "${tmp_file}" - fi -} -export -f execute_test - -# Function to run tests -function run_tests() { - local jobs="${1:-1}" - tmp_file=$(mktemp) - - # Ensure temporary file is removed on script exit - trap 'cleanup' EXIT - - for service in "${connector_map[@]}"; do - declare -n connectors="$service" - - if [[ ${#connectors[@]} -eq 0 ]]; then - # Service-level test (e.g., payment-method-list or routing) - [[ $service == "payment_method_list" ]] && service="payment-method-list" - - echo "Running ${service} tests without connectors..." - export REPORT_NAME="${service}_report" - - if ! npm run "cypress:${service}"; then - echo "${service}" >> "${tmp_file}" - fi - else - # Connector-specific tests (e.g., payments or payouts) - print_color "yellow" "Running tests for service: '${service}' with connectors: [${connectors[*]}] in batches of ${jobs}..." - - # Execute tests in parallel - printf '%s\n' "${connectors[@]}" | parallel --jobs "${jobs}" execute_test {} "${service}" "${tmp_file}" - fi - done - - # Collect failed connectors - if [[ -s "${tmp_file}" ]]; then - failed_connectors=($(< "${tmp_file}")) - print_color "red" "One or more connectors failed to run:" - printf '%s\n' "${failed_connectors[@]}" - exit 1 - else - print_color "green" "Cypress tests execution successful!" - fi -} - -# Function to check and install dependencies -function check_dependencies() { - # parallel and npm are mandatory dependencies. exit the script if not found. - local dependencies=("parallel" "npm") - - for cmd in "${dependencies[@]}"; do - if ! command_exists "$cmd"; then - print_color "red" "ERROR: ${cmd^} is not installed!" - exit 1 - else - print_color "green" "${cmd^} is installed already!" - - if [[ ${cmd} == "npm" ]]; then - npm ci || { - print_color "red" "Command \`npm ci\` failed!" - exit 1 - } - fi - fi - done -} - -# Cleanup function to handle exit -function cleanup() { - print_color "yellow" "Cleaning up..." - if [[ -d "cypress-tests" ]]; then - cd - - fi - - if [[ -n "${tmp_file}" && -f "${tmp_file}" ]]; then - rm -f "${tmp_file}" - fi -} - -# Main function -function main() { - local command="${1:-}" - local jobs="${2:-5}" - - # Ensure script runs from 'cypress-tests' directory - if [[ "$(basename "$PWD")" != "cypress-tests-v2" ]]; then - print_color "yellow" "Changing directory to 'cypress-tests-v2'..." - cd cypress-tests-v2 || { - print_color "red" "ERROR: Directory 'cypress-tests-v2' not found!" - exit 1 - } - fi - - check_dependencies - read_service_arrays - - case "$command" in - --parallel | -p) - print_color "yellow" "WARNING: Running Cypress tests in parallel is more resource-intensive!" - # At present, parallel execution is restricted to not run out of memory - # But can be scaled up by passing the value as an argument - run_tests "$jobs" - ;; - *) - run_tests 1 - ;; - esac -} - -# Execute the main function with passed arguments -main "$@" From 0d0e65b2bb366cdea83846010bc6a6c07c210b85 Mon Sep 17 00:00:00 2001 From: Anurag Thakur Date: Tue, 31 Dec 2024 15:08:09 +0530 Subject: [PATCH 4/6] Improved Documentation --- .github/workflows/cypress-tests-runner.yml | 12 +++- README.md | 4 ++ docs/CONTRIBUTING.md | 69 +++++++++++++--------- 3 files changed, 54 insertions(+), 31 deletions(-) diff --git a/.github/workflows/cypress-tests-runner.yml b/.github/workflows/cypress-tests-runner.yml index 973ab4993b25..896ece73b559 100644 --- a/.github/workflows/cypress-tests-runner.yml +++ b/.github/workflows/cypress-tests-runner.yml @@ -429,8 +429,8 @@ jobs: ROUTER__SERVER__WORKERS: 4 shell: bash -leuo pipefail {0} continue-on-error: true - run: | - scripts/execute_cypress.sh "" "" "cypress-tests-v2" + # 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() @@ -446,6 +446,14 @@ jobs: 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 + # - "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. - name: Process coverage report if: ${{ env.RUN_TESTS == 'true' }} run: | diff --git a/README.md b/README.md index 10fdb6afc760..ca98709be792 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,10 @@ The single API to access payment ecosystems across 130+ countries + +

diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 9b7b6790e3c8..9efb6529bf19 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -229,50 +229,61 @@ We appreciate well-tested code, so feel free to add tests when you can. To generate code coverage using the cypress tests, follow these steps: -- Make sure `grcov` and `llvm-tools-preview` are installed +0. Make sure `grcov` and `llvm-tools-preview` are installed - ```shell - rustup install llvm-tools-preview - cargo install grcov - ``` + ```shell + rustup install llvm-tools-preview + cargo install grcov + ``` + +1. Build the project with the `-Cinstrument-coverage` flag: + + ```shell + RUSTFLAGS="-Cinstrument-coverage" cargo build --bin=router --package=router + ``` + + Several `.profraw` files will be generated. (Due to the execution of build scripts) + +2. Execute the binary: -- Build the project with the `-Cinstrument-coverage` flag: + ```shell + LLVM_PROFILE_FILE="coverage.profraw" target/debug/router + ``` - ```shell - RUSTFLAGS="-Cinstrument-coverage" cargo build --bin=router --package=router - ``` +3. Open a separate terminal tab and run the cypress tests, following the [README] - Several `.profraw` files will be generated. (Due to the execution of build scripts) +4. After the tests have finished running, stop the `router` process using `Ctrl+C` -- Execute the binary: + The generated `coverage.profraw` file will contain the code coverage data for `router` - ```shell - LLVM_PROFILE_FILE="coverage.profraw" target/debug/router - ``` +5. Generate an html report from the data: -- Open a separate terminal tab and run the cypress tests, following the [README] + ```shell + grcov . --source-dir . --output-type html --binary-path ./target/debug + ``` -- After the tests have finished running, stop the `router` process using `Ctrl+C` +6. A folder named `html` will be generated, containing the report. You can view it using: -- The generated `coverage.profraw` file will contain the code coverage data for `router` + ```shell + cd html && python3 -m http.server 8000 + ``` -- Generate an html report from the data: +7. You can delete the generated `.profraw` files: - ```shell - grcov . --source-dir . --output-type html --binary-path ./target/debug - ``` + ```shell + rm **/*.profraw + ``` -- A folder named `html` will be generated, containing the report. You can view it using: +#### Integration with VSCode +You can also visualize code coverage in VSCode using the [coverage-gutters](https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters) extension. - ```shell - cd html && python3 -m http.server 8000 - ``` +You need to generate an `lcov.info` file in the directory root. After following till step 4 above: -- You can delete the generated `.profraw` files using: +```shell +grcov . -s . -t lcov --output-path lcov.info --binary-path ./target/debug --ignore "*cargo*" --ignore "target/*" --ignore "/*" +``` - ```shell - rm **/*.profraw - ``` +This will generate an `lcov.info` file that can be read by the extension. Note: - It is necessary to stop the `router` process to generate the coverage file From 961ce987a97b07c61f68d47c6a16777787201c41 Mon Sep 17 00:00:00 2001 From: Anurag Thakur Date: Tue, 31 Dec 2024 17:13:49 +0530 Subject: [PATCH 5/6] Update S3 source --- .github/workflows/cypress-tests-runner.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cypress-tests-runner.yml b/.github/workflows/cypress-tests-runner.yml index 896ece73b559..e7aa9f1d3773 100644 --- a/.github/workflows/cypress-tests-runner.yml +++ b/.github/workflows/cypress-tests-runner.yml @@ -304,7 +304,7 @@ jobs: 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: "6f8289a9-6da0-433b-8a24-18d4d7257b7f.json.gpg" + S3_SOURCE_FILE_NAME: "aa328308-b34e-41b7-a590-4fe45cfe7991.json.gpg" shell: bash run: | mkdir -p ".github/secrets" ".github/test" From 95c95ed4a82d2eebd0bb374ca20c5e4bf00b5141 Mon Sep 17 00:00:00 2001 From: Anurag Thakur Date: Thu, 2 Jan 2025 16:19:24 +0530 Subject: [PATCH 6/6] Address review comments --- .github/workflows/cypress-tests-runner.yml | 12 ++++-------- .gitignore | 1 + docs/CONTRIBUTING.md | 17 +++++++++-------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/.github/workflows/cypress-tests-runner.yml b/.github/workflows/cypress-tests-runner.yml index e7aa9f1d3773..30432945e3b1 100644 --- a/.github/workflows/cypress-tests-runner.yml +++ b/.github/workflows/cypress-tests-runner.yml @@ -450,18 +450,14 @@ jobs: # - 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 - # - "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. + # - --keep-only argument is used to exclude external crates in generated lcov.info file (~500MiB -> ~70MiB) - 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 "/*" + if: ${{ env.RUN_TESTS == 'true' && github.event_name != 'merge_group' }} + run: grcov . --source-dir . --output-types lcov --output-path ${{ env.CODECOV_FILE }} --binary-path ./target/debug --keep-only "crates/*" - name: Upload coverage reports to Codecov uses: codecov/codecov-action@v5 - if: ${{ env.RUN_TESTS == 'true' }} + if: ${{ env.RUN_TESTS == 'true' && github.event_name != 'merge_group'}} with: token: ${{ secrets.CODECOV_TOKEN }} files: ${{ env.CODECOV_FILE }} diff --git a/.gitignore b/.gitignore index dcbeddf7adab..d53145b33ee9 100644 --- a/.gitignore +++ b/.gitignore @@ -241,6 +241,7 @@ $RECYCLE.BIN/ # hyperswitch Project specific excludes # code coverage report *.profraw +lcov.info html/ coverage.json # other diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 9efb6529bf19..d9314ceb9196 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -34,6 +34,7 @@ Please join us! - [Resolving a Bug Report](#resolving-a-bug-report) - [Pull Requests](#pull-requests) - [Cargo Commands](#cargo-commands) + - [Code Coverage](#code-coverage) - [Commits](#commits) - [Opening the Pull Request](#opening-the-pull-request) - [Discuss and update](#discuss-and-update) @@ -232,7 +233,7 @@ To generate code coverage using the cypress tests, follow these steps: 0. Make sure `grcov` and `llvm-tools-preview` are installed ```shell - rustup install llvm-tools-preview + rustup component add llvm-tools-preview cargo install grcov ``` @@ -250,7 +251,7 @@ To generate code coverage using the cypress tests, follow these steps: LLVM_PROFILE_FILE="coverage.profraw" target/debug/router ``` -3. Open a separate terminal tab and run the cypress tests, following the [README] +3. Open a separate terminal tab and run the cypress tests, following the [README][cypress-v2-readme] 4. After the tests have finished running, stop the `router` process using `Ctrl+C` @@ -274,22 +275,22 @@ To generate code coverage using the cypress tests, follow these steps: rm **/*.profraw ``` +Note: +- It is necessary to stop the `router` process to generate the coverage file +- Branch coverage generation requires nightly and currently `grcov` crashes while trying to include branch coverage. (Checked using `--log-level` parameter in `grcov`) + #### Integration with VSCode You can also visualize code coverage in VSCode using the [coverage-gutters](https://marketplace.visualstudio.com/items?itemName=ryanluker.vscode-coverage-gutters) extension. You need to generate an `lcov.info` file in the directory root. After following till step 4 above: ```shell -grcov . -s . -t lcov --output-path lcov.info --binary-path ./target/debug --ignore "*cargo*" --ignore "target/*" --ignore "/*" +grcov . -s . -t lcov --output-path lcov.info --binary-path ./target/debug --keep-only "crates/*" ``` This will generate an `lcov.info` file that can be read by the extension. -Note: -- It is necessary to stop the `router` process to generate the coverage file -- Branch coverage generation requires nightly and currently `grcov` crashes while trying to include branch coverage. (Checked using `--log-level` parameter in `grcov`) - -[README]: /cypress-tests-v2/README.md +[cypress-v2-readme]: /cypress-tests-v2/README.md ### Commits