From f63ca52a5c335359867afa99dcc495125e076b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Chlup?= Date: Thu, 27 Aug 2026 11:18:08 +0200 Subject: [PATCH 1/5] test: Use ServerName directive at the top level --- test/httpd/mod_proxy_cluster.conf | 2 +- test/usealias/mod_proxy_cluster.conf | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/test/httpd/mod_proxy_cluster.conf b/test/httpd/mod_proxy_cluster.conf index acb3d388..3b7d4cd3 100644 --- a/test/httpd/mod_proxy_cluster.conf +++ b/test/httpd/mod_proxy_cluster.conf @@ -11,9 +11,9 @@ ProxyPreserveHost On Listen 8090 ManagerBalancerName mycluster WSUpgradeHeader websocket +ServerName httpd-mod_proxy_cluster - ServerName httpd-mod_proxy_cluster EnableMCMPReceive # For podman, this gets changed to IP in httpd/run.sh diff --git a/test/usealias/mod_proxy_cluster.conf b/test/usealias/mod_proxy_cluster.conf index 3c8110bf..2dc95cdf 100644 --- a/test/usealias/mod_proxy_cluster.conf +++ b/test/usealias/mod_proxy_cluster.conf @@ -9,13 +9,12 @@ LoadModule proxy_cluster_module modules/mod_proxy_cluster.so UseAlias On ProxyPreserveHost On - Listen 8090 ManagerBalancerName mycluster WSUpgradeHeader websocket +ServerName httpd-mod_proxy_cluster - ServerName httpd-mod_proxy_cluster EnableMCMPReceive # For podman, this gets changed to IP in httpd/run.sh From 12d8231260a716ad34c77a0b320f8432be16d2ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Chlup?= Date: Thu, 27 Aug 2026 11:21:35 +0200 Subject: [PATCH 2/5] test: Add CODE_COVERAGE flag for code coverage generation, use CMake for modules compilation --- test/httpd/Containerfile | 21 ++++++++------------- test/httpd/run.sh | 10 +++++++++- test/includes/common.sh | 23 +++++++++++++++++++++-- test/testsuite.sh | 27 +++++++++++++++++++++++++-- 4 files changed, 63 insertions(+), 18 deletions(-) diff --git a/test/httpd/Containerfile b/test/httpd/Containerfile index a9dd733e..540beec5 100644 --- a/test/httpd/Containerfile +++ b/test/httpd/Containerfile @@ -1,8 +1,9 @@ FROM fedora:44 AS builder ARG HTTPD_SOURCES="https://dlcdn.apache.org/httpd/httpd-2.4.68.tar.gz" +ARG ENABLE_COVERAGE="" -RUN dnf install gcc apr-devel apr-util-devel openssl-devel pcre-devel redhat-rpm-config autoconf wcstools -y +RUN dnf install gcc apr-devel apr-util-devel openssl-devel pcre-devel redhat-rpm-config wcstools cmake -y ENV HTTPD=${HTTPD_SOURCES} @@ -29,17 +30,10 @@ RUN sed -i 's/\(Listen 80\)/#\1/' /usr/local/apache2/conf/httpd.conf # httpd is installed in /usr/local/apache2/bin/ # build and install mod_proxy_cluster *.so files. WORKDIR /native -RUN for m in advertise mod_proxy_cluster balancers mod_manager; \ - do \ - cd $m; \ - echo "Building $m"; \ - ./buildconf; \ - ./configure --with-apxs=/usr/local/apache2/bin/apxs; \ - make clean; \ - make || exit 1; \ - cp *.so /usr/local/apache2/modules; \ - cd $OLDPWD; \ - done; + +RUN mkdir build || true + +RUN cd build && rm -rf * && cmake .. -DAPACHE_INCLUDE_DIR=/usr/local/apache2/include -DENABLE_COVERAGE=${ENABLE_COVERAGE:-OFF} && make && for f in modules/*.so; do ln -s "$PWD/$f" /usr/local/apache2/$f; done; RUN rm -rf /test/httpd/mod_proxy_cluster @@ -47,9 +41,10 @@ FROM fedora:44 ENV CONF=httpd/mod_proxy_cluster.conf -RUN dnf install pcre apr-util wcstools -y +RUN dnf install pcre apr-util wcstools gcc gcovr lcov -y COPY --from=builder /usr/local/apache2 /usr/local/apache2 +COPY --from=builder /native /native COPY --from=builder /test /test diff --git a/test/httpd/run.sh b/test/httpd/run.sh index 0f92a4d7..519d6203 100755 --- a/test/httpd/run.sh +++ b/test/httpd/run.sh @@ -24,7 +24,15 @@ if [ ! -z "$MPC_NAME" ]; then sed -i "s/ServerName httpd-mod_proxy_cluster/ServerName ${MPC_NAME}/g" /usr/local/apache2/conf/$FILECONF fi -# start apache httpd server in foreground +# start apache httpd server echo "Starting httpd..." +if [ "$ENABLE_COVERAGE" = "1" ]; then + # Let the unprivileged worker children create/merge .gcda files in the + # root-owned build tree: 777 for directory traversal + file creation, and + # umask 0 so gcov creates the .gcda files world-writable (0666). umask is + # inherited across fork(), so every worker gets it. + chmod -R 777 /native + umask 0 +fi /usr/local/apache2/bin/apachectl start tail -f /usr/local/apache2/logs/error_log diff --git a/test/includes/common.sh b/test/includes/common.sh index 1fcbd9bb..5b0d61ed 100644 --- a/test/includes/common.sh +++ b/test/includes/common.sh @@ -23,12 +23,28 @@ run_test() { echo " NOK" ret=1 fi + + local httpd_cont=$(docker ps -a | grep $HTTPD_IMG | cut -f 1 -d' ') # preserve httpd's logs too if DEBUG if is_enabled "$DEBUG"; then - local httpd_cont=$(docker ps -a | grep $HTTPD_IMG | cut -f 1 -d' ') docker logs $httpd_cont > "logs/${2:-$1}-httpd.log" 2>&1 docker cp ${httpd_cont}:/usr/local/apache2/logs/access_log "logs/${2:-$1}-httpd_access.log" 2> /dev/null || true fi + + if is_enabled "$CODE_COVERAGE"; then + f=$(echo ${2:-$1} | sed 's/ /-/g') + + docker exec ${httpd_cont} mkdir -p /coverage + docker exec ${httpd_cont} sh -c "/usr/local/apache2/bin/apachectl stop" + sleep 2 # wait for the coverage dump, just to be sure + docker exec ${httpd_cont} sh -c "cd /native && gcovr --gcov-ignore-parse-errors=negative_hits.warn_once_per_file --json /coverage/coverage-$f.json > /coverage/coverage-$f.log 2>&1" + docker exec ${httpd_cont} sh -c "lcov --capture --directory /native/build --ignore-errors gcov,negative --exclude '/usr/local/*' --output-file /coverage/coverage-$f.info > /coverage/coverage-lcov-$f.log 2>&1" + + for cf in $(docker exec ${httpd_cont} ls /coverage/); do + docker cp ${httpd_cont}:/coverage/$cf $PWD/coverage/$cf > /dev/null + done + fi + # Clean all after run httpd_remove > /dev/null 2>&1 tomcat_all_remove > /dev/null 2>&1 @@ -66,7 +82,9 @@ httpd_create() { done cp -r ../native ../test /tmp/mod_proxy_cluster/ mv /tmp/mod_proxy_cluster httpd/ - docker build -t $HTTPD_IMG -f httpd/Containerfile httpd/ + + docker build -t $HTTPD_IMG ${CODE_COVERAGE:+--build-arg ENABLE_COVERAGE=ON} \ + -f httpd/Containerfile httpd/ } # Build and run httpd container @@ -83,6 +101,7 @@ httpd_start() { --ulimit nofile=65536:65536 --name ${MPC_NAME:-httpd-mod_proxy_cluster} \ -e MPC_NAME=${MPC_NAME:-httpd-mod_proxy_cluster} \ -e CONF=${MPC_CONF:-httpd/mod_proxy_cluster.conf} \ + ${CODE_COVERAGE:+-e ENABLE_COVERAGE=1} \ $HTTPD_IMG httpd_wait_until_ready diff --git a/test/testsuite.sh b/test/testsuite.sh index 8ef515e9..bb5b6df5 100644 --- a/test/testsuite.sh +++ b/test/testsuite.sh @@ -37,11 +37,18 @@ if [ ! -d logs ]; then mkdir logs fi +if [ $CODE_COVERAGE ]; then + if [ ! -d coverage ]; then + mkdir coverage + fi + rm -f coverage/* +fi + . includes/common.sh if [ ! -d tomcat/target ]; then echo "Missing dependencies. Please run setup-dependencies.sh and then try again" - exit 4 + exit 4 fi echo -n "Creating docker containers..." @@ -108,7 +115,7 @@ res=$(expr $res + $?) echo -n "Cleaning containers if any..." httpd_remove > /dev/null 2>&1 tomcat_all_remove > /dev/null 2>&1 -echo " Done" +echo " Done" if [ $res -eq 0 ]; then echo "Tests finished successfully!" @@ -117,4 +124,20 @@ else res=1 fi +if [ $CODE_COVERAGE ]; then + echo "Generating test coverage..." + MPC_CONF=httpd/mod_lbmethod_cluster.conf httpd_start > /dev/null 2>&1 + docker exec $MPC_NAME mkdir -p /coverage + + for f in coverage/*.json coverage/*.info; do + [ -e "$f" ] && docker cp $f $MPC_NAME:/coverage/ > /dev/null + done + + docker exec $MPC_NAME sh -c 'cd /native && gcovr --gcov-ignore-parse-errors=negative_hits.warn_once_per_file --add-tracefile "/coverage/coverage-*.json" --txt /coverage/test-coverage.txt --html-details /coverage/test-coverage.html > /coverage/test-coverage.log 2>&1' + docker exec $MPC_NAME sh -c 'cd /coverage && mkdir -p lcov && genhtml --ignore-errors negative,empty *.info --output-directory lcov > /coverage/lcov/test-coverage-lcov.log 2>&1' + docker cp $MPC_NAME:/coverage/ . > /dev/null + + httpd_remove > /dev/null 2>&1 +fi + exit $res From d60c8a8aba329b58bb8019902bc1874b7b2e6f98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Chlup?= Date: Thu, 27 Aug 2026 11:22:17 +0200 Subject: [PATCH 3/5] Add code coverage support to CMakeLists.txt --- native/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index c2fe9168..2c3ce4f2 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -17,6 +17,12 @@ ELSE() SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -p -O1 -std=gnu99 -fPIC -Wall -Wextra") ENDIF() +OPTION(ENABLE_COVERAGE "Enable code coverage instrumentation" OFF) +IF(ENABLE_COVERAGE) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage -O0 -g -fprofile-update=atomic") + SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} --coverage") +ENDIF() + SET(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/modules) SET(PROJECT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include) SET(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules ${CMAKE_MODULE_PATH}) From e0144a62af3a105eef2e375ceb09741b627150e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Chlup?= Date: Thu, 27 Aug 2026 11:22:41 +0200 Subject: [PATCH 4/5] Add coverage files to gitignore --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 1dfff7a0..574e5b8b 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,12 @@ test/httpd/mod_proxy_cluster # Log files **/*.log +# Coverage files +test/coverage/ +*.gcno +*.gcda +*.gcov + # build files *.slo *.so From c317291de1d25dcbee3e0fbce4a7a2d48a024ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Chlup?= Date: Thu, 27 Aug 2026 11:23:12 +0200 Subject: [PATCH 5/5] ci: Enable code coverage by default, preserve its output --- .github/workflows/ci.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14c02f22..8ea2abd6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,14 @@ on: - "off" default: "on" + code-coverage: + description: "Test code coverage is gathered when on" + type: choice + options: + - "on" + - "off" + default: "on" + forever-pause: description: "Length of a period during which tomcats are run and stopped (MODCLUSTER-736 test)" type: number @@ -305,6 +313,7 @@ jobs: FOREVER_PAUSE: ${{ inputs.forever-pause || 100 }} ITERATION_COUNT: ${{ inputs.iteration-count || 2 }} TOMCAT_CYCLE_COUNT: ${{ inputs.tomcat-cycle-count || 2 }} + CODE_COVERAGE: ${{ inputs.code-coverage || 'on' }} steps: - name: Checkout uses: actions/checkout@v6 @@ -342,6 +351,17 @@ jobs: path: | test/logs/* retention-days: 7 + - name: Print the coverage summary + if: ${{ env.CODE_COVERAGE == 'on' }} + run: cat test/coverage/test-coverage.txt + # Preserve coverage data if defined + - name: Preserve coverage files + if: ${{ env.CODE_COVERAGE == 'on' }} + uses: actions/upload-artifact@v4 + with: + name: Coverage ${{ matrix.os }} + path: test/coverage/* + retention-days: 7 perl-tests: runs-on: ubuntu-latest