Skip to content

Revamp code coverage tooling#30181

Merged
dotnwat merged 4 commits intoredpanda-data:devfrom
dotnwat:coverage
Apr 29, 2026
Merged

Revamp code coverage tooling#30181
dotnwat merged 4 commits intoredpanda-data:devfrom
dotnwat:coverage

Conversation

@dotnwat
Copy link
Copy Markdown
Member

@dotnwat dotnwat commented Apr 15, 2026

Revamp code coverage tooling

  • HTML, terminal, and LLM optimized output formats
  • Testing for "what's coverage like for my PR/diff"
  • Testing of the coverage tooling itself to avoid bit rot
  • Claude skill for improving coverage
  • Some other junk
Coverage: //src/v/cloud_topics/level_one/...

  Totals:  Lines: 66816/292585 (22.8%)  Functions: 21443/103109 (20.8%)  Branches: 11583/72346 (16.0%)

  Scope: src/v/cloud_topics/level_one/

  File                                                             Lines      Functions       Branches
  ─────────────────────────────────────────────────────────────────────────────────────────────────────
  ...v/cloud_topics/level_one/domain/db_domain_manager.cc  1041/1686  61.7%    45/51  88.2%  297/496  59.9%
  ...d_topics/level_one/metastore/replicated_metastore.cc  535/892  60.0%    31/41  75.6%  136/234  58.1%
  ...oud_topics/level_one/domain/simple_domain_manager.cc  393/688  57.1%    21/33  63.6%   93/174  53.4%
  ...cloud_topics/level_one/metastore/lsm/state_update.cc  932/1126  82.8%    18/28  64.3%  314/380  82.6%
  ...cloud_topics/level_one/metastore/lsm/state_reader.cc  445/591  75.3%    27/30  90.0%  141/176  80.1%
  ...ud_topics/level_one/metastore/partition_validator.cc  323/451  71.6%     9/12  75.0%  112/188  59.6%
  src/v/cloud_topics/level_one/common/file_io.cc            97/224  43.3%    16/22  72.7%    16/56  28.6%
  src/v/cloud_topics/level_one/metastore/leader_router.cc  393/515  76.3%   84/125  67.2%    29/56  51.8%
  src/v/cloud_topics/level_one/common/object.cc            472/582  81.1%    87/94  92.6%   85/118  72.0%
  ...topics/level_one/frontend_reader/level_one_reader.cc  301/405  74.3%    17/18  94.4%   83/112  74.1%
  src/v/cloud_topics/level_one/compaction/sink.cc          226/314  72.0%    16/16 100.0%    45/72  62.5%
  ...ud_topics/level_one/metastore/leader_router_probe.cc     5/85   5.9%     1/18   5.6%      1/2  50.0%
  ..._topics/level_one/metastore/lsm/garbage_collector.cc  110/190  57.9%      4/6  66.7%    45/86  52.3%
  ...cloud_topics/level_one/metastore/simple_metastore.cc  615/688  89.4%    45/45 100.0%  181/222  81.5%
  src/v/cloud_topics/level_one/metastore/rpc_types.h         16/85  18.8%     9/39  23.1%    10/16  62.5%
  ...ud_topics/level_one/compaction/log_info_collector.cc  162/228  71.1%    10/12  83.3%    40/70  57.1%
  ...loud_topics/level_one/metastore/lsm/replicated_db.cc  280/337  83.1%    17/17 100.0%    76/98  77.6%
  src/v/cloud_topics/level_one/metastore/state_update.cc   716/772  92.7%    21/22  95.5%  234/262  89.3%
  src/v/cloud_topics/level_one/metastore/service.cc          18/70  25.7%     5/18  27.8%      0/0     -
  src/v/cloud_topics/level_one/metastore/topic_purger.cc   122/169  72.2%    16/19  84.2%    29/48  60.4%
  ─────────────────────────────────────────────────────────────────────────────────────────────────────
  Showing 20 of 97 files (sorted by uncovered)
  4 files with 0% coverage (use -f <pattern> to inspect)
  1872 out-of-scope files hidden (use --all-files to show)

