Skip to content

Add code coverage measurement for unit and integration tests - #1005

Open
roydahan wants to merge 3 commits into
scylla-4.xfrom
claude/java-driver-code-coverage
Open

Add code coverage measurement for unit and integration tests#1005
roydahan wants to merge 3 commits into
scylla-4.xfrom
claude/java-driver-code-coverage

Conversation

@roydahan

Copy link
Copy Markdown
Collaborator

What

jacoco-maven-plugin was already declared in the parent pom.xml (prepare-agent + report bound to every module via inheritance), but two things kept it from producing anything useful.

1. A real, pre-existing bug: coverage was silently not being collected for core

core/pom.xml (surefire) and integration-tests/pom.xml (failsafe, all three test-group executions) set <argLine> to just their own JVM flags -- ${mockitoopens.argline} / ${blockhound.argline} -- completely replacing rather than combining with the value jacoco:prepare-agent injects into that same property. distribution-tests/pom.xml had the identical bug.

Confirmed empirically while working on this: before the fix, running core's unit tests never wrote core/target/jacoco.exec at all -- jacoco:prepare-agent logged argLine set to -javaagent:... correctly, but the flag never reached the forked test JVM, so no coverage data was ever recorded for the driver's main module. Fixed with Maven's deferred-property syntax:

- <argLine>${mockitoopens.argline}</argLine>
+ <argLine>@{argLine} ${mockitoopens.argline}</argLine>

@{...} (not ${...}) matters specifically because jacoco:prepare-agent sets argLine at build-execution time, after the POM's own ${...} references would already have been resolved.

2. Nothing merged the per-module exec files into one cross-module view

Coverage core gets exercised through other modules -- most importantly the integration suite -- was never attributed back to core's own source, since each module's JaCoCo report execution only knows about its own classes. Added a new coverage-report module (packaging=pom, depends on core/query-builder/mapper-runtime/mapper-processor/metrics-micrometer/metrics-microprofile/integration-tests) that runs jacoco:report-aggregate over all of them into one report.

Makefile

  • make test-unit-coverage (new target, not a drop-in replacement for test-unit) tests each module as its own mvn invocation rather than one reactor-wide mvn test. This isn't cosmetic: in a single reactor build, a test failure in core makes Maven skip every module that depends on it (query-builder, mapper-runtime, ...) too, discarding their coverage data along with core's. Confirmed empirically, and this is unaffected by -fae/--fail-never -- those flags only rescue independent modules in the reactor, not ones with a real dependency on the failed one.
  • test-integration-scylla/test-integration-cassandra need no such variant: maven-failsafe-plugin already separates running integration tests (integration-test phase, which always completes regardless of failures) from failing the build on their results (verify phase), so a test failure there was never able to lose coverage data in the first place.
  • make coverage-report merges and renders whatever the above collected: a per-module summary plus an HTML report at coverage-report/target/site/jacoco-aggregate/index.html, and jacoco.xml/jacoco.csv alongside it.
  • make clean-coverage resets it.

Docs added to README-dev.md (the file that already documents this fork's Makefile-based workflow; the upstream CONTRIBUTING.md predates it and wasn't touched).

CI

.github/workflows/coverage.yml: runs test-unit-coverage + test-integration-scylla (a single canonical ScyllaDB version) on every push/PR, posts a summary to the job log, and uploads the HTML/XML/CSV reports as a build artifact -- surfaced this way instead of through a third-party service like Codecov, matching the choice already made for the Python, Go, and Rust drivers' equivalent tooling.

Testing

Verified end-to-end locally (JDK 17, since JDK 21+ broke an unrelated fmt-maven-plugin/google-java-format compatibility unrelated to this change, and only a modern GNU Make -- macOS ships GNU Make 3.81 from 2006, which predates .ONESHELL, silently splitting every multi-line recipe in this Makefile, not just my new ones):

  • Confirmed the argLine bug and fix directly: core/target/jacoco.exec didn't exist after a test run before the fix, existed with real data (46KB+) after it.
  • Ran make test-unit-coverage end-to-end; confirmed a genuine test failure in core (a pre-existing, environment-specific timezone test failing only because my sandbox's local timezone happens to be Asia/Jerusalem -- one of the test's own parameterized cases -- not something introduced here) did not prevent query-builder/mapper-runtime/mapper-processor/metrics-micrometer/metrics-microprofile from being tested and contributing coverage data, whereas a single reactor-wide mvn test -fae did lose all of them, which is what motivated the per-module-invocation design.
  • Ran make coverage-report; got a real aggregate report across all 6 modules (952 + 174 + 17 + 93 + 5 + 5 classes analyzed), 70.4% line coverage from unit tests alone in this constrained environment (no live cluster available locally for the integration leg, which CI's job exercises).

Fixes: https://scylladb.atlassian.net/browse/DRIVER-891

jacoco-maven-plugin was already declared in the parent pom (prepare-agent
+ report bound to every module), but two things kept it from doing
anything useful:

1. core/pom.xml and integration-tests/pom.xml (surefire and failsafe,
   respectively) set <argLine> to just their own JVM flags
   (${mockitoopens.argline} / ${blockhound.argline}), completely
   replacing rather than combining with the value jacoco:prepare-agent
   injects into that property. Confirmed empirically: before this fix,
   running core's unit tests never wrote core/target/jacoco.exec at
   all -- the -javaagent flag jacoco set up never reached the forked
   test JVM. Fixed by combining both via Maven's deferred-property
   syntax, `<argLine>@{argLine} ${mockitoopens.argline}</argLine>`
   (`@{...}` rather than `${...}` because prepare-agent sets `argLine`
   at build-execution time, after the POM's own `${...}` references
   would already have been resolved). distribution-tests/pom.xml had
   the same bug and got the same fix, for the modules that do have
   real jacoco data.

2. Nothing merged the resulting per-module jacoco.exec files into one
   cross-module view -- coverage `core` gets exercised through the
   integration suite, for instance, was never attributed back to
   core's own source. Added a new `coverage-report` module (packaging
   pom, depends on core/query-builder/mapper-runtime/mapper-processor/
   metrics-micrometer/metrics-microprofile/integration-tests) that runs
   jacoco:report-aggregate over all of them.

