All checks were successful
CI Code / Check spelling (push) Successful in 18s
CI Code / Check coding style (push) Successful in 31s
CI Code / Code Coverage (push) Successful in 15m25s
CI Code / Linux (debian) (push) Successful in 15m57s
CI Code / Linux (ubuntu) (push) Successful in 16m0s
CI Code / Linux (arch) (push) Successful in 16m6s
Split functional tests into 4 parallel groups and add check-functional-parallel target (~3x faster CI runs). Add branch-aware LCOV coverage reporting with new --enable-coverage option and lcov summary in CI pipeline. Enable ccache via -C configure flag for faster recompilations. Install lcov in all Docker images and use --depth 1 git clones + parallel make -j$(nproc) for quicker container builds. Update CONTRIBUTING.md with instructions for parallel test groups and adding new ones. All changes are tightly related CI/performance improvements developed in sequence. No external service uploads (e.g. Codecov skipped due to Gitea incompatibility).
272 lines
8.2 KiB
Bash
Executable File
272 lines
8.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
log_content()
|
|
{
|
|
echo
|
|
echo "Content of $1:"
|
|
cat "$1"
|
|
}
|
|
|
|
error_handler()
|
|
{
|
|
ERR_CODE=$?
|
|
|
|
log_content ./config.log
|
|
log_content ./test-suite.log
|
|
log_content ./test-suite-memcheck.log
|
|
|
|
echo
|
|
echo "Error ${ERR_CODE} with command '${BASH_COMMAND}' on line ${BASH_LINENO[0]}. Exiting."
|
|
echo
|
|
exit ${ERR_CODE}
|
|
}
|
|
|
|
trap error_handler ERR
|
|
|
|
# Verify that test failures are properly detected
|
|
# This is a meta-test: it runs a deliberately failing test
|
|
# and checks that the test framework reports the failure correctly
|
|
verify_test_failure_detection()
|
|
{
|
|
echo
|
|
echo "==> Verifying test failure detection..."
|
|
|
|
# Create a simple failing test
|
|
cat > /tmp/test_must_fail.c << 'EOF'
|
|
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <setjmp.h>
|
|
#include <cmocka.h>
|
|
|
|
static void test_that_must_fail(void **state) {
|
|
(void)state;
|
|
assert_true(0); // This MUST fail
|
|
}
|
|
|
|
int main(void) {
|
|
const struct CMUnitTest tests[] = {
|
|
cmocka_unit_test(test_that_must_fail),
|
|
};
|
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
|
}
|
|
EOF
|
|
|
|
# Compile the failing test
|
|
if ! gcc -o /tmp/test_must_fail /tmp/test_must_fail.c -lcmocka 2>/dev/null; then
|
|
echo "Warning: Could not compile test failure verification (cmocka not available?)"
|
|
echo "Skipping test failure detection verification"
|
|
return 0
|
|
fi
|
|
|
|
# Test 1: Single failing test detection
|
|
echo " Testing single test failure detection..."
|
|
if /tmp/test_must_fail > /tmp/test_must_fail.log 2>&1; then
|
|
echo "ERROR: Test that should fail returned success (exit code 0)"
|
|
echo "This means the test framework is NOT detecting failures correctly!"
|
|
echo "--- Test output ---"
|
|
cat /tmp/test_must_fail.log
|
|
echo "--- End output ---"
|
|
rm -f /tmp/test_must_fail /tmp/test_must_fail.c /tmp/test_must_fail.log
|
|
exit 1
|
|
fi
|
|
echo " ✓ Single test failure correctly detected"
|
|
|
|
# Test 2: Parallel failure detection (simulates check-functional-parallel)
|
|
echo " Testing parallel test failure detection..."
|
|
failed=0
|
|
/tmp/test_must_fail > /tmp/p1.log 2>&1 & pid1=$!
|
|
true > /tmp/p2.log 2>&1 & pid2=$! # This passes
|
|
/tmp/test_must_fail > /tmp/p3.log 2>&1 & pid3=$!
|
|
true > /tmp/p4.log 2>&1 & pid4=$! # This passes
|
|
|
|
wait $pid1 || failed=$((failed + 1))
|
|
wait $pid2 || failed=$((failed + 1))
|
|
wait $pid3 || failed=$((failed + 1))
|
|
wait $pid4 || failed=$((failed + 1))
|
|
|
|
if [ $failed -ne 2 ]; then
|
|
echo "ERROR: Expected 2 failures in parallel tests, got $failed"
|
|
echo "Parallel failure detection is broken!"
|
|
rm -f /tmp/test_must_fail /tmp/test_must_fail.c /tmp/test_must_fail.log /tmp/p?.log
|
|
exit 1
|
|
fi
|
|
echo " ✓ Parallel test failures correctly detected (2 of 4 failed as expected)"
|
|
|
|
rm -f /tmp/test_must_fail /tmp/test_must_fail.c /tmp/test_must_fail.log /tmp/p?.log
|
|
echo "✓ Test failure detection verified"
|
|
}
|
|
|
|
num_cores()
|
|
{
|
|
# Check for cores, for systems with:
|
|
# Line 1. Linux w/ coreutils, or...
|
|
# Line 2. OpenBSD, FreeBSD, NetBSD or macOS, or...
|
|
# Line 3. Fallback for Linux w/o coreutils (glibc).
|
|
nproc \
|
|
|| sysctl -n hw.ncpu \
|
|
|| getconf _NPROCESSORS_ONLN 2>/dev/null
|
|
}
|
|
|
|
# Run test failure detection verification first
|
|
verify_test_failure_detection
|
|
|
|
./bootstrap.sh
|
|
|
|
tests=()
|
|
MAKE="make --quiet -j$(num_cores)"
|
|
CC="gcc"
|
|
|
|
ARCH="$(uname | tr '[:upper:]' '[:lower:]')"
|
|
|
|
case "$ARCH" in
|
|
linux*)
|
|
# 4 configurations for parallel CI
|
|
tests=(
|
|
# 1. Full build (all features enabled)
|
|
"--enable-notifications --enable-icons-and-clipboard --enable-otr --enable-pgp
|
|
--enable-omemo --enable-plugins --enable-c-plugins
|
|
--enable-python-plugins --with-xscreensaver --enable-omemo-qrcode --enable-gdk-pixbuf"
|
|
# 2. Minimal build (all optional features disabled)
|
|
"--disable-notifications --disable-icons-and-clipboard --disable-otr --disable-pgp
|
|
--disable-omemo --disable-plugins --disable-c-plugins
|
|
--disable-python-plugins --without-xscreensaver --disable-omemo-qrcode --disable-gdk-pixbuf"
|
|
# 3. No encryption (disable otr, pgp, omemo)
|
|
"--disable-pgp --disable-otr --disable-omemo --disable-omemo-qrcode"
|
|
# 4. Default configuration
|
|
""
|
|
)
|
|
source /etc/profile.d/debuginfod.sh 2>/dev/null || true
|
|
;;
|
|
darwin*)
|
|
# 4 configurations for parallel CI
|
|
tests=(
|
|
# 1. Full build (all features enabled)
|
|
"--enable-notifications --enable-icons-and-clipboard --enable-otr --enable-pgp
|
|
--enable-omemo --enable-plugins --enable-c-plugins
|
|
--enable-python-plugins"
|
|
# 2. Minimal build (all optional features disabled)
|
|
"--disable-notifications --disable-icons-and-clipboard --disable-otr --disable-pgp
|
|
--disable-omemo --disable-plugins --disable-c-plugins
|
|
--disable-python-plugins"
|
|
# 3. No encryption (disable otr, pgp, omemo)
|
|
"--disable-pgp --disable-otr --disable-omemo"
|
|
# 4. Default configuration
|
|
""
|
|
)
|
|
;;
|
|
openbsd*)
|
|
MAKE="gmake"
|
|
# TODO(#1231):
|
|
# `-std=gnu99 -fexec-charset=UTF-8` to silence:
|
|
# src/event/server_events.c:1453:19: error: universal character names are only valid in C++ and C99
|
|
# src/event/server_events.c:1454:19: error: universal character names are only valid in C++ and C99
|
|
CC="egcc -std=gnu99 -fexec-charset=UTF-8"
|
|
|
|
# 4 configurations for parallel CI
|
|
tests=(
|
|
# 1. Full build (all features enabled)
|
|
"--enable-notifications --enable-icons-and-clipboard --enable-otr --enable-pgp
|
|
--enable-omemo --enable-plugins --enable-c-plugins
|
|
--enable-python-plugins"
|
|
# 2. Minimal build (all optional features disabled)
|
|
"--disable-notifications --disable-icons-and-clipboard --disable-otr --disable-pgp
|
|
--disable-omemo --disable-plugins --disable-c-plugins
|
|
--disable-python-plugins"
|
|
# 3. No encryption (disable otr, pgp, omemo)
|
|
"--disable-pgp --disable-otr --disable-omemo"
|
|
# 4. Default configuration
|
|
""
|
|
)
|
|
;;
|
|
esac
|
|
|
|
case "$ARCH" in
|
|
linux*)
|
|
echo
|
|
echo "--> Building with ./configure -C ${tests[0]} --enable-valgrind $*"
|
|
echo
|
|
|
|
# shellcheck disable=SC2086
|
|
./configure -C ${tests[0]} --enable-valgrind $*
|
|
|
|
$MAKE CC="${CC}"
|
|
if grep '^ID=' /etc/os-release | grep -q -e debian; then
|
|
$MAKE check-valgrind
|
|
else
|
|
$MAKE check-valgrind || log_content ./test-suite-memcheck.log
|
|
fi
|
|
$MAKE distclean
|
|
;;
|
|
esac
|
|
|
|
# Function to build and test a single configuration
|
|
build_and_test() {
|
|
local features="$1"
|
|
local extra_args="$2"
|
|
local idx="$3"
|
|
local build_dir="build-$idx"
|
|
local log_file="build-$idx.log"
|
|
|
|
{
|
|
echo "=== Build $idx started at $(date) ==="
|
|
echo "--> Building in $build_dir with ./configure -C $features $extra_args"
|
|
|
|
mkdir -p "$build_dir"
|
|
cd "$build_dir"
|
|
|
|
# shellcheck disable=SC2086
|
|
../configure -C $features $extra_args
|
|
|
|
$MAKE CC="${CC}"
|
|
$MAKE check-functional-parallel
|
|
|
|
./profanity -v
|
|
$MAKE clean
|
|
|
|
cd ..
|
|
rm -rf "$build_dir"
|
|
|
|
echo "=== Build $idx completed at $(date) ==="
|
|
} > "$log_file" 2>&1
|
|
}
|
|
|
|
# Run all 4 configurations in parallel
|
|
echo "Starting parallel builds..."
|
|
pids=()
|
|
for idx in 1 2 3 4; do
|
|
if [ $idx -le ${#tests[@]} ]; then
|
|
build_and_test "${tests[$((idx-1))]}" "$*" "$idx" &
|
|
pids+=("$!")
|
|
echo "Started build $idx (PID: $!)"
|
|
fi
|
|
done
|
|
|
|
# Wait for all builds and check exit codes
|
|
failed=0
|
|
for i in "${!pids[@]}"; do
|
|
idx=$((i + 1))
|
|
if wait "${pids[$i]}"; then
|
|
echo "✓ Build $idx passed"
|
|
else
|
|
echo "✗ Build $idx failed"
|
|
echo "--- Log for build $idx ---"
|
|
cat "build-$idx.log"
|
|
echo "--- End log ---"
|
|
failed=1
|
|
fi
|
|
done
|
|
|
|
# Show all logs on success too
|
|
if [ $failed -eq 0 ]; then
|
|
echo
|
|
echo "All builds passed!"
|
|
for idx in 1 2 3 4; do
|
|
if [ -f "build-$idx.log" ]; then
|
|
echo "--- Log for build $idx ---"
|
|
cat "build-$idx.log"
|
|
fi
|
|
done
|
|
else
|
|
exit 1
|
|
fi
|