Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tests

tracexec currently contains two kinds of tests:

  • the normal tests that are executed when running cargo test --workspace,
  • tests requiring root that are excluded by default.

Running the Tests

To run the normal tests, use

cargo test --workspace

sudo is needed to run the tests that requires root:

CARGO_TARGET_<TARGET_TRIPLE>_RUNNER='sudo -E' cargo test --workspace -- --ignored

For example, if you are testing on a x86_64 linux machine, use

CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER='sudo -E' cargo test --workspace -- --ignored

eBPF Verifier Complexity

Verifier complexity collection is available as an optional UKCI-style Nix runner. It boots the same UKCI kernels in QEMU, loads tracexec’s eBPF programs with verifier stats enabled, and writes one JSON file per kernel/LLVM combination:

nix run .#ukci-complexity

By default, results are written to verifier-complexity/. Set UKCI_COMPLEXITY_OUT_DIR to use a different output directory. This runner is intentionally separate from ukci and is not part of the required UKCI test pass.

For pull requests, a dedicated Nix workflow runs this collector on x86_64 when the compiled kernel-space eBPF sources or x86 BTF headers change. It uploads the raw JSON and rendered plots as Actions artifacts and updates a folded summary comment as soon as the complexity run finishes. The reporter also stores the PNG plots on ImgBB without an expiration and embeds them in the comment so they remain available after the artifacts expire. Configure the reporter with an IMGBB_API_KEY repository secret.

To plot the collected results from the repository root:

nix run .#plot-verifier-complexity -- verifier-complexity

The plotting script writes charts and a summary under verifier-complexity-plots/ by default. Use -o to choose another output directory, and --log-scale when comparing runs with large differences between the smallest and largest verifier counts.

Test Coverage

Most of the time you do not need to calculate the test coverage by yourself because we are tracking the test coverage continuously with CodeCov.

You will see the patch coverage and code coverage diff in a comment by CodeCov once you opened a pull request and all the tests pass.

Continue to read this section if you want to calculate the test coverage by yourself.

First, install cargo-llvm-cov if you haven’t already installed.

Then run the normal tests with coverage instrumentation to generate a coverage report named lcov.info:

cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info

After that, run the root-only tests with coverage instrumentation. We use bpfcov-rs to collect coverage of eBPF code that executes in kernel-space.

export CARGO_TARGET_<TARGET_TRIPLE>_RUNNER='sudo -E env TRACEXEC_BPFCOV_OUTDIR=/tmp/bpfcov'
# Replace <TARGET_TRIPLE> with your rust target triple in uppercase and replace dash with underscore.
# For example:  export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER='sudo -E env TRACEXEC_BPFCOV_OUTDIR=/tmp/bpfcov'
cargo llvm-cov --all-features --workspace --lcov \
    --output-path root-lcov.info -- --ignored

After the tests finish,

  • a user-space coverage report named root-lcov.info is produced,
  • and kernel-space test coverage reports for each eBPF test is located in /tmp/bpfcov.

Then, combine all the kernel-space test coverage reports:

find /tmp/bpfcov -name '*.lcov' -print0 \
    | xargs -0 -I{} echo -a {} \
    | xargs lcov -o ebpf.lcov

And finally combine all three coverage reports into one:

lcov -a ebpf.lcov -a lcov.info -a root-lcov.info -o tracexec.info

Optionally you can generate an HTML report with:

genhtml tracexec.info --output-directory cov-out

Add a Test

Feel free to add new tests to cover new/modified code.

When adding a test that requires root, please mark it with

#![allow(unused)]
fn main() {
#[ignore = "root"]
}

When the test loads eBPF program, please make sure that it runs sequentially with respect to other eBPF tests by marking it with:

#![allow(unused)]
fn main() {
#[rstest]
#[file_serial(bpf)]
}

The outer rstest attribute is a workaround for getting the real test name.