diff --git a/.github/actions/prepare-test-environment/action.yml b/.github/actions/prepare-test-environment/action.yml new file mode 100644 index 00000000..96ca9676 --- /dev/null +++ b/.github/actions/prepare-test-environment/action.yml @@ -0,0 +1,50 @@ +name: Prepare the test environment +description: Install and setup dependencies and load the container images built by build-test-containers + +inputs: + os: + description: Runner OS, selects which test-containers artifact to download + default: ubuntu-latest + extra-packages: + description: Additional apt packages the testsuite needs + default: '' + +runs: + using: composite + steps: + - name: Setup dependencies + shell: bash + run: | + sudo apt-get update -y + sudo apt-get install -y podman-docker zstd ${{ inputs.extra-packages }} + sudo touch /etc/containers/nodocker + + - name: Create the testsuite network + shell: bash + run: docker network create mod_proxy_cluster_testsuite_net > /dev/null 2>&1 || true + + - name: Configure Podman logging driver + shell: bash + run: | + mkdir -p ~/.config/containers + cat < ~/.config/containers/containers.conf + [containers] + log_driver = "k8s-file" + + [engine] + events_logger = "file" + EOF + + - name: Get the test images built + uses: actions/download-artifact@v8 + with: + name: test-containers-${{ inputs.os }} + path: /tmp + + - name: Load the test images + shell: bash + run: | + for img in /tmp/*.tar.zst; do + echo "Loading $img image" + zstd -dc "$img" | docker load + done diff --git a/.github/workflows/ci-ignored-workaround.yml b/.github/workflows/ci-ignored-workaround.yml index 4f35e429..509b73c0 100644 --- a/.github/workflows/ci-ignored-workaround.yml +++ b/.github/workflows/ci-ignored-workaround.yml @@ -12,42 +12,10 @@ on: - 'LICENSE' jobs: - cmake-fedora-latest: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - compiler: [ gcc, clang ] - steps: - - name: Skip - run: echo "Skipping the job" - - clang-format-style-check: - runs-on: ubuntu-latest - steps: - - name: Skip - run: echo "Skipping the job" - clang-tidy-naming-check: + gather-results: runs-on: ubuntu-latest steps: - name: Skip run: echo "Skipping the job" - make-fedora-latest: - runs-on: ubuntu-latest - steps: - - name: Skip - run: echo "Skipping the job" - - tests: - runs-on: ubuntu-latest - steps: - - name: Skip - run: echo "Skipping the job" - - perl-tests: - runs-on: ubuntu-latest - steps: - - name: Skip - run: echo "Skipping the job" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d981f5e4..8b83a728 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,12 @@ on: debug: description: "Test logs are generated when on" type: choice + options: [ "on", "off" ] + default: "on" + + code-coverage: + description: "Test code coverage is gathered when on" + type: choice options: - "on" - "off" @@ -37,10 +43,31 @@ on: type: number default: 2 + mod_proxy_cluster: + description: "mod_proxy_cluster tests are executed" + type: choice + options: [ "on", "off" ] + default: "on" + + balancer: + description: "mod_proxy_balancer tests are executed" + type: choice + options: [ "on", "off" ] + default: "on" + +env: + IMG: local-tomcat + HTTPD_IMG: local-httpd + DEBUG: ${{ inputs.debug || 'on' }} + FOREVER_PAUSE: ${{ inputs.forever-pause || 100 }} + ITERATION_COUNT: ${{ inputs.iteration-count || 2 }} + TOMCAT_CYCLE_COUNT: ${{ inputs.tomcat-cycle-count || 2 }} + SKIP_CONTAINER_CREATION: 'on' + CODE_COVERAGE: ${{ inputs.code-coverage || 'on' }} + jobs: cmake-fedora-latest: - name: cmake-fedora-latest runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -81,7 +108,7 @@ jobs: path: mod_proxy_cluster - name: Setup Podman run: | - sudo apt update + sudo apt-get update sudo apt-get -y install podman - name: Create container and build run: | @@ -105,17 +132,17 @@ jobs: } > Containerfile podman build . - clang-format-style-check: + clang-style-checks: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v6 with: path: mod_proxy_cluster - - name: Install clang-format + - name: Install clang-format and clang-tidy run: | sudo apt-get update - sudo apt-get install -y clang-format + sudo apt-get install -y clang-format clang-tidy apache2-dev - name: Check styles run: | code=0 @@ -132,18 +159,6 @@ jobs: rm diff.txt || true # we don't fail if the file does not exist done; exit $code - - clang-tidy-naming-check: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - path: mod_proxy_cluster - - name: Install clang-tidy - run: | - sudo apt-get update - sudo apt-get install -y clang-tidy apache2-dev - name: Check naming conventions run: | code=0 @@ -161,6 +176,7 @@ jobs: done exit $code + make-httpd-maintainer-mode: runs-on: ubuntu-latest strategy: @@ -210,17 +226,15 @@ jobs: path: httpd/srclib/apr - name: Install necessary packages run: | - ls sudo apt-get update sudo apt-get install gcc cmake make libtool libtool-bin python3 autoconf libxml2-dev libpcre2-dev -y - name: Build httpd run: | - ls export "APACHE_DIR=/usr/local/apache2/" cd httpd ./buildconf ./configure --prefix=/usr/local/apache2 --with-included-apr --enable-proxy-ajp --enable-maintainer-mode \ - --enable-so --enable-proxy --enable-proxy-http --enable-proxy-wstunned --enable-proxy-hcheck \ + --enable-so --enable-proxy --enable-proxy-http --enable-proxy-wstunnel --enable-proxy-hcheck \ --with-port=8090 sudo make sudo make install @@ -228,7 +242,6 @@ jobs: env: CFLAGS: "-Wall -Werror" run: | - ls cd mod_proxy_cluster/native for module in advertise/ mod_proxy_cluster/ balancers/ mod_manager/; do \ cd $module; \ @@ -239,12 +252,6 @@ jobs: sudo cp *.so /usr/local/apache2/modules; \ cd ..; \ done; - - name: Preserve built Apache for perl-test job - uses: actions/upload-artifact@v6 - with: - name: apache-trunk - path: /usr/local/apache2 - retention-days: 0 cmake-windows-latest: runs-on: ${{ matrix.os }} @@ -289,22 +296,17 @@ jobs: if: always() with: name: Windows logs for ${{ matrix.os }} - path: C:\Apache24\logs\ + path: C:\Apache24\logs\*log retention-days: 7 - tests: + # Both testsuites run against this one image, so that they exercise the very same + # binaries and the coverage they gather can be merged (see the merged-coverage job). + build-test-containers: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - os: [ ubuntu-latest, ubuntu-24.04-arm ] - env: - IMG: local-tomcat - HTTPD_IMG: local-httpd - DEBUG: ${{ inputs.debug || 'on' }} - FOREVER_PAUSE: ${{ inputs.forever-pause || 100 }} - ITERATION_COUNT: ${{ inputs.iteration-count || 2 }} - TOMCAT_CYCLE_COUNT: ${{ inputs.tomcat-cycle-count || 2 }} + os: [ ubuntu-latest, ubuntu-24.04-arm ] steps: - name: Checkout uses: actions/checkout@v6 @@ -316,67 +318,156 @@ jobs: - name: Setup dependencies run: | sudo apt-get update -y - sudo apt-get install -y podman-docker maven git curl iproute2 wcstools + sudo apt-get install -y podman-docker maven git curl iproute2 wcstools zstd sudo touch /etc/containers/nodocker cd test sh setup-dependencies.sh - - name: Configure Podman logging driver + - name: Build the test images + run: | + cd test + . includes/common.sh + test_create_all_containers + for img in $(docker image ls --format "{{.Repository}}:{{.Tag}}" | sed 's|^localhost/||'); do + if [[ "$img" != "$IMG"* ]] && [[ "$img" != "$HTTPD_IMG"* ]]; then continue; fi + echo "Saving $img image" + docker save $img | zstd -T0 -o /tmp/$(echo $img | sed 's|:|-|').tar.zst + done + - name: Preserve the test images + uses: actions/upload-artifact@v6 + with: + name: test-containers-${{ matrix.os }} + path: /tmp/*.tar.zst + retention-days: 1 + # the tests themselves need these, they don't run setup-dependencies.sh + - name: Preserve the test dependencies + uses: actions/upload-artifact@v6 + with: + name: test-dependencies-${{ matrix.os }} + path: | + test/websocket/websocket-hello-0.0.1.war + test/includes/target/test-1.0.jar + retention-days: 1 + + test-extra: + name: test-extra (${{ matrix.os }}, ${{ matrix.test.name }}) + runs-on: ${{ matrix.os }} + needs: build-test-containers + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, ubuntu-24.04-arm ] + # these tests take a lot of time, that's why we keep them separate + test: + - name: MODCLUSTER-736 + script: MODCLUSTER-736/testit.sh + + - name: Hanging tests + script: hangingtests.sh + steps: + - name: Checkout + uses: actions/checkout@v6 + - name: Setup podman and load the test images + uses: ./.github/actions/prepare-test-environment + with: + os: ${{ matrix.os }} + extra-packages: git curl iproute2 wcstools + - name: Run ${{ matrix.test.name }} run: | - mkdir -p ~/.config/containers - cat < ~/.config/containers/containers.conf - [containers] - log_driver = "k8s-file" + cd test + mkdir logs coverage + . includes/common.sh + run_test "${{ matrix.test.script }}" "${{ matrix.test.name }}" + - name: Preserve test logs + uses: actions/upload-artifact@v6 + if: ${{ !cancelled() && env.DEBUG == 'on' }} + with: + name: ${{ matrix.test.name }} logs ${{ matrix.os }} + path: | + test/logs/* + retention-days: 7 + # Preserve coverage data if defined + - name: Preserve coverage files + if: ${{ !cancelled() && env.CODE_COVERAGE == 'on' && matrix.os == 'ubuntu-latest' }} + uses: actions/upload-artifact@v6 + with: + name: ${{ matrix.test.name }} coverage ${{ matrix.os }} + path: test/coverage/* + retention-days: 7 + - [engine] - events_logger = "file" - EOF + tests: + runs-on: ${{ matrix.os }} + needs: build-test-containers + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, ubuntu-24.04-arm ] + suite: [ mod_proxy_cluster, mod_proxy_balancer ] + env: + MOD_PROXY_CLUSTER_TESTS: ${{ matrix.suite == 'mod_proxy_cluster' && (inputs.mod_proxy_cluster || 'on') || 'off' }} + MOD_PROXY_BALANCER_TESTS: ${{ matrix.suite == 'mod_proxy_balancer' && (inputs.balancer || 'on') || 'off' }} + steps: + - name: Checkout + uses: actions/checkout@v6 + - name: Setup podman and load the test images + uses: ./.github/actions/prepare-test-environment + with: + os: ${{ matrix.os }} + extra-packages: git curl iproute2 wcstools + - name: Get the test dependencies built + uses: actions/download-artifact@v8 + with: + name: test-dependencies-${{ matrix.os }} + path: test + - name: Disable MODCLUSTER-736 and Hanging tests + run: | + cd test + sed -i '/MODCLUSTER-736/s|^|#|' testsuite.sh + sed -i '/Hanging tests/s|^|#|' testsuite.sh - name: Run testsuite run: | cd test sh testsuite.sh - name: Preserve test logs uses: actions/upload-artifact@v6 - if: ${{ env.DEBUG == 'on' }} + if: ${{ !cancelled() && env.DEBUG == 'on' }} with: - name: Test logs ${{ matrix.os }} + name: Test logs ${{ matrix.os }} ${{ matrix.suite }} path: | test/logs/* retention-days: 7 + - name: Print the coverage summary + if: ${{ !cancelled() && env.CODE_COVERAGE == 'on' }} + run: cat test/coverage/test-coverage.txt + # Preserve coverage data if defined + - name: Preserve coverage files + if: ${{ !cancelled() && env.CODE_COVERAGE == 'on' && matrix.os == 'ubuntu-latest' }} + uses: actions/upload-artifact@v6 + with: + name: Test coverage ${{ matrix.os }} ${{ matrix.suite }} + path: test/coverage/* + retention-days: 7 perl-tests: runs-on: ubuntu-latest - needs: make-with-httpd-trunk + needs: build-test-containers + env: + PERL_IMG: local-perl-tests steps: - name: Checkout uses: actions/checkout@v6 - - name: Setup dependencies - run: | - sudo apt-get update - sudo apt-get remove apache2* - sudo apt-get install -y gcc make perl cpanminus libcrypt-ssleay-perl - - name: Get Apache built in the previous job - uses: actions/download-artifact@v7 - with: - name: apache-trunk - path: apache2 - - name: Put httpd on the right path - run: | - mkdir test-perl/t/modules/ - cp apache2/modules/{mod_proxy_cluster.so,mod_manager.so,mod_advertise.so,mod_lbmethod_cluster.so} test-perl/t/modules/ - sudo mv apache2/ /usr/local/apache2/ - sudo chmod -R 755 /usr/local/apache2/ - - name: Install perl modules - run: | - sudo cpanm --force Apache::Test Apache::TestMM HTTP::Request LWP::UserAgent + - name: Setup podman and load the test images + uses: ./.github/actions/prepare-test-environment + - name: Build the perl testsuite image + run: docker build -t $PERL_IMG --build-arg HTTPD_IMG=$HTTPD_IMG -f test-perl/Containerfile test-perl/ - name: Run testsuite run: | - cd test-perl - perl Makefile.PL -httpd /usr/local/apache2/bin/httpd - make - t/TEST -httpd /usr/local/apache2/bin/httpd 2>&1 | tee test-perl.log - mv test-perl.log t/logs/test-perl.log - grep "Result: PASS" -q t/logs/test-perl.log - exit $? + if [ "$CODE_COVERAGE" = "on" ]; then coverage_env="-e ENABLE_COVERAGE=1"; fi + docker run --name perl-tests $coverage_env $PERL_IMG + # now get the logs and coverage + mkdir -p test-perl/t/logs test-perl/coverage + docker cp perl-tests:/test-perl/t/logs/. test-perl/t/logs/ || true + docker cp perl-tests:/coverage/. test-perl/coverage/ || true - name: Preserve test logs uses: actions/upload-artifact@v6 if: always() @@ -385,6 +476,16 @@ jobs: path: | test-perl/t/logs/* retention-days: 7 + - name: Print the coverage summary + if: ${{ !cancelled() && env.CODE_COVERAGE == 'on' }} + run: cat test-perl/coverage/test-coverage.txt + - name: Preserve coverage files + if: ${{ !cancelled() && env.CODE_COVERAGE == 'on' }} + uses: actions/upload-artifact@v6 + with: + name: Perl tests coverage + path: test-perl/coverage/* + retention-days: 7 doxygen: runs-on: ubuntu-latest @@ -403,3 +504,79 @@ jobs: name: Doxygen docs path: doxygen-out/html/* retention-days: 30 + + gather-results: + runs-on: ubuntu-latest + if: always() + needs: + - tests + - perl-tests + - test-extra + - clang-style-checks + - cmake-fedora-latest + - cmake-windows-latest + - make-httpd-maintainer-mode + - make-fedora-latest + - make-with-httpd-trunk + - doxygen + steps: + # Check that all the needs jobs were successful + - name: Check the results of all the jobs + if: always() + run: | + results="${{ join(needs.*.result, ' ') }}" + echo "Job results: $results" + for result in $results; do + if [ "$result" != "success" ]; then + echo "At least one job did not succeed" + exit 1 + fi + done + # the checkout is only here so that the local action below can be used + - name: Checkout + uses: actions/checkout@v6 + # we need the httpd/mod_proxy_cluster image to merge the coverage reports + - name: Setup podman and load the test images + if: ${{ env.CODE_COVERAGE == 'on' }} + uses: ./.github/actions/prepare-test-environment + - name: Get all the coverage reports + if: ${{ env.CODE_COVERAGE == 'on' }} + uses: actions/download-artifact@v8 + with: + pattern: '*coverage*' + path: coverage + merge-multiple: true + - name: Get all the coverage files + if: ${{ env.CODE_COVERAGE == 'on' }} + run: | + rm -rf coverage/lcov coverage/test-coverage.* + docker run --rm -v $PWD/coverage:/coverage $HTTPD_IMG \ + /native/scripts/coverage.sh report /coverage + - name: Print the full coverage summary + if: ${{ env.CODE_COVERAGE == 'on' }} + run: cat coverage/test-coverage.txt + - name: Delete all the artifacts we no longer need + uses: geekyeggo/delete-artifact@v6 + with: + name: | + test-containers* + test-dependencies* + *coverage* + failOnError: false + # First delete the individual coverage archives, then create a final report + - name: Preserve coverage files + if: ${{ env.CODE_COVERAGE == 'on' }} + uses: actions/upload-artifact@v6 + with: + name: Test coverage + path: coverage/* + retention-days: 14 + - name: Merge all the logs + uses: actions/upload-artifact/merge@v6 + with: + name: Test logs + pattern: '*logs*' + separate-directories: true + delete-merged: true + retention-days: 14 + diff --git a/.gitignore b/.gitignore index 1dfff7a0..cd8da86e 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,13 @@ test/httpd/mod_proxy_cluster # Log files **/*.log +# Coverage files +test/coverage/ +test-perl/coverage/ +*.gcno +*.gcda +*.gcov + # build files *.slo *.so 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}) diff --git a/native/scripts/coverage.sh b/native/scripts/coverage.sh new file mode 100755 index 00000000..a8372fb3 --- /dev/null +++ b/native/scripts/coverage.sh @@ -0,0 +1,94 @@ +#!/usr/bin/sh +# Collects code coverage of the modules built with -DENABLE_COVERAGE=ON. +# +# coverage.sh capture gather the counters dumped so far +# coverage.sh report merge the gathered tracefiles into reports +# +# "capture" produces the coverage-.json and coverage-.info tracefiles, +# "report" merges every tracefile within the output directory into test-coverage.txt, +# test-coverage.html and lcov/index.html. +# +# The httpd instance under test has to be stopped before capturing, otherwise gcov +# has not dumped its counters yet and there is nothing to collect. +# +# The location of the sources is derived from the location of this script, override +# it with the NATIVE variable if needed. +# +# exits with 0 if the data were collected +# exits with 1 if there is nothing to collect +# exits with 2 when used incorrectly +# exits with 3 if one of the coverage tools failed + +NATIVE=${NATIVE:-$(cd -- "$(dirname -- "$0")/.." && pwd)} + +# gcovr is always given --root so that the paths within the tracefiles stay relative +# to native/. That keeps tracefiles captured from different runs (and even on +# different machines) mergeable. Mind that gcovr reads its own tracefiles only when +# they were written by the very same version, so all the jobs have to agree on one. +GCOVR="gcovr --gcov-ignore-parse-errors=negative_hits.warn_once_per_file --root $NATIVE" + +# Prints the given message and gives up +fail() { + echo "$1" + exit 3 +} + +capture() { + name=$1 + out=$2 + + if [ -z "$(find $NATIVE -name '*.gcda' 2> /dev/null)" ]; then + echo "No coverage data found in $NATIVE, is httpd stopped?" + return 1 + fi + + mkdir -p $out + $GCOVR --json $out/coverage-$name.json > $out/coverage-$name.log 2>&1 \ + || fail "gcovr failed to capture $name, see $out/coverage-$name.log" + # lcov is confined to our sources the same way gcovr is by --root, otherwise the + # httpd headers end up in the report as well (wherever they happen to live) + lcov --capture --directory $NATIVE/build --ignore-errors gcov,negative \ + --include "$NATIVE/*" --output-file $out/coverage-$name.info \ + > $out/coverage-lcov-$name.log 2>&1 \ + || fail "lcov failed to capture $name, see $out/coverage-lcov-$name.log" +} + +report() { + out=$1 + + if [ -z "$(ls $out/coverage-*.json 2> /dev/null)" ]; then + echo "No tracefiles to report on within $out." + return 1 + fi + + mkdir -p $out/lcov + # the glob is quoted on purpose, it is gcovr who expands it + $GCOVR --add-tracefile "$out/coverage-*.json" \ + --txt $out/test-coverage.txt --html-details $out/test-coverage.html \ + > $out/test-coverage.log 2>&1 \ + || fail "gcovr failed to merge the tracefiles, see $out/test-coverage.log" + # unlike gcovr, lcov records absolute paths, so they are pointed back at these + # sources; that is a no-op for the tracefiles captured here and it is what makes + # the ones captured elsewhere merge (and render) instead of piling up side by side + sed -i "s|^SF:.*/native/|SF:$NATIVE/|" $out/coverage-*.info + genhtml --ignore-errors negative,empty $out/coverage-*.info \ + --output-directory $out/lcov > $out/lcov/test-coverage-lcov.log 2>&1 \ + || fail "genhtml failed, see $out/lcov/test-coverage-lcov.log" +} + +usage() { + echo "usage: $0 capture " + echo " $0 report " + exit 2 +} + +case "$1" in +capture) + if [ -z "$2" ] || [ -z "$3" ]; then usage; fi + capture "$2" "$3";; +report) + if [ -z "$2" ]; then usage; fi + report "$2";; +*) + usage;; +esac diff --git a/test-perl/Containerfile b/test-perl/Containerfile new file mode 100644 index 00000000..ad984b8a --- /dev/null +++ b/test-perl/Containerfile @@ -0,0 +1,32 @@ +# Runs the Apache::Test testsuite against the very same image the container testsuite +# uses. Building on top of it is what makes the code coverage of the two mergeable: +# the modules are the ones compiled there, so the compiler, the httpd headers and the +# paths recorded in the coverage data all agree. +# +# Pass the image to build upon with --build-arg HTTPD_IMG=. + +ARG HTTPD_IMG=mod_proxy_cluster-testsuite-httpd + +FROM ${HTTPD_IMG} + +RUN dnf install make perl perl-App-cpanminus perl-ExtUtils-MakeMaker \ + perl-libwww-perl perl-LWP-Protocol-https perl-HTTP-Message \ + perl-Crypt-SSLeay -y + +# Apache::Test is not packaged by Fedora, so this one has to come from CPAN +# (LWP::Protocol::https above is what lets cpanm reach it) +RUN cpanm --force Apache::Test Apache::TestMM + +# Apache::Test refuses to spawn the httpd children as root, so everything it touches +# is handed over to a plain user. That includes the build tree, because the .gcda +# files are written next to the objects the modules were compiled from. +RUN useradd --create-home tester && mkdir /coverage \ + && chown -R tester:tester /native /coverage + +COPY --chown=tester:tester . /test-perl + +USER tester + +WORKDIR /test-perl + +CMD /test-perl/run.sh diff --git a/test-perl/run.sh b/test-perl/run.sh new file mode 100755 index 00000000..f38d5bf4 --- /dev/null +++ b/test-perl/run.sh @@ -0,0 +1,32 @@ +#!/usr/bin/sh +# Entrypoint of the perl testsuite image. +# It uses the contaniner image from test/ testsuite. +# Runs it and gathers the code coverage when the underlying container has ENABLE_COVERAGE set to 1 +# +# The test log ends up in t/logs/test-perl.log and the coverage data in /coverage. +# +# exits with 0 if every test passed + +HTTPD=/usr/local/apache2/bin/httpd + +# Apache::Test puts the ServerRoot at t/, so every module the generated config loads +# has to be found in t/modules -- the httpd ones included. Ours are symlinked among +# them by the image, cp resolves that for us. +mkdir -p t/modules +cp /usr/local/apache2/modules/*.so t/modules/ || exit 1 + +perl Makefile.PL -httpd $HTTPD || exit 1 +make || exit 1 + +t/TEST -httpd $HTTPD 2>&1 | tee test-perl.log +mv test-perl.log t/logs/test-perl.log +grep -q "Result: PASS" t/logs/test-perl.log +res=$? + +# t/TEST stops httpd on its own, so the counters are already dumped by now +if [ "$ENABLE_COVERAGE" = "1" ]; then + /native/scripts/coverage.sh capture perl-tests /coverage \ + && /native/scripts/coverage.sh report /coverage +fi + +exit $res diff --git a/test-perl/t/conf/extra.conf.in b/test-perl/t/conf/extra.conf.in index b2d403c5..3b0ca8fe 100644 --- a/test-perl/t/conf/extra.conf.in +++ b/test-perl/t/conf/extra.conf.in @@ -1,3 +1,7 @@ + + LoadModule watchdog_module modules/mod_watchdog.so + + LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule proxy_hcheck_module modules/mod_proxy_hcheck.so diff --git a/test/MODCLUSTER-736/testit.sh b/test/MODCLUSTER-736/testit.sh index d2248669..964c37cd 100644 --- a/test/MODCLUSTER-736/testit.sh +++ b/test/MODCLUSTER-736/testit.sh @@ -25,34 +25,22 @@ runtomcatbatch() { MPC_NAME=MODCLUSTER-736 tomcat_start $i done - tomcat_count=$(expr 3 + 11 - $t) - tomcat_wait_for_n_nodes $tomcat_count || exit 1 + tomcat_count=$(( 3 + 11 - $t )) + tomcat_wait_for_n_nodes $tomcat_count for i in $(seq $t 10); do - tomcat_start_webapp $i || exit 1 + tomcat_start_webapp $i done # test the tomcats sleep 20 tomcat_all_test_app $tomcat_count - if [ $? -ne 0 ]; then - echo "runtomcatbatch tomcat_all_test_app $tomcat_count FAILED!" - exit 1 - fi # "load test" 9 of them tomcat_all_run_ab $tomcat_count - if [ $? -ne 0 ]; then - echo "runtomcatbatch tomcat_all_run_ab $tomcat_count FAILED!" - exit 1 - fi # retest tomcat_all_test_app $tomcat_count - if [ $? -ne 0 ]; then - echo "runtomcatbatch tomcat_all_test_app $tomcat_count FAILED!" - exit 1 - fi # stop the tomcats for i in $(seq $t 10); @@ -61,10 +49,6 @@ runtomcatbatch() { done tomcat_wait_for_n_nodes 3 - if [ $? -ne 0 ]; then - echo "runtomcatbatch tomcat_wait_for_n_nodes 3 FAILED!" - exit 1 - fi # remove the tomcats for i in $(seq $t 10); @@ -79,7 +63,7 @@ runtomcatbatch() { singlecycle() { echo "singlecycle: Testing tomcat$1" R=$1 - MPC_NAME=MODCLUSTER-736 tomcat_start $1 || exit 1 + MPC_NAME=MODCLUSTER-736 tomcat_start $1 # Wait for it to start echo "Testing(0) tomcat$1 waiting..." @@ -94,11 +78,11 @@ singlecycle() { echo "Timeout: tomcat$1 is not ready" exit 1 fi - i=$(expr $i + 1) + i=$(( $i + 1 )) sleep 1 done echo "Testing(0) tomcat$1 started" - tomcat_start_webapp $1 || exit 1 + tomcat_start_webapp $1 echo "Testing(0) tomcat$1 with webapp" i=0 while true @@ -112,14 +96,14 @@ singlecycle() { echo "Timeout: webapp on tomcat$1 is not ready after 300 seconds" exit 1 fi - i=$(expr $i + 1) + i=$(( $i + 1 )) sleep 1 done echo "Testing(1) tomcat$1" - tomcat_test_app $1 || exit 1 + tomcat_test_app $1 echo "Testing(2) tomcat$1" - tomcat_test_app $1 || exit 1 - tomcat_run_ab $1 || exit 1 + tomcat_test_app $1 + tomcat_run_ab $1 echo "Testing(3) tomcat$1" tomcat_shutdown $1 || exit 1 while true @@ -132,7 +116,7 @@ singlecycle() { echo "Timeout: webapp is still present on tomcat$1 after 300 seconds" exit 1 fi - i=$(expr $i + 1) + i=$(( $i + 1 )) sleep 1 done tomcat_remove $1 || exit 1 @@ -143,7 +127,7 @@ singlecycle() { looptomcatforever() { while true do - singlecycle $1 || exit 1 + singlecycle $1 done } @@ -177,14 +161,16 @@ forevertomcat() { tomcat_remove_by_name tomcat14 tomcat_remove_by_name tomcat15 tomcat_remove_by_name tomcat16 - sleep 10 + # the nodes have to be gone from the manager, otherwise the following + # tomcat_wait_for_n_nodes calls would be satisfied by these leftovers + tomcat_wait_for_n_nodes 0 } # Start and stop successively (one after another) $1 tomcats cyclestomcats() { for i in $(seq 1 $1); do echo -n "$i/$1: " - singlecycle $i || exit 1 + singlecycle $i done echo "Looks OK, Done!" } @@ -196,77 +182,44 @@ runmodcluster736() { MPC_NAME=MODCLUSTER-736 tomcat_start 2 MPC_NAME=MODCLUSTER-736 tomcat_start 3 MPC_NAME=MODCLUSTER-736 tomcat_start 4 - tomcat_wait_for_n_nodes 3 || exit 1 + tomcat_wait_for_n_nodes 3 # check them - tomcat_start_webapp 2 || exit 1 - tomcat_start_webapp 3 || exit 1 - tomcat_start_webapp 4 || exit 1 + tomcat_start_webapp 2 + tomcat_start_webapp 3 + tomcat_start_webapp 4 sleep 20 - tomcat_test_app 2 || exit 1 - tomcat_test_app 3 || exit 1 - tomcat_test_app 4 || exit 1 + tomcat_test_app 2 + tomcat_test_app 3 + tomcat_test_app 4 # start a bunch of tomcats, test, shutdown, remove and try in a loop. runmodcluster736=0 while true do - runmodcluster736=$(expr $runmodcluster736 + 1) + runmodcluster736=$(( $runmodcluster736 + 1 )) if [ $runmodcluster736 -gt 2 ]; then echo "Looks OK, runmodcluster736 stopping!" break fi # cycle the tomcats runtomcatbatch - - if [ $? -ne 0 ]; then - echo "runtomcatbatch: runmodcluster736 Failed!" - exit 1 - fi tomcat_shutdown 2 tomcat_wait_for_n_nodes 2 - if [ $? -ne 0 ]; then - echo "tomcat_wait_for_n_nodes 2: runmodcluster736 Failed!" - exit 1 - fi tomcat_remove 2 MPC_NAME=MODCLUSTER-736 tomcat_start 5 tomcat_wait_for_n_nodes 3 - if [ $? -ne 0 ]; then - echo "tomcat_wait_for_n_nodes 3: runmodcluster736 Failed!" - exit 1 - fi tomcat_start_webapp 5 - if [ $? -ne 0 ]; then - echo "tomcat_start_webapp 5: runmodcluster736 Failed!" - exit 1 - fi sleep 20 tomcat_test_app 5 - if [ $? -ne 0 ]; then - echo "tomcat_test_app 5: runmodcluster736 Failed!" - exit 1 - fi # we have 5 3 4 in shared memory # read 2 MPC_NAME=MODCLUSTER-736 tomcat_start 2 tomcat_wait_for_n_nodes 4 - if [ $? -ne 0 ]; then - echo "tomcat_wait_for_n_nodes 4: runmodcluster736 Failed!" - exit 1 - fi tomcat_start_webapp 2 - if [ $? -ne 0 ]; then - echo "tomcat_start_webapp 2: runmodcluster736 Failed!" - exit 1 - fi sleep 20 tomcat_test_app 2 - if [ $? -ne 0 ]; then - echo "tomcat_test_app 2: runmodcluster736 Failed!" - exit 1 - fi sleep 20 @@ -275,29 +228,11 @@ runmodcluster736() { tomcat_shutdown 5 tomcat_wait_for_n_nodes 3 - if [ $? -ne 0 ]; then - echo "tomcat_wait_for_n_nodes 3: runmodcluster736 Failed!" - exit 1 - fi tomcat_remove 5 tomcat_test_app 2 - if [ $? -ne 0 ]; then - echo "tomcat_test_app 2: runmodcluster736 Failed!" - exit 1 - fi - tomcat_test_app 3 - if [ $? -ne 0 ]; then - echo "tomcat_test_app 3: runmodcluster736 Failed!" - exit 1 - fi - tomcat_test_app 4 - if [ $? -ne 0 ]; then - echo "tomcat_test_app 4: runmodcluster736 Failed!" - exit 1 - fi echo "runmodcluster736 loop: $runmodcluster736 DONE" done @@ -305,7 +240,7 @@ runmodcluster736() { tomcat_shutdown 4 tomcat_shutdown 3 tomcat_shutdown 2 - tomcat_wait_for_n_nodes 0 || exit 1 + tomcat_wait_for_n_nodes 0 tomcat_remove 2 tomcat_remove 3 tomcat_remove 4 @@ -314,16 +249,8 @@ runmodcluster736() { # MODCLUSTER-736 echo "Testing MODCLUSTER-736" cyclestomcats ${TOMCAT_CYCLE_COUNT:-10} -if [ $? -ne 0 ]; then - echo "MODCLUSTER-736 cyclestomcats 100 FAILED!" - exit 1 -fi echo "cycletomcats DONE" forevertomcat -if [ $? -ne 0 ]; then - echo "MODCLUSTER-736 forevertomcat FAILED!" - exit 1 -fi echo "forevertomcat DONE" runmodcluster736 if [ $? -ne 0 ]; then diff --git a/test/MODCLUSTER-755/testit.sh b/test/MODCLUSTER-755/testit.sh index 9fe7c726..f9aae7cc 100755 --- a/test/MODCLUSTER-755/testit.sh +++ b/test/MODCLUSTER-755/testit.sh @@ -33,7 +33,7 @@ if [ "x$USE_MULTI_APP" = "xtrue" ]; then echo "The webapp are going to be 1-9000/2-9000 until count (1-9499/2-9499)" fi -for i in $(seq 9000 $(expr 9000 + $NODE_COUNT - 1)) +for i in $(seq 9000 $(( 9000 + $NODE_COUNT - 1 ))) do curl $HTTPD -H "User-Agent: ClusterListener/1.0" -X CONFIG --data "JVMRoute=appserver$i&Host=127.0.0.1&Maxattempts=1&Port=$i&StickySessionForce=No&Timeout=20&Type=ajp&ping=20" curl $HTTPD -H "User-Agent: ClusterListener/1.0" -X STATUS --data "JVMRoute=appserver$i&Load=100" @@ -51,7 +51,7 @@ done i=0 while [ true ] do - for i in $(seq 9000 $(expr 9000 + $NODE_COUNT - 1)) + for i in $(seq 9000 $(( 9000 + $NODE_COUNT - 1 ))) do curl $HTTPD -H "User-Agent: ClusterListener/1.0" -X STATUS --data "JVMRoute=appserver$i&Load=100" if [ $? -ne 0 ]; then @@ -60,7 +60,7 @@ do fi done sleep 10 - i=$(expr $i + 1) + i=$(( $i + 1 )) if [ $i -gt 100 ]; then break fi diff --git a/test/MODCLUSTER-785/testit.sh b/test/MODCLUSTER-785/testit.sh index f6dbf214..9871b2b2 100755 --- a/test/MODCLUSTER-785/testit.sh +++ b/test/MODCLUSTER-785/testit.sh @@ -67,7 +67,7 @@ do if [ ${http_code} = 200 ]; then break fi - i=$(expr $i + 1) + i=$(( $i + 1 )) if [ $i -gt 60 ]; then break fi @@ -92,7 +92,7 @@ do echo "MODCLUSTER-785 Failed! return 503" exit 1 fi - i=$(expr $i + 1) + i=$(( $i + 1 )) if [ $i -gt 60 ]; then break fi diff --git a/test/basetests.sh b/test/basetests.sh index 3ea5e1fc..fdd36154 100644 --- a/test/basetests.sh +++ b/test/basetests.sh @@ -45,7 +45,7 @@ do tomcat_shutdown 1 tomcat_wait_for_n_nodes 0 || exit 1 tomcat_remove 1 - iter=$(expr $iter + 1) + iter=$(( $iter + 1 )) done tomcat_all_remove diff --git a/test/httpd/Containerfile b/test/httpd/Containerfile index 31d117e6..cc6c5ccd 100644 --- a/test/httpd/Containerfile +++ b/test/httpd/Containerfile @@ -1,15 +1,12 @@ FROM fedora:44 AS builder ARG HTTPD_SOURCES="https://dlcdn.apache.org/httpd/httpd-2.4.69.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} -# make sure you have copy of the local repository at place -# (our function "httpd_create" takes care of that) -COPY mod_proxy_cluster / - ADD ${HTTPD} . RUN mkdir /httpd && tar xvf $(filename $HTTPD) --strip 1 -C /httpd @@ -26,20 +23,20 @@ RUN make install # we don't need any other listeners except the ones we define in our config files RUN sed -i 's/\(Listen 80\)/#\1/' /usr/local/apache2/conf/httpd.conf +# the sources come in only now so that a change in them does not invalidate the layers +# above, the httpd build in particular +# +# make sure you have copy of the local repository at place +# (our function "httpd_create" takes care of that) +COPY mod_proxy_cluster / + # 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 +44,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 lcov gcovr -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/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/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..f1a86b25 100644 --- a/test/includes/common.sh +++ b/test/includes/common.sh @@ -8,27 +8,41 @@ MPC_NAME=${MPC_NAME:-httpd-mod_proxy_cluster} run_test() { local ret=0 if [ ! -z "$2" ]; then - printf "Running %-42s ..." "$2" + printf "Running %-64s ..." "$2" else - printf "Running %-42s ..." "$1" + printf "Running %-64s ..." "$1" fi if is_enabled "$DEBUG"; then - sh $1 > "logs/${2:-$1}.log" 2>&1 + sh $1 > "logs/${2:-$1}.log" 2>&1 || ret=$? else - sh $1 > /dev/null 2>&1 + sh $1 > /dev/null 2>&1 || ret=$? fi - if [ $? = 0 ]; then + if [ $ret = 0 ]; then echo " OK" else 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} sh -c "/usr/local/apache2/bin/apachectl stop" + sleep 2 # wait for the coverage dump, just to be sure + docker exec ${httpd_cont} /native/scripts/coverage.sh capture "$f" /coverage + + 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 @@ -47,6 +61,24 @@ is_enabled() { return 0 } +test_create_all_containers() { + if is_enabled "$DEBUG"; then + httpd_create || exit 2 + tomcat_create || exit 3 + else + httpd_create > /dev/null 2>&1 || exit 2 + tomcat_create > /dev/null 2>&1 || exit 3 + fi + # create all main tomcat versions for Base tests + ## IMG name might include specific version, we have to handle that + IMG_NOVER=$(echo $IMG | cut -d: -f1) + for tomcat_version in "9.0" "10.1" "11.0" + do + IMG="$IMG_NOVER:$tomcat_version" tomcat_create $tomcat_version > /dev/null 2>&1 || exit 3 + done +} + + ##################################################### ### H T T P D H E L P E R F U N C T I O N S ### ##################################################### @@ -66,7 +98,13 @@ 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/ + + local coverage_arg="" + if is_enabled "$CODE_COVERAGE"; then + coverage_arg="--build-arg ENABLE_COVERAGE=ON" + fi + + docker build -t $HTTPD_IMG $coverage_arg -f httpd/Containerfile httpd/ } # Build and run httpd container @@ -79,10 +117,16 @@ httpd_start() { echo " NAME: ${MPC_NAME:-httpd-mod_proxy_cluster}" echo "You can config those with envars MPC_SOURCES, MPC_BRANCH, MPC_CONF, MPC_NAME respectively" fi + local coverage_env="" + if is_enabled "$CODE_COVERAGE"; then + coverage_env="-e ENABLE_COVERAGE=1" + fi + docker run -d --network=mod_proxy_cluster_testsuite_net -p 8090:8090 \ --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} \ + $coverage_env \ $HTTPD_IMG httpd_wait_until_ready @@ -93,7 +137,7 @@ httpd_wait_until_ready() { curl -m 20 localhost:8090 > /dev/null 2>&1 while [ $? != 0 ]; do - i=$(expr $i + 1) + i=$(( $i + 1 )) if [ $i -gt 20 ]; then echo "$(date) Failed to run httpd container" exit 1; @@ -151,8 +195,8 @@ tomcat_start() { exit 1 fi - local DEFAULT_OFFSET=$(expr $1 - 1) - local shutport=$(expr ${SHUTDOWN_PORT:-8005} + $DEFAULT_OFFSET) + local DEFAULT_OFFSET=$(( $1 - 1 )) + local shutport=$(( ${SHUTDOWN_PORT:-8005} + $DEFAULT_OFFSET )) echo "$(date) Starting tomcat$1" nohup docker run --network=mod_proxy_cluster_testsuite_net \ @@ -182,14 +226,14 @@ tomcat_wait_for_n_nodes() { echo "$(date) httpd isn't running or something is VERY wrong" exit 1 fi - NBNODES=-1 + NBNODES=$(curl -s http://localhost:8090/mod_cluster_manager -m 20 | grep "Status: OK" | awk ' { print $3} ' | wc -l) i=0 while [ ${NBNODES} != ${nodes} ] do NBNODES=$(curl -s http://localhost:8090/mod_cluster_manager -m 20 | grep "Status: OK" | awk ' { print $3} ' | wc -l) sleep 10 echo "$(date) Waiting for $nodes node to be ready (nodes ready: $NBNODES)" - i=$(expr $i + 1) + i=$(( $i + 1 )) if [ $i -gt 60 ]; then echo "($date) Timeout! There are not $nodes nodes but $NBNODES instead" exit 1 @@ -272,7 +316,7 @@ tomcat_shutdown() { fi echo "$(date) shutting down tomcat$1" - echo "SHUTDOWN" | nc localhost $(expr ${SHUTDOWN_PORT:-8005} + $1 - 1) + echo "SHUTDOWN" | nc localhost $(( ${SHUTDOWN_PORT:-8005} + $1 - 1 )) } # Remove the docker image tomcat$1 @@ -352,7 +396,7 @@ tomcat_all_run_ab() { while true do tomcat_run_ab $tc || exit 1 - tc=$(expr $tc + 1) + tc=$(( $tc + 1 )) if [ $tc -gt $1 ]; then echo "$(date) abtomcats: Done!" break @@ -376,7 +420,7 @@ tomcat_all_test_app() { while true do tomcat_test_app $tc || exit 1 - tc=$(expr $tc + 1) + tc=$(( $tc + 1 )) if [ $tc -gt $1 ]; then echo "$(date) tomcat_tests $tc Done!" break diff --git a/test/maintests.sh b/test/maintests.sh index b909bbd4..fd67da8f 100644 --- a/test/maintests.sh +++ b/test/maintests.sh @@ -60,7 +60,7 @@ while [ "${NODE}" = "${NEWNODE}" ] do NEWCO=$(curl -v http://localhost:8090/testapp/test.jsp -m 20 -o /dev/null 2>&1 | grep Set-Cookie | awk '{ print $3 } ' | sed 's:;::') NEWNODE=$(echo ${NEWCO} | awk -F = '{ print $2 }' | awk -F . '{ print $2 }') - i=$(expr $i + 1) + i=$(( $i + 1 )) if [ $i -gt 40 ]; then echo "Can't find the 2 webapps" exit 1 @@ -90,7 +90,7 @@ echotestlabel "sticky: stopping one node and doing requests..." NODE=$(echo ${NEWCO} | awk -F = '{ print $2 }' | awk -F . '{ print $2 }') echo $NODE PORT=$(curl http://localhost:8090/mod_cluster_manager -m 20 | grep Node | grep $NODE | sed 's:)::' | awk -F : '{ print $3 } ') -NUMBER=$(expr ${PORT} - 8080 + 1) +NUMBER=$(( ${PORT} - 8080 + 1 )) CODE="200" i=0 while [ "$CODE" = "200" ] @@ -106,7 +106,7 @@ do # We're going to kill instead of removal because kill only tomcat proc (keeps the container in DNS) tomcat_kill $NUMBER fi - i=$(expr $i + 1) + i=$(( $i + 1 )) done if [ ${CODE} != "200" ]; then echo "Something was wrong... got: ${CODE}" diff --git a/test/testsuite.sh b/test/testsuite.sh index 8ef515e9..e2ba92e9 100644 --- a/test/testsuite.sh +++ b/test/testsuite.sh @@ -4,34 +4,21 @@ # exits with 2 if httpd container build failed # exits with 3 if tomcat container build failed -# configuration of variables -# if you want tests to pass much faster, decrease these values -if [ -z ${FOREVER_PAUSE+x} ]; then - export FOREVER_PAUSE=3600 # sleep period length during which tomcats are run & stopped -fi -if [ -z ${TOMCAT_CYCLE_COUNT+x} ]; then - export TOMCAT_CYCLE_COUNT=100 # the number of repetitions of a test cycle -fi -if [ -z ${ITERATION_COUNT+x} ]; then - export ITERATION_COUNT=50 # the number of iteration of starting/stopping a tomcat -fi -if [ -z ${IMG+x} ]; then - export IMG=mod_proxy_cluster-testsuite-tomcat -fi -if [ -z ${HTTPD_IMG+x} ]; then - export HTTPD_IMG=mod_proxy_cluster-testsuite-httpd -fi - echo "Test parameters are:" -echo " FOREVER_PAUSE=$FOREVER_PAUSE" -echo " TOMCAT_CYCLE_COUNT=$TOMCAT_CYCLE_COUNT" -echo " ITERATION_COUNT=$ITERATION_COUNT" -echo " IMG=$IMG" -echo " HTTPD_IMG=$HTTPD_IMG" +echo " FOREVER_PAUSE=${FOREVER_PAUSE:=3600}" # sleep period length during which tomcats are run & stopped +echo " TOMCAT_CYCLE_COUNT=${TOMCAT_CYCLE_COUNT:=100}" # the number of repetitions of a test cycle +echo " ITERATION_COUNT=${ITERATION_COUNT:=50}" # the number of iteration of starting/stopping a tomcat +echo " IMG=${IMG:=mod_proxy_cluster-testsuite-tomcat}" # tomcat container image +echo " HTTPD_IMG=${HTTPD_IMG:=mod_proxy_cluster-testsuite-httpd}" # httpd with mod_proxy_cluster container image if [ ! -z ${MPC_CONF+x} ]; then echo " MPC_CONF=$MPC_CONF" fi echo " DEBUG=${DEBUG:-Off (undefined)}" +echo " MOD_PROXY_CLUSTER_TESTS=${MOD_PROXY_CLUSTER_TESTS:=On}" +echo " MOD_PROXY_BALANCER_TESTS=${MOD_PROXY_BALANCER_TESTS:=On}" +echo " SKIP_CONTAINER_CREATION=${SKIP_CONTAINER_CREATION:=Off}" +export FOREVER_PAUSE TOMCAT_CYCLE_COUNT ITERATION_COUNT IMG HTTPD_IMG + if [ ! -d logs ]; then mkdir logs @@ -39,20 +26,39 @@ fi . includes/common.sh -if [ ! -d tomcat/target ]; then - echo "Missing dependencies. Please run setup-dependencies.sh and then try again" - exit 4 +if is_enabled "$CODE_COVERAGE"; then + if [ ! -d coverage ]; then + mkdir coverage + fi + rm -f coverage/* fi -echo -n "Creating docker containers..." -if is_enabled "$DEBUG"; then - httpd_create || exit 2 - tomcat_create || exit 3 +IMG_NOVER=$(echo $IMG | cut -d: -f1) + +if is_enabled "$SKIP_CONTAINER_CREATION"; then + # let's just check all the containers are present + for tomcat_image in "$IMG_NOVER:latest" "$IMG_NOVER:9.0" "$IMG_NOVER:10.1" "$IMG_NOVER:11.0" + do + if ! docker image inspect $tomcat_image > /dev/null 2>&1; then + echo "tomcat image $tomcat_image is missing" + exit 3 + fi + done + if ! docker image inspect $HTTPD_IMG > /dev/null 2>&1; then + echo "httpd image $HTTPD_IMG is missing" + exit 2 + fi else - httpd_create > /dev/null 2>&1 || exit 2 - tomcat_create > /dev/null 2>&1 || exit 3 + # create all containers + if [ ! -d tomcat/target ]; then + echo "Missing dependencies. Please run setup-dependencies.sh and then try again" + exit 4 + fi + + echo "Creating docker containers..." + test_create_all_containers + echo "Done" fi -echo " Done" # clean everything at first echo -n "Cleaning possibly running containers..." @@ -62,53 +68,56 @@ echo " Done" res=0 -# IMG name might include specific version, we have to handle that -IMG_NOVER=$(echo $IMG | cut -d: -f1) +if is_enabled "$MOD_PROXY_CLUSTER_TESTS"; then + for tomcat_version in "9.0" "10.1" "11.0" + do + IMG="$IMG_NOVER:$tomcat_version" run_test basetests.sh "Basic tests with tomcat $tomcat_version" + res=$(( $res + $? )) + done + run_test hangingtests.sh "Hanging tests" + res=$(( $res + $? )) + run_test maintests.sh "Main tests" + res=$(( $res + $? )) + run_test websocket/basic.sh "Websocket tests" + res=$(( $res + $? )) + run_test usealias/testit.sh "UseAlias" + res=$(( $res + $? )) + run_test MODCLUSTER-640/testit.sh "MODCLUSTER-640" + res=$(( $res + $? )) + run_test MODCLUSTER-734/testit.sh "MODCLUSTER-734" + res=$(( $res + $? )) + run_test MODCLUSTER-736/testit.sh "MODCLUSTER-736" + res=$(( $res + $? )) + run_test MODCLUSTER-755/testit.sh "MODCLUSTER-755" + res=$(( $res + $? )) + run_test MODCLUSTER-785/testit.sh "MODCLUSTER-785" + res=$(( $res + $? )) + run_test MODCLUSTER-794/testit.sh "MODCLUSTER-794" + res=$(( $res + $? )) +fi -for tomcat_version in "9.0" "10.1" "11.0" -do - IMG="$IMG_NOVER:$tomcat_version" tomcat_create $tomcat_version > /dev/null 2>&1 || exit 3 - IMG="$IMG_NOVER:$tomcat_version" run_test basetests.sh "Basic tests with tomcat $tomcat_version" - res=$(expr $res + $?) -done -run_test hangingtests.sh "Hanging tests" -res=$(expr $res + $?) -run_test maintests.sh "Main tests" -res=$(expr $res + $?) -run_test websocket/basic.sh "Websocket tests" -res=$(expr $res + $?) -run_test usealias/testit.sh "UseAlias" -res=$(expr $res + $?) -run_test MODCLUSTER-640/testit.sh "MODCLUSTER-640" -res=$(expr $res + $?) -run_test MODCLUSTER-734/testit.sh "MODCLUSTER-734" -res=$(expr $res + $?) -run_test MODCLUSTER-736/testit.sh "MODCLUSTER-736" -res=$(expr $res + $?) -run_test MODCLUSTER-755/testit.sh "MODCLUSTER-755" -res=$(expr $res + $?) -run_test MODCLUSTER-785/testit.sh "MODCLUSTER-785" -res=$(expr $res + $?) -run_test MODCLUSTER-794/testit.sh "MODCLUSTER-794" -res=$(expr $res + $?) - -MPC_CONF=httpd/mod_lbmethod_cluster.conf run_test basetests.sh "Basic tests with mod_proxy_balancer" -res=$(expr $res + $?) -MPC_CONF=MODCLUSTER-640/mod_lbmethod_cluster.conf run_test MODCLUSTER-640/testit.sh "MODCLUSTER-640 with mod_proxy_balancer" -res=$(expr $res + $?) -MPC_CONF=MODCLUSTER-734/mod_lbmethod_cluster.conf run_test MODCLUSTER-734/testit.sh "MODCLUSTER-734 with mod_proxy_balancer" -res=$(expr $res + $?) -MPC_CONF=httpd/mod_lbmethod_cluster.conf run_test MODCLUSTER-755/testit.sh "MODCLUSTER-755 with mod_proxy_balancer" -res=$(expr $res + $?) -MPC_CONF=MODCLUSTER-785/mod_lbmethod_cluster.conf run_test MODCLUSTER-785/testit.sh "MODCLUSTER-785 with mod_proxy_balancer" -res=$(expr $res + $?) -MPC_CONF=MODCLUSTER-794/mod_lbmethod_cluster.conf run_test MODCLUSTER-794/testit.sh "MODCLUSTER-794 with mod_proxy_balancer" -res=$(expr $res + $?) +if is_enabled "$MOD_PROXY_BALANCER_TESTS"; then + for tomcat_version in "9.0" "10.1" "11.0" + do + IMG="$IMG_NOVER:$tomcat_version" MPC_CONF=httpd/mod_lbmethod_cluster.conf run_test basetests.sh "Basic tests with mod_proxy_balancer and tomcat $tomcat_version" + res=$(( $res + $? )) + done + MPC_CONF=MODCLUSTER-640/mod_lbmethod_cluster.conf run_test MODCLUSTER-640/testit.sh "MODCLUSTER-640 with mod_proxy_balancer" + res=$(( $res + $? )) + MPC_CONF=MODCLUSTER-734/mod_lbmethod_cluster.conf run_test MODCLUSTER-734/testit.sh "MODCLUSTER-734 with mod_proxy_balancer" + res=$(( $res + $? )) + MPC_CONF=httpd/mod_lbmethod_cluster.conf run_test MODCLUSTER-755/testit.sh "MODCLUSTER-755 with mod_proxy_balancer" + res=$(( $res + $? )) + MPC_CONF=MODCLUSTER-785/mod_lbmethod_cluster.conf run_test MODCLUSTER-785/testit.sh "MODCLUSTER-785 with mod_proxy_balancer" + res=$(( $res + $? )) + MPC_CONF=MODCLUSTER-794/mod_lbmethod_cluster.conf run_test MODCLUSTER-794/testit.sh "MODCLUSTER-794 with mod_proxy_balancer" + res=$(( $res + $? )) +fi 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 +126,19 @@ else res=1 fi +if is_enabled "$CODE_COVERAGE"; then + echo "Generating test coverage..." + 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 /native/scripts/coverage.sh report /coverage + docker cp $MPC_NAME:/coverage/ . > /dev/null + + httpd_remove > /dev/null 2>&1 +fi + exit $res 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