Backports Required

  • none - not a bug fix
  • none - this is a backport
  • none - issue does not exist in previous branches
  • none - papercut/not impactful enough to backport
  • v26.1.x
  • v25.3.x
  • v25.2.x

Release Notes

  • none

Signed-off-by: Noah Watkins <noahwatkins@gmail.com>
dotnwat added 3 commits April 20, 2026 10:47
Signed-off-by: Noah Watkins <noahwatkins@gmail.com>
Signed-off-by: Noah Watkins <noahwatkins@gmail.com>
Signed-off-by: Noah Watkins <noahwatkins@gmail.com>
@dotnwat dotnwat changed the title [WIP] Revamp code coverage tooling Revamp code coverage tooling Apr 20, 2026
@dotnwat dotnwat marked this pull request as ready for review April 20, 2026 18:28
Copilot AI review requested due to automatic review settings April 20, 2026 18:28
@dotnwat dotnwat requested a review from a team as a code owner April 20, 2026 18:28
@dotnwat dotnwat requested review from PrzemekZglinicki and removed request for a team April 20, 2026 18:28
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR replaces legacy coverage utilities with a unified tools/run-cov tool that can generate terminal/HTML/LLM-friendly coverage reports, including coverage focused on changed lines in a diff, and adds Bazel-backed tests and fixtures to prevent regressions.

Changes:

  • Add tools/run-cov (Python) to run/reuse Bazel C++ coverage and emit terminal, HTML, and LLM-optimized reports (including diff coverage).
  • Add Bazel sh_test coverage-tool regression tests plus LCOV/diff fixtures under tools/tests/.
  • Remove legacy coverage scripts and update repo config (.bazelrc coverage settings, .gitignore for coverage-out/).

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tools/run-cov New unified coverage runner/report generator (terminal/html/llm + diff coverage).
tools/tests/run_cov_test.sh End-to-end Bazel shell test for tools/run-cov outputs and failure modes.
tools/tests/BUILD Registers the run_cov_test Bazel test and its runfiles.
tools/tests/testdata/sample.diff Fixture unified diff used to validate diff-coverage classification.
tools/tests/testdata/coverage_fixture.dat Fixture LCOV data used by the regression test.
tools/tests/testdata/BUILD Exposes test fixtures as Bazel data files.
tools/BUILD Exports run-cov for Bazel runfiles usage.
.bazelrc Updates coverage config flags/environment.
.gitignore Ignores coverage-out/ (default output dir).
.claude/skills/improve-coverage/SKILL.md Adds a Claude skill/playbook for using the new coverage tooling.
tools/single_test_cov.sh Removed legacy single-test coverage script.
tools/gen_coverage.py Removed legacy coverage generator.
tools/coverage_dash.py Removed legacy coverage dashboard generator.

Comment thread tools/run-cov
info.changed_lines[current_file].add(current_line)
current_line += 1
elif line.startswith("-"):
pass # deleted line — don't advance new-file counter
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

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

parse_unified_diff() treats any non "+"/"-" line inside a hunk as a context line and increments current_line. This will miscount when the diff contains metadata lines like \ No newline at end of file (which should not advance either side’s line counters), causing off-by-one changed-line mapping for the remainder of the hunk. Consider explicitly skipping lines starting with \\ (and potentially other non-hunk metadata) when current_file is set.

Suggested change
pass # deleted line — don't advance new-file counter
pass # deleted line — don't advance new-file counter
elif line.startswith("\\"):
pass # hunk metadata (for example: '\ No newline at end of file')

Copilot uses AI. Check for mistakes.
@dotnwat dotnwat requested review from StephanDollberg, WillemKauf, andrwng, bashtanov and pgellert and removed request for PrzemekZglinicki April 20, 2026 18:54
@vbotbuildovich
Copy link
Copy Markdown
Collaborator

CI test results

