Repository navigation
Merge pull request #1131 from Nanle-code/dependabot/cargo/rusqlite-0.… #245
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Mutation Testing (Wallet Import) | ||
| on: | ||
| push: | ||
| branches: [main, master, develop] | ||
| paths: | ||
| - 'src/utils/wallet_import.rs' | ||
| - 'src/utils/crypto.rs' | ||
| - '.cargo-mutants.toml' | ||
| - '.github/workflows/mutation-testing.yml' | ||
| - 'Cargo.toml' | ||
| pull_request: | ||
| paths: | ||
| - 'src/utils/wallet_import.rs' | ||
| - 'src/utils/crypto.rs' | ||
| - '.cargo-mutants.toml' | ||
| - '.github/workflows/mutation-testing.yml' | ||
| - 'Cargo.toml' | ||
| # Weekly mutation testing run (Monday 3 AM UTC) to detect regressions | ||
| schedule: | ||
| - cron: '0 3 * * 1' | ||
| # Allow manual dispatch with configurable parameters | ||
| workflow_dispatch: | ||
| inputs: | ||
| max_mutants: | ||
| description: 'Maximum mutants to generate (0 = unlimited)' | ||
| required: false | ||
| default: '0' | ||
| min_kill_rate: | ||
| description: 'Minimum kill rate threshold (0.0-1.0)' | ||
| required: false | ||
| default: '0.85' | ||
| # Cancel in-progress runs when a new commit is pushed to the same branch | ||
| concurrency: | ||
| group: mutation-testing-${{ github.ref }} | ||
| cancel-in-progress: true | ||
| jobs: | ||
| mutation-testing: | ||
| name: Mutation Testing - Wallet Import/Backup | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 120 | ||
| env: | ||
| MIN_KILL_RATE: ${{ github.event.inputs.min_kill_rate || '0.85' }} | ||
| MAX_MUTANTS: ${{ github.event.inputs.max_mutants || '0' }} | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Install Rust stable | ||
| uses: dtolnay/rust-toolchain@stable | ||
| - name: Install cargo-mutants | ||
| run: cargo install cargo-mutants | ||
| - name: Install system dependencies | ||
| run: sudo apt-get update && sudo apt-get install -y libudev-dev | ||
| - name: Cache cargo registry and target | ||
| uses: actions/cache@v4 | ||
| with: | ||
| path: | | ||
| ~/.cargo/registry | ||
| ~/.cargo/git | ||
| target | ||
| key: ${{ runner.os }}-cargo-mutants-${{ hashFiles('**/Cargo.lock') }} | ||
| restore-keys: | | ||
| ${{ runner.os }}-cargo-mutants- | ||
| - name: Run baseline tests | ||
| run: cargo test --lib wallet_import --locked | ||
| - name: Generate mutation testing report for wallet_import | ||
| run: | | ||
| mkdir -p mutation-reports | ||
| cargo mutants \ | ||
| --file src/utils/wallet_import.rs \ | ||
| --jobs 4 \ | ||
| $([ "$MAX_MUTANTS" != "0" ] && echo "--max-mutants $MAX_MUTANTS" || echo "") \ | ||
| 2>&1 | tee mutation-reports/wallet_import.log || EXIT_CODE=$? | ||
| # cargo mutants writes results under mutants.out/; copy them into our report dir. | ||
| if [ -d mutants.out ]; then | ||
| cp -r mutants.out/* mutation-reports/ 2>/dev/null || true | ||
| fi | ||
| - name: Parse mutation testing results | ||
| id: parse_results | ||
| run: python3 scripts/parse-mutants-report.py | ||
| - name: Comment PR with mutation results | ||
| if: github.event_name == 'pull_request' | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| script: | | ||
| const fs = require('fs'); | ||
| const kill_rate = '${{ steps.parse_results.outputs.kill_rate }}'; | ||
| const killed = '${{ steps.parse_results.outputs.killed }}'; | ||
| const survived = '${{ steps.parse_results.outputs.survived }}'; | ||
| const total = '${{ steps.parse_results.outputs.total }}'; | ||
| const threshold = '${{ env.MIN_KILL_RATE }}'; | ||
| const comment = `## 🧬 Mutation Testing Results | ||
| | Metric | Value | | ||
| |--------|-------| | ||
| | **Kill Rate** | ${(parseFloat(kill_rate) * 100).toFixed(1)}% | | ||
| | **Killed** | ${killed}/${total} mutants | | ||
| | **Survived** | ${survived}/${total} mutants | | ||
| | **Threshold** | ${(parseFloat(threshold) * 100).toFixed(1)}% | | ||
| Module: \`src/utils/wallet_import.rs\` (wallet backup/import cryptographic code) | ||
| ${parseFloat(kill_rate) >= parseFloat(threshold) ? '✓ **PASSED**: Kill rate meets threshold' : '❌ **FAILED**: Kill rate below threshold'} | ||
| See [mutation-reports](${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}) for details. | ||
| `; | ||
| github.rest.issues.createComment({ | ||
| issue_number: context.issue.number, | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| body: comment | ||
| }); | ||
| - name: Upload mutation reports as artifacts | ||
| if: always() | ||
| uses: actions/upload-artifact@v4 | ||
| with: | ||
| name: mutation-reports | ||
| path: | | ||
| mutation-reports/ | ||
| mutants.out/ | ||
| retention-days: 30 | ||
| - name: Check kill rate threshold | ||
| run: | | ||
| kill_rate="${{ steps.parse_results.outputs.kill_rate }}" | ||
| threshold="${{ env.MIN_KILL_RATE }}" | ||
| python3 -c " | ||
| kill_rate = float('$kill_rate') if '$kill_rate' else 0.0 | ||
| threshold = float('$threshold') | ||
| if kill_rate < threshold: | ||
| print(f'❌ Mutation kill rate {kill_rate:.1%} is below threshold {threshold:.1%}') | ||
| raise SystemExit(1) | ||
| print(f'✓ Mutation kill rate {kill_rate:.1%} meets threshold {threshold:.1%}') | ||
| " | ||
| - name: Report to pull request | ||
| if: failure() && github.event_name == 'pull_request' | ||
| run: | | ||
| echo "## ❌ Mutation Testing Failed" | ||
| echo "" | ||
| echo "The wallet import/backup module's test suite is not sensitive enough to catch potential logic errors." | ||
| echo "" | ||
| echo "**Next steps:**" | ||
| echo "1. Review surviving mutants in the artifacts" | ||
| echo "2. Add or strengthen tests to kill surviving mutants" | ||
| echo "3. See MUTATION_TESTING.md for interpretation guide" | ||