Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,369 changes: 1,369 additions & 0 deletions test/c/cov_api_surface.c

Large diffs are not rendered by default.

464 changes: 464 additions & 0 deletions test/c/cov_codecs.c

Large diffs are not rendered by default.

932 changes: 932 additions & 0 deletions test/c/cov_logrec_print.c

Large diffs are not rendered by default.

654 changes: 654 additions & 0 deletions test/c/cov_oom_paths.c

Large diffs are not rendered by default.

892 changes: 892 additions & 0 deletions test/c/cov_rep_api.c

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions test/c/run_cov_api_surface.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/bin/sh -
#
# $Id$
#
# run_cov_api_surface.sh --
# Build and run cov_api_surface.c, the direct driver for the DB_ENV / DB /
# DBC / DB_TXN / DB_MPOOLFILE *getter* + callback-setter surface and the
# argument-validation branches of the matching setters (the ~60
# never-called getters in db_method.c / env_method.c / mp_fmethod.c /
# db_cds.c that the Tcl bindings never reach).
#
# Same shape as test/xa/run_xa_direct.sh and test/os/run_os_aio.sh:
# compile against the just-built libdb in ./.libs, run in a clean home
# under a hard timeout, report PASS/FAIL, exit non-zero on failure.
#
# Usage (from build_unix):
# sh ../test/c/run_cov_api_surface.sh

set -e

BUILD=${BUILD:-.}
SRC=${SRC:-../test/c/cov_api_surface.c}
TIMEOUT=${TIMEOUT:-180}

LIB="$BUILD/.libs/libdb-5.3.so"
if [ ! -f "$LIB" ]; then
LIB=$(ls "$BUILD"/.libs/libdb-*.so 2>/dev/null | head -1)
fi
[ -n "$LIB" ] || { echo "FAIL: libdb .so not found in $BUILD/.libs"; exit 1; }

EXTRA_LIBS="-lpthread"
# liburing is linked into the .so on Linux builds that found it.
if echo 'int main(){return 0;}' > /tmp/_covapi_surface_probe.c && \
gcc /tmp/_covapi_surface_probe.c -luring -o /tmp/_covapi_surface_probe 2>/dev/null; then
EXTRA_LIBS="$EXTRA_LIBS -luring"
fi
rm -f /tmp/_covapi_surface_probe.c /tmp/_covapi_surface_probe 2>/dev/null || true

echo "Compiling cov_api_surface against $LIB"
gcc -g -O1 ${CFLAGS:-} -I"$BUILD" -I../src -I../src/dbinc "$SRC" "$LIB" \
$EXTRA_LIBS -Wl,-rpath,"$(cd "$BUILD/.libs" && pwd)" \
-o "$BUILD/cov_api_surface"

