diff --git a/.cargo/mutants.toml b/.cargo/mutants.toml new file mode 100644 index 000000000..ede43a210 --- /dev/null +++ b/.cargo/mutants.toml @@ -0,0 +1,10 @@ +# Configuration for cargo-mutants . +# Run locally with `cargo mutants`; CI runs it against the pull request diff. + +# ignore build.rs downloads and hashes frontend assets at build time as well as +# executing the build. +exclude_globs = ["build.rs"] + +# The suite starts a web server and talks to a database, so a mutant that +# deadlocks needs a longer leash than the ~4s baseline would allow. +minimum_test_timeout = 60 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3977c512..1db1162a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -543,3 +543,30 @@ jobs: TAG_SUFFIX: ${{ matrix.variant != 'minimal' && format('-{0}', matrix.variant) || '' }} run: | docker buildx imagetools inspect "${REGISTRY_IMAGE}:${GITHUB_REF_NAME}${TAG_SUFFIX}" + + mutants: + if: github.event_name == 'pull_request' + runs-on: ubuntu-latest + timeout-minutes: 30 + continue-on-error: true + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + - uses: taiki-e/install-action@v2 + with: + tool: cargo-mutants + - name: Set up cargo cache + uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 + with: + shared-key: rust-sqlpage-mutants + save-if: ${{ github.ref == 'refs/heads/main' }} + - name: Mutate only the lines this pull request changed + run: | + git diff "origin/${{ github.base_ref }}...HEAD" > mutants.diff + cargo mutants --in-diff mutants.diff --jobs 2 + - uses: actions/upload-artifact@v7 + if: always() + with: + name: mutants-report + path: mutants.out/ diff --git a/.gitignore b/.gitignore index 994459944..328c531b8 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,5 @@ sqlpage/sqlpage.db tests_uploads/ /test-results/ /playwright-report/ +/mutants.out*/ +mutants.diff diff --git a/CHANGELOG.md b/CHANGELOG.md index 5144ae1e4..003c8dcc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ - `stacked` is now ignored on chart types that cannot stack, instead of displaying an empty chart. - Screen readers now announce the title of the modal component instead of an unnamed dialog. - `sqlpage.request_body` and `sqlpage.request_body_base64` now return NULL when the request has no body. A body that cannot be read, such as one exceeding the payload limit, is now reported as an error instead of being silently replaced with an empty body. + - `sqlpage.fetch_with_meta` now returns JSON response bodies under the documented `body` key. ## v0.45 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f764460e2..c5dc394a1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -95,6 +95,19 @@ export DATABASE_URL=mssql://root:Password123!@localhost/sqlpage cargo test ``` +### Mutation Testing + +[cargo-mutants](https://mutants.rs) finds dead code or missing tests by mutating +params and re-running the suite. + +```bash +cargo mutants --in-diff <(git diff origin/main...HEAD) # what your branch changed +``` + +A whole-codebase run takes hours, so CI only mutates the lines a pull request +touches, and reports without failing the build. Results are attached to the run +as the `mutants-report` artifact. + ### End-to-End Tests We use Playwright for end-to-end testing of dynamic frontend features. @@ -225,6 +238,7 @@ git checkout -b feature/your-feature-name - Execute all tests across multiple platforms (Linux, Windows) - Build Docker images for multiple architectures - Run frontend linting, typechecking and unit tests (`npm test`) + - Report surviving mutants for the lines the pull request changed - Test against multiple databases (SQLite, PostgreSQL, MySQL, MSSQL, Oracle, and ODBC) ## Release Process