How to properly handle test coverage report (HTML) generation with Bazel?

1.5k views Asked by At

Goal

I would like to handle the entire process of generating the HTML report with test coverage data through Bazel.

Components

In order to achieve my goal I understand that the following components are necessary:

  • lcov .dat file: provides information about what parts of a program are actually executed (i.e. "covered") while running a particular test case . I can generate the required lcov files for my project by running ./bazelw query "attr(name, '.*test_main', //...)" | xargs ./bazelw coverage --combined_report=lcov (all my test targets are named test_main, that's how I can execute the coverage command in all of them and combine the results with --combined_report=lcov;
  • genhtml: an executable that can parse the lcov file and generate a HTML test report out of it (the final goal);
  • coverage.blz: A custom bazel rule that takes the .dat file and the genrule binary as inputs and spits the final HTML and its deps (images and other HTMLs);

What I was able to do so far...

Create an executable script for genhtml

I'm not sure if this is the best approach, however, it seemed reasonable to me at this point:

#!/bin/zsh

TOOLS_ROOT="${HOME}/.devxp/tools"
LCOV_BIN_HOME="${TOOLS_ROOT}/lcov/bin"
LCOV_GIT_REPO="https://github.com/linux-test-project/lcov.git"
GENHTML="${LCOV_BIN_HOME}/genhtml"


function main () {
  if [[ ! -f "${GENHTML}" ]]; then
    _install &> /dev/null
  fi

  "${GENHTML}" "${@}"
}

function _install () {
  mkdir -p "${LCOV_HOME}"
  pushd "${TOOLS_ROOT}" || true
  git clone "${LCOV_GIT_REPO}"
  cd "${LCOV_HOME}" || true
  make install
  popd &> /dev/null || true
}

main "${@}"

Create a file group to access the .dat in the repository

Following the suggestions from - Using Bazel to generate coverage report;

filegroup(
    name = "coverage_files",
    srcs = glob(["bazel-out/**/coverage.dat"]),
    visibility = [
        "//visibility:public"
    ]
)

This lives in my repository's root BUILD file

Start my custom rule

On file coverage_report.bzl

def _coverage_report_impl(ctx):
    dat_lcov_file = ctx.attr.coverage_files

coverage_report = rule(
    implementation = _coverage_report_impl,
    attrs = {
        "coverage_files": attr.label(),
    },
)

In the context of the custom rule implementation, I have the following questions:

  • QUESTION 1: I don't know if at this point the .dat file was already generated since it requires bazel coverage to have ran. Can I force bazel coverage from here?
  • QUESTION 2: I don't know how to get reference to my executable genhtml tool inside here. My plan was to do something like genhtml *.dat -o output;
  • QUESTION 3: I don't know how to specify the output files of the genhtml as the output for this rule (as you can see this is the first time I attempt to implement my own rule);

Any help is very much appreciated!

Reference Material

0

There are 0 answers