test results on build#83411
test_status test_class test_method test_arguments test_kind job_url passed reason test_history
FLAKY(PASS) IcebergUsageTest test_iceberg_usage {"catalog_type": "rest_hadoop", "cloud_storage_type": 1, "query_engine": "spark"} integration https://buildkite.com/redpanda/redpanda/builds/83411#019dac33-7f0d-477e-8ac8-a75966eee234 10/11 Test PASSES after retries.No significant increase in flaky rate(baseline=0.0038, p0=1.0000, reject_threshold=0.0100. adj_baseline=0.1000, p1=0.3487, trust_threshold=0.5000) https://redpanda.metabaseapp.com/dashboard/87-tests?tab=142-dt-individual-test-history&test_class=IcebergUsageTest&test_method=test_iceberg_usage

Comment thread tools/run-cov
return None

bin_dir = os.path.join(
output_base, "external", "current_llvm_toolchain_llvm", "bin"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Did you try this on arm. I remember something breaking there when I did similar for PGO.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I didn't. I don't think any developers work on arm. I guess if we wanted to use this tooling in CI we'd need to address that for sure.

Comment thread tools/run-cov
workspace_root: str | None,
output,
):
"""Generate an LLM-optimized diff coverage report in markdown."""
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What does "LLM-optimized" mean?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

basically it means no formatting.

Comment thread tools/run-cov
# ---------------------------------------------------------------------------


def parse_lcov(path: str) -> CoverageReport:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Bit confused by all the things going on in this script:

  • Parsing lcov
  • Demangling
  • Output generation

Isn't there existing tooling for all of this? Gcov? Never really been much into coverage reports.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'm unaware of any tooling that would provide reporting on the terminal. But maybe? If there is then we should use that.

Comment thread .bazelrc
Comment on lines -286 to -295
build:coverage --action_env=BAZEL_USE_LLVM_NATIVE_COVERAGE=1
build:coverage --action_env=GCOV=llvm-profdata
build:coverage --copt=-DNDEBUG
build:coverage --define=dynamic_link_tests=true
build:coverage --repo_env=BAZEL_USE_LLVM_NATIVE_COVERAGE=1
build:coverage --combined_report=lcov
build:coverage --experimental_use_llvm_covmap
build:coverage --experimental_generate_llvm_lcov
build:coverage --experimental_split_coverage_postprocessing
build:coverage --experimental_fetch_all_coverage_outputs
build:coverage --collect_code_coverage
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

i copied these settings from another c++ project two years ago. i don't know how much of that is old bazel versions vs secret magic settings. in any case, with these simplified settings coverage passes the spot testing i've been doing.

Comment thread tools/run-cov


@dataclass
class LineCoverage:
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The tool is large because it does parsing of coverage data and commits in order to be able to build custom output formats for UIs like the terminal.

Comment thread tools/run-cov
workspace_root: str | None,
output,
):
"""Generate an LLM-optimized diff coverage report in markdown."""
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

basically it means no formatting.

Comment thread tools/run-cov
# ---------------------------------------------------------------------------


def parse_lcov(path: str) -> CoverageReport:
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'm unaware of any tooling that would provide reporting on the terminal. But maybe? If there is then we should use that.

Comment thread tools/run-cov
return None

bin_dir = os.path.join(
output_base, "external", "current_llvm_toolchain_llvm", "bin"
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I didn't. I don't think any developers work on arm. I guess if we wanted to use this tooling in CI we'd need to address that for sure.

@dotnwat dotnwat requested a review from StephanDollberg April 29, 2026 14:27
Copy link
Copy Markdown
Contributor

@pgellert pgellert left a comment

Choose a reason for hiding this comment

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

pretty cool

Comment thread tools/coverage_dash.py
@@ -1,289 +0,0 @@
import argparse
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should update the bazel wiki's coverage subheader to point to this new tool once this merges

@dotnwat dotnwat merged commit ef5fa67 into redpanda-data:dev Apr 29, 2026
25 checks passed
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.

5 participants