# Guaranteed-clean homes (no rm -rf).
for d in COVAPI_TESTDIR COVAPI_TESTDIR_notxn COVAPI_TESTDIR_cds; do
rm -f "$d"/__db.* "$d"/__dbq.* "$d"/log.* "$d"/*.db "$d"/*.dat "$d"/DB_CONFIG 2>/dev/null || true
mkdir -p "$d"
done

echo "Running cov_api_surface (timeout ${TIMEOUT}s)"
if timeout "$TIMEOUT" "$BUILD/cov_api_surface"; then
echo "run_cov_api_surface.sh: PASS"
exit 0
else
rc=$?
echo "run_cov_api_surface.sh: FAIL (rc=$rc)"
exit $rc
fi
62 changes: 62 additions & 0 deletions test/c/run_cov_codecs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/bin/sh -
#
# $Id$
#
# run_cov_codecs.sh --
# Build and run cov_codecs.c: exhaustive boundary coverage of libdb's
# self-contained codecs -- the compressed-integer (varint) codec in
# src/common/db_compint.c and the string-to-number parsers in
# src/common/db_getlong.c.
#
# db_compint sits at 21% line / 25% branch in report #3 with
# __db_decompress_int NEVER CALLED, because btree compression only
# marshals 32-bit lengths (so the 64-bit decoder and the 4..9-byte size
# classes are unreachable from any Tcl workload) and the property-based
# tier that does cover them (test/pbt/pbt_compint.c) needs the `hegel`
# server binary and compiles in STUB mode -- it links, prints SKIP and
# executes nothing -- on a machine without hegel. This driver walks the
# size-class boundaries directly, with no external dependency.
#
# Same shape as test/xa/run_xa_direct.sh and test/os/run_os_aio.sh:
# compile against the just-built libdb in ./.libs, run in a clean home
# under a hard timeout, report PASS/FAIL, exit non-zero on failure.
#
# Usage (from build_unix):
# sh ../test/c/run_cov_codecs.sh

set -e

BUILD=${BUILD:-.}
SRC=${SRC:-../test/c/cov_codecs.c}
TIMEOUT=${TIMEOUT:-120}

LIB="$BUILD/.libs/libdb-5.3.so"
if [ ! -f "$LIB" ]; then
LIB=$(ls "$BUILD"/.libs/libdb-*.so 2>/dev/null | head -1)
fi
[ -n "$LIB" ] || { echo "FAIL: libdb .so not found in $BUILD/.libs"; exit 1; }

EXTRA_LIBS="-lpthread"
# liburing is linked into the .so on Linux builds that found it.
if echo 'int main(){return 0;}' > /tmp/_covcodecs_probe.c && \
gcc /tmp/_covcodecs_probe.c -luring -o /tmp/_covcodecs_probe 2>/dev/null; then
EXTRA_LIBS="$EXTRA_LIBS -luring"
fi
rm -f /tmp/_covcodecs_probe.c /tmp/_covcodecs_probe 2>/dev/null || true

echo "Compiling cov_codecs against $LIB"
gcc -g -O1 ${CFLAGS:-} -I"$BUILD" -I../src -I../src/dbinc "$SRC" "$LIB" \
$EXTRA_LIBS -Wl,-rpath,"$(cd "$BUILD/.libs" && pwd)" \
-o "$BUILD/cov_codecs"

# No environment and no files: these are pure functions.

echo "Running cov_codecs (timeout ${TIMEOUT}s)"
if timeout "$TIMEOUT" "$BUILD/cov_codecs"; then
echo "run_cov_codecs.sh: PASS"
exit 0
else
rc=$?
echo "run_cov_codecs.sh: FAIL (rc=$rc)"
exit $rc
fi
131 changes: 131 additions & 0 deletions test/c/run_cov_cutest.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
#!/bin/sh -
#
# $Id$
#
# run_cov_cutest.sh --
# Run the C unit-test binary `cutest` (test/c/cutest + test/c/suites)
# from a coverage driver.
#
# This is a MEASUREMENT GAP closer, not a new test. `cutest` is a
# 12-suite CuTest binary that already exists, already has a Makefile.in
# target (`make cutest`), and passes 100%. No coverage driver has ever
# run it, so the code only it reaches has always measured as cold. Two
# of its suites reach surfaces nothing else in the tree does:
#
# * TestChannel -- brings up THREE live repmgr sites in one process
# (ports 30101-30103), installs a message-dispatch callback, and
# drives the whole DB_CHANNEL API: async send, request/response,
# multi-segment and zero-segment messages, USERMEM buffers with and
# without DB_MULTIPLE, send-to-master, send-to-self, master
# switchover, sending to a shut-down site, connecting to a
# non-existent EID, and illegal calls from inside the dispatch
# function. That is precisely the never-called set in
# repmgr/repmgr_method.c (__repmgr_channel, __repmgr_send_msg,
# __repmgr_send_request, __repmgr_send_response,
# __repmgr_set_msg_dispatch, get_channel_connection,
# establish_connection, send_msg_conn, send_msg_self,
# request_self, response_complete, adjust_bulk_response,
# copy_body, bad_callback_method, ...) plus repmgr_msg.c's
# dispatch-side handlers.
# * TestDbTuner -- drives db_tuner.c (the page-size advisor), which
# no Tcl test runs.
#
# The other suites (TestDbHotBackup x5, TestEncryption x12,
# TestEnvConfig x12, TestEnvMethod, TestKeyExistErrorReturn,
# TestPartial x4, TestQueue incl. the shared-list unit tests) add
# env-config, encryption and partial-record coverage cheaply.
#
# Runs in its own directory under a hard timeout; cutest creates and
# removes its own TESTDIR-style homes.
#
# Usage (from build_unix):
# sh ../test/c/run_cov_cutest.sh

set -u

BUILD=${BUILD:-.}
TIMEOUT=${TIMEOUT:-600} # per suite
RUNDIR=${RUNDIR:-CUTEST_TESTDIR}

# Build it if it is not there yet (the coverage driver's `make` may not have
# asked for it; `make cutest` is cheap next to a full build).
if [ ! -x "$BUILD/cutest" ]; then
echo "Building cutest"
( cd "$BUILD" && make cutest ) || {
echo "run_cov_cutest.sh: SKIP (cutest did not build)"
exit 0
}
fi

mkdir -p "$BUILD/$RUNDIR"
# Guaranteed-clean run dir (no rm -rf).
find "$BUILD/$RUNDIR" -mindepth 1 -delete 2>/dev/null || true

# cutest links the shared lib; point the loader at the build tree.
LIBS_DIR=$(cd "$BUILD/.libs" && pwd)
LD_LIBRARY_PATH="$LIBS_DIR:${LD_LIBRARY_PATH:-}"
export LD_LIBRARY_PATH

#
# Run ONE SUITE PER PROCESS (cutest -s <suite>) rather than the whole binary.
# Two reasons, both about not losing coverage:
#
# 1. gcov writes its .gcda from an atexit handler, so a process that dies by
# a signal contributes NOTHING. One crashing suite would throw away the
# coverage of every suite in the same process.
# 2. TestQueue DOES crash in an optimised build: sh_l_as_string()
# (test/c/suites/TestQueue.c:64) fills a fixed `static char buf[1024]`
# from a list with no bound check, and the shared-list op matrix
# overruns it -- SIGSEGV at TestQueue.c:64 via TestQueue.c:827. That is
# a pre-existing bug in the TEST HARNESS, not in libdb, and it is
# reported in test/coverage/FULL-COVERAGE-REPORT-4.md rather than fixed
# here. Isolating it keeps the other eleven suites' coverage.
#
# A suite that crashes is reported but does not fail the run, for the same
# reason: this driver's job is measurement, and the crash is a known,
# documented harness defect. A suite that reports a CuTest FAILURE does fail.
#
SUITES=${SUITES:-"TestChannel TestDbHotBackup TestDbTuner TestEncryption \
TestEnvConfig TestEnvMethod TestKeyExistErrorReturn TestPartial TestQueue"}

cd "$BUILD/$RUNDIR"
ran=0
okc=0
bad=0
crashed=""
failed=""

for s in $SUITES; do
log="cutest-$s.log"
timeout "$TIMEOUT" ../cutest -s "$s" > "$log" 2>&1
rc=$?
ran=$((ran + 1))
if grep -q '!!!FAILURES!!!' "$log" 2>/dev/null; then
bad=$((bad + 1))
failed="$failed $s"
elif [ $rc -eq 0 ]; then
okc=$((okc + 1))
else
crashed="$crashed $s(rc=$rc)"
fi
# Clean between suites: several create their own TESTDIR homes.
find . -mindepth 1 ! -name 'cutest-*.log' -delete 2>/dev/null || true
done

echo "run_cov_cutest.sh: ran $ran suites, $okc clean, $bad with test failures"
[ -n "$crashed" ] && echo "run_cov_cutest.sh: CRASHED (known harness bugs):$crashed"
if [ "$bad" -gt 0 ]; then
echo "run_cov_cutest.sh: FAILURES:$failed"
for s in $failed; do
echo "--- $s ---"
grep -A6 '!!!FAILURES!!!' "cutest-$s.log" | head -20
done
echo "run_cov_cutest.sh: FAIL"
exit 1
fi
if [ "$okc" -eq 0 ]; then
echo "run_cov_cutest.sh: SKIP (no suite ran clean)"
exit 0
fi
echo "run_cov_cutest.sh: PASS"
exit 0
138 changes: 138 additions & 0 deletions test/c/run_cov_dst.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#!/bin/sh -
#
# $Id$
#
# run_cov_dst.sh --
# Run the Deterministic Simulation Testing (DST) scenarios
# (test/sim/test_sim_*.c, 41 of them) against the COVERAGE-instrumented
# libdb so their crash / fault-injection paths are measured.
#
# Why this is a measurement gap. The DST tier is built by
# `make dst_tests` and normally run from its own sweep scripts
# (test/sim/dst-sweep.sh, dst-swarm.sh) against a `--enable-dst` build.
# No coverage driver has ever run it, so everything only DST reaches has
# always measured as cold. DST is the tree's ONLY source for several
# whole classes of branch:
#
# * crash-at-an-arbitrary-write recovery (torn pages, torn log, torn
# meta page) -- the redo/undo error arms of the recovery handlers
# * ENOSPC on a data write, a log write, and during a checkpoint --
# the "out of space" propagation branches of log_put.c / mp_sync.c /
# os_write, which no functional test produces
# * crash DURING recovery (test_sim_crash_in_recovery,
# test_sim_recovery_undo_crash / _redo_crash / _ckp_crash) -- the
# re-entrant recovery arms
# * clock skew (backward jumps, timeout skew, checkpoint skew) --
# the timespec comparison branches
# * latency injection + a compound multi-fault scenario
#
# Each scenario is a self-contained C program with its own bounded
# workload and its own assertions, so this script just runs them and
# reports; a scenario failure is a real DST failure and is surfaced.
#
# IMPORTANT: this runs the scenarios as built by the ambient build. It
# does NOT plant DST bugs (DSTBUG=n) -- test/sim/dst-bug-inject.sh owns
# that, and a planted bug is *supposed* to fail, which would make the
# coverage run red. Untouched scenarios must all pass.
#
# Usage (from build_unix):
# sh ../test/c/run_cov_dst.sh
# Env:
# DST_TIMEOUT per-scenario timeout (default 300s)
# DST_ONLY space-separated scenario names to run (default: all built)

set -u

BUILD=${BUILD:-.}
DST_TIMEOUT=${DST_TIMEOUT:-300}
RUNDIR=${RUNDIR:-DSTCOV_TESTDIR}

# Build the DST scenarios if they are not there (the coverage driver's make
# does not ask for them by default).
#
# NOTE: they only LINK against a library built with --enable-dst -- the sim
# core (test/sim/sim_core.c, sim_os_hooks.c) is compiled INTO libdb by that
# option, so without it the scenarios fail to link with undefined references
# to __db_sim_strict / __db_sim_nondeterminism / __db_sim_deactivate. Both
# --enable-dst and --enable-faultinject are additive and inert until armed
# (dist/configure.ac: "when off ... a production build is bit-for-bit the
# stock library"), so the coverage build can and should carry both; see
# test/coverage/full_run4.sh. If the ambient build lacks it we SKIP rather
# than fail, so this script is safe in any tree.
if [ ! -x "$BUILD/test_sim_crash_recover" ]; then
echo "Building dst_tests"
( cd "$BUILD" && make dst_tests ) >/tmp/covdst-build.log 2>&1 || {
if grep -q '__db_sim_' /tmp/covdst-build.log 2>/dev/null; then
echo "run_cov_dst.sh: SKIP (library built without" \
"--enable-dst; DST hooks are not in libdb)"
else
echo "run_cov_dst.sh: SKIP (dst_tests did not build)"
tail -20 /tmp/covdst-build.log
fi
exit 0
}
fi

mkdir -p "$BUILD/$RUNDIR"
find "$BUILD/$RUNDIR" -mindepth 1 -delete 2>/dev/null || true

LIBS_DIR=$(cd "$BUILD/.libs" && pwd)
LD_LIBRARY_PATH="$LIBS_DIR:${LD_LIBRARY_PATH:-}"
export LD_LIBRARY_PATH

if [ -n "${DST_ONLY:-}" ]; then
scenarios="$DST_ONLY"
else
scenarios=""
for f in "$BUILD"/test_sim_* "$BUILD"/mp_failchk_pilot; do
[ -x "$f" ] || continue
case "$f" in *.o|*.lo|*.c|*.gcno|*.gcda) continue ;; esac
scenarios="$scenarios $(basename "$f")"
done
fi

pass=0
fail=0
hang=0
failed_names=""

for s in $scenarios; do
[ -x "$BUILD/$s" ] || continue
# Each scenario in its own cwd so their homes cannot collide, and
# under a hard timeout so a fault-injected hang cannot wedge the run.
d="$BUILD/$RUNDIR/$s"
mkdir -p "$d"
( cd "$d" && timeout "$DST_TIMEOUT" "../../$s" >run.log 2>&1 )
rc=$?
if [ $rc -eq 0 ]; then
pass=$((pass + 1))
elif [ $rc -eq 124 ]; then
hang=$((hang + 1))
failed_names="$failed_names $s(HANG)"
else
fail=$((fail + 1))
failed_names="$failed_names $s(rc=$rc)"
fi
# Reclaim space between scenarios (some write large logs).
find "$d" -mindepth 1 ! -name run.log -delete 2>/dev/null || true
done

echo "run_cov_dst.sh: $pass passed, $fail failed, $hang hung"
if [ $fail -ne 0 ] || [ $hang -ne 0 ]; then
echo "run_cov_dst.sh: FAILURES:$failed_names"
for s in $failed_names; do
n=${s%%(*}
[ -f "$BUILD/$RUNDIR/$n/run.log" ] && {
echo "--- $n ---"
tail -15 "$BUILD/$RUNDIR/$n/run.log"
}
done
echo "run_cov_dst.sh: FAIL"
exit 1
fi
if [ $pass -eq 0 ]; then
echo "run_cov_dst.sh: SKIP (no scenario ran)"
exit 0
fi
echo "run_cov_dst.sh: PASS"
exit 0
Loading
Loading