blob: 97a83ffbbaf36d3bfd5aa93c4384a601b878e309 [file]
#! /usr/bin/env bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Build ATS with gcov instrumentation, run the unit tests (and optionally
# autests), and produce a coverage report with gcovr.
#
# Usage:
# ci/coverage [extra cmake args...]
#
# Environment overrides:
# BUILDDIR build tree (default: $SRCROOT/build-coverage)
# PREFIX install prefix (default: /tmp/ts-coverage)
# NPROCS build parallelism (default: nproc)
# GCOVR gcovr command (default: gcovr, falls back to uvx gcovr)
# AUTEST run autests too if set to a -f/--filter basename glob,
# e.g. AUTEST='tls_*' or AUTEST=all for the whole suite
#
# Requires: cmake, ninja or make, gcc/gcov, and gcovr (pip install gcovr).
set -e
SRCROOT=${SRCROOT:-$(cd "$(dirname "$0")"/.. && pwd)}
BUILDDIR=${BUILDDIR:-$SRCROOT/build-coverage}
PREFIX=${PREFIX:-/tmp/ts-coverage}
NPROCS=${NPROCS:-$(nproc 2>/dev/null || echo 4)}
GCOVR=${GCOVR:-gcovr}
if ! command -v "${GCOVR%% *}" >/dev/null 2>&1; then
if command -v uvx >/dev/null 2>&1; then
GCOVR="uvx gcovr"
else
echo "gcovr not found; install it with 'pip install gcovr'" >&2
exit 1
fi
fi
# --coverage instruments compile and link. Atomic profile updates keep the
# counters sane in ATS's heavily threaded runtime, and absolute paths in the
# notes files let gcovr resolve sources from any working directory.
COVERAGE_FLAGS="-g -O0 --coverage -fprofile-update=atomic -fprofile-abs-path"
configure() {
# Enabling autest pulls in Python3/uv/nc and the proxy-verifier toolchain at
# configure time, so only ask for it when AUTEST actually selects a run.
local autest_args=()
if [ -n "$AUTEST" ]; then
autest_args=(-DENABLE_AUTEST=ON)
fi
cmake -S "$SRCROOT" -B "$BUILDDIR" \
-DCMAKE_BUILD_TYPE=Debug \
-DCMAKE_INSTALL_PREFIX="$PREFIX" \
-DCMAKE_COMPILE_WARNING_AS_ERROR=OFF \
-DBUILD_TESTING=ON \
"${autest_args[@]}" \
-DBUILD_EXPERIMENTAL_PLUGINS=ON \
-DENABLE_EXAMPLE=ON \
-DCMAKE_CXX_FLAGS_DEBUG="$COVERAGE_FLAGS" \
-DCMAKE_C_FLAGS_DEBUG="$COVERAGE_FLAGS" \
"$@"
}
build() {
cmake --build "$BUILDDIR" -j "$NPROCS"
cmake --install "$BUILDDIR"
}
run_tests() {
# Reset counters so the report reflects exactly this run.
find "$BUILDDIR" -name '*.gcda' -delete
ctest --test-dir "$BUILDDIR" -j "$NPROCS"
if [ -n "$AUTEST" ]; then
local filter_args=()
if [ "$AUTEST" != all ]; then
# Quote the pattern: the parallel runner fnmatches it against each test's
# basename (e.g. 'tls_*'), so it must reach autest verbatim rather than be
# glob-expanded by the shell first.
filter_args=(-f "$AUTEST")
fi
# Match ctest's parallelism: -j routes autest.sh through autest-parallel.py,
# which already aims --sandbox at a per-build-tree path under /tmp, so
# concurrent coverage runs in separate build trees don't trample each other.
(cd "$BUILDDIR/tests" && ./autest.sh -j "$NPROCS" "${filter_args[@]}")
fi
}
report() {
cd "$SRCROOT"
# no_working_dir_found: vendored/generated objects whose recorded cwd is
# gone. merge-use-line-min: sources compiled into both a library and a
# unit-test binary produce slightly different function records.
# suspicious_hits: hot-path counters legitimately reach billions of hits
# over a full test run, tripping gcovr's corruption heuristic (gcc #68080).
$GCOVR -r . "$BUILDDIR" -j "$NPROCS" \
--gcov-ignore-errors=no_working_dir_found \
--gcov-ignore-parse-errors=suspicious_hits.warn_once_per_file \
--merge-mode-functions=merge-use-line-min \
--exclude 'lib/' --exclude '.*/unit_tests/' --exclude 'build.*/' \
--print-summary \
--html-details coverage.html \
--json coverage.json \
--xml coverage.xml
echo "Reports written: coverage.html coverage.json coverage.xml"
}
configure "$@"
build
run_tests
report