Makefile: `test-unit-coverage` is a new target, not a coverage-flavored
variant of the existing `test-unit`. It has to test each module as its
own `mvn` invocation rather than one reactor-wide `mvn test`: in a
single reactor build, a test failure in core makes Maven skip every
module depending on it (query-builder, mapper-runtime, ...) too,
losing their coverage data along with core's -- confirmed empirically,
and unaffected by -fae/-fn, since those only rescue independent
modules in the reactor, not ones with a real dependency on the failed
one. test-integration-scylla/test-integration-cassandra need no such
variant: maven-failsafe-plugin already separates running ITs
(integration-test phase, which always completes) from failing the
build on their results (verify phase), so a test failure there was
never able to lose coverage data to begin with. `coverage-report`
merges and renders whatever the above collected; `clean-coverage`
resets it.

CI (.github/workflows/coverage.yml) runs this against a single canonical
ScyllaDB version on every push/PR, posts a summary to the job log, and
uploads the HTML/XML/CSV reports as a build artifact -- surfaced this
way instead of through a third-party service like Codecov, matching
the choice already made for the Python, Go, and Rust drivers'
equivalent tooling this session.

Fixes: https://scylladb.atlassian.net/browse/DRIVER-891

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: QUIET

Plan: Pro Plus

Run ID: 78555360-8621-4230-8798-6219f5ffe462

📥 Commits

Reviewing files that changed from the base of the PR and between 6b16577 and 7283c0f.

📒 Files selected for processing (1)
  • coverage-report/pom.xml
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • scylladb/scylladb (auto-detected)
  • scylladb/github-automation (auto-detected)
💤 Files with no reviewable changes (1)
  • coverage-report/pom.xml

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

Added Maven JaCoCo aggregation for core, query-builder, mapper, metrics, and integration-test modules. Added Makefile targets and developer documentation for coverage collection, reporting, and cleanup. Added a GitHub Actions workflow for Scylla unit and integration coverage, CCM image caching, coverage summaries, and report artifacts. Preserved existing Maven argLine values across test configurations.

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions
  participant Maven
  participant ScyllaCCM
  participant JaCoCo
  GitHubActions->>Maven: run unit coverage
  GitHubActions->>ScyllaCCM: install and prepare cached image
  GitHubActions->>Maven: run Scylla integration coverage
  Maven->>JaCoCo: generate aggregate report
  GitHubActions->>JaCoCo: publish summary and upload report
Loading

Suggested reviewers: dkropachev, nikagra

Merge Risk: ⚪ Minimal · up to 7283c

The PR adds coverage collection, aggregation, developer commands, documentation, and CI reporting without any supplied current-head issue requiring merge-blocking action.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description check ✅ Passed The description clearly explains the coverage, build, documentation, CI, and testing changes.
Title check ✅ Passed The title clearly and concisely describes the primary change: adding code coverage measurement.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@roydahan

Copy link
Copy Markdown
Collaborator Author

@coderabbitai help

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Chat

There are 3 ways to chat with CodeRabbit:

‼️ IMPORTANT
Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai review --preview-config to test the unmerged CodeRabbit configuration on a draft PR. The requester must have repository write access; preview results are non-authoritative.
  • @coderabbitai rate limit to show your current review rate limit status.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
  • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
  • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai emit path instructions to emit generated path-specific review instructions for this repository.
  • @coderabbitai resolve merge conflict to automatically resolve merge conflicts.
  • @coderabbitai autofix to automatically fix issues identified in unresolved review comments.
  • @coderabbitai fix-ci to automatically fix failing CI checks in a stacked pull request.
  • @coderabbitai fix-ci commit to automatically fix failing CI checks by committing fixes to the current branch.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit configuration file (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

@roydahan

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Aug 19, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

jacoco:report-aggregate only aggregates compile/runtime-scoped reactor
dependencies. The root pom's dependencyManagement pins mapper-runtime,
mapper-processor, metrics-micrometer, and metrics-microprofile to
scope=test (correct for their other consumers like integration-tests),
and coverage-report inherited that scope for its own dependency on them,
so their classes were silently excluded from the aggregate even though
their jacoco.exec data was loaded (confirmed: all 7 exec files load, only
3 modules got analyzed as bundles). This lost their own integration test
coverage entirely (MicrometerMetricsIT, MicroProfileMetricsIT). Override
the scope to compile for coverage-report's own dependency declarations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant