From 1e37f1592539922dda1c2a3fcea9202da6d0740a Mon Sep 17 00:00:00 2001 From: Paul Lodge Date: Fri, 2 Oct 2026 12:27:17 +0200 Subject: [PATCH 1/2] add --enable-test-apps to build test binaries at make time --- Makefile.in | 6 ++++- configure.in | 30 +++++++++++++++++++++++ test/Makefile.in | 49 +++++++++++++++++++++++++++++++++++++- test/modules/http1/env.py | 2 +- test/modules/http2/env.py | 2 +- test/pyhttpd/config.ini.in | 1 + test/pyhttpd/env.py | 2 +- 7 files changed, 87 insertions(+), 5 deletions(-) diff --git a/Makefile.in b/Makefile.in index cd5903aa1cc..74e6dae6b75 100644 --- a/Makefile.in +++ b/Makefile.in @@ -34,7 +34,7 @@ DISTCLEAN_TARGETS = include/ap_config_auto.h include/ap_config_layout.h \ build/pkg/pkginfo build/config_vars.sh bsd_converted EXTRACLEAN_TARGETS = configure include/ap_config_auto.h.in generated_lists \ httpd.spec -PHONY_TARGETS := check check-conf check-dirs check-include check-pytest check-all-pytest unittest-objdir +PHONY_TARGETS := check check-conf check-dirs check-include check-pytest check-all-pytest unittest-objdir test-apps TESTS = TEST_CONFIG = @@ -527,6 +527,10 @@ check-all-pytest: check-tree check/bin/apachectl check/config.ini check/modules/ # Runs all configured/available test targets. check: $(CHECK_TARGETS) +# Build test binaries/modules (enabled by --enable-test-apps) +test-apps: + cd test && $(MAKE) $(MFLAGS) test-apps + # # Unit Test Suite # diff --git a/configure.in b/configure.in index 58e996c4537..9f9554b9257 100644 --- a/configure.in +++ b/configure.in @@ -793,6 +793,14 @@ if test -d "./test"; then fi APACHE_SUBST(PYTEST3) +dnl Enable building test binaries/modules at make time +AC_ARG_ENABLE(test-apps, +APACHE_HELP_STRING(--enable-test-apps,Build test binaries and modules at make time),[ + enable_test_apps=$enableval +],[ + enable_test_apps=no +]) + prefix="$orig_prefix" APACHE_ENABLE_MODULES @@ -808,6 +816,28 @@ APACHE_SUBST(OS_SPECIFIC_VARS) APACHE_SUBST(HTTPD_LIBS) APACHE_SUBST(CHECK_TARGETS) +dnl Resolve --enable-test-apps after module config stubs have run +dnl (nghttp2 detection for h2ws happens in modules/http2/config2.m4) +if test "$enable_test_apps" = "yes" -a -d "./test"; then + + dnl h2ws requires nghttp2 + if test "x$ac_cv_nghttp2" != "xyes"; then + AC_MSG_ERROR([--enable-test-apps requires nghttp2 for h2ws client (use --with-nghttp2=PATH)]) + fi + + dnl Test modules require DSO support + if test "$enable_so" != "yes" -a "$enable_so" != "static"; then + AC_MSG_ERROR([--enable-test-apps requires DSO support (--enable-so)]) + fi + + TEST_MODULES_DIR="$abs_builddir/test/test-modules/.libs" + other_targets="$other_targets test-apps" + AC_MSG_NOTICE([test apps will be built at make time]) +else + TEST_MODULES_DIR="" +fi +APACHE_SUBST(TEST_MODULES_DIR) + PRE_SHARED_CMDS='echo ""' POST_SHARED_CMDS='echo ""' diff --git a/test/Makefile.in b/test/Makefile.in index ae5bf2b8c98..b84d8905f96 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -19,8 +19,55 @@ test: $(bin_PROGRAMS) # dbu: $(dbu_OBJECTS) # $(LINK) $(dbu_OBJECTS) $(PROGRAM_LDADD) +# --- Test module builds (used by --enable-test-apps) --- + +TM = test-modules + +mod_aptest_SRC = $(top_srcdir)/test/pyhttpd/mod_aptest/mod_aptest.c + +$(TM)/mod_aptest.slo: $(mod_aptest_SRC) + @mkdir -p $(TM) + $(LIBTOOL) --mode=compile $(BASE_CC) $(SHLTCFLAGS) \ + -c $(mod_aptest_SRC) -o $(TM)/mod_aptest.lo && touch $@ + +$(TM)/mod_aptest.la: $(TM)/mod_aptest.slo + $(SH_LINK) -rpath $(libexecdir) -module -avoid-version \ + $(TM)/mod_aptest.lo + +mod_h1test_SRC = $(top_srcdir)/test/modules/http1/mod_h1test/mod_h1test.c + +$(TM)/mod_h1test.slo: $(mod_h1test_SRC) + @mkdir -p $(TM) + $(LIBTOOL) --mode=compile $(BASE_CC) $(SHLTCFLAGS) \ + -c $(mod_h1test_SRC) -o $(TM)/mod_h1test.lo && touch $@ + +$(TM)/mod_h1test.la: $(TM)/mod_h1test.slo + $(SH_LINK) -rpath $(libexecdir) -module -avoid-version \ + $(TM)/mod_h1test.lo + +mod_h2test_SRC = $(top_srcdir)/test/modules/http2/mod_h2test/mod_h2test.c + +$(TM)/mod_h2test.slo: $(mod_h2test_SRC) + @mkdir -p $(TM) + $(LIBTOOL) --mode=compile $(BASE_CC) $(SHLTCFLAGS) \ + -I$(top_srcdir)/test/modules/http2/mod_h2test \ + -c $(mod_h2test_SRC) -o $(TM)/mod_h2test.lo && touch $@ + +$(TM)/mod_h2test.la: $(TM)/mod_h2test.slo + $(SH_LINK) -rpath $(libexecdir) -module -avoid-version \ + $(TM)/mod_h2test.lo + +test-modules: $(TM)/mod_aptest.la $(TM)/mod_h1test.la $(TM)/mod_h2test.la + +h2ws-client: + cd clients && $(MAKE) $(MFLAGS) h2ws + +.PHONY: test-apps test-modules h2ws-client + +test-apps: test-modules h2ws-client + clean: - rm -rf gen + rm -rf gen test-modules find . -name __pycache__ | xargs rm -rf distclean: diff --git a/test/modules/http1/env.py b/test/modules/http1/env.py index 1a88e3b032f..620d1a43c23 100644 --- a/test/modules/http1/env.py +++ b/test/modules/http1/env.py @@ -25,7 +25,7 @@ def make(self): def _add_h1test(self): module_dir = self.env.test_modules_dir - if not self.env.isWindows: + if not module_dir and not self.env.isWindows: local_dir = os.path.dirname(inspect.getfile(H1TestSetup)) p = subprocess.run([self.env.apxs, '-c', 'mod_h1test.c'], capture_output=True, diff --git a/test/modules/http2/env.py b/test/modules/http2/env.py index fe690bf9811..496f9a80ae3 100644 --- a/test/modules/http2/env.py +++ b/test/modules/http2/env.py @@ -26,7 +26,7 @@ def make(self): def _add_h2test(self): module_dir = self.env.test_modules_dir - if not self.env.isWindows: + if not module_dir and not self.env.isWindows: local_dir = os.path.dirname(inspect.getfile(H2TestSetup)) p = subprocess.run([self.env.apxs, '-c', 'mod_h2test.c'], capture_output=True, diff --git a/test/pyhttpd/config.ini.in b/test/pyhttpd/config.ini.in index 3f42248f65b..8591fb663cc 100644 --- a/test/pyhttpd/config.ini.in +++ b/test/pyhttpd/config.ini.in @@ -13,6 +13,7 @@ libexecdir = @libexecdir@ apr_bindir = @APR_BINDIR@ apxs = @bindir@/apxs apachectl = @sbindir@/apachectl +pre_built_test_binaries_dir = @TEST_MODULES_DIR@ [httpd] version = @HTTPD_VERSION@ diff --git a/test/pyhttpd/env.py b/test/pyhttpd/env.py index 521c16124d7..45d69c0ef9d 100644 --- a/test/pyhttpd/env.py +++ b/test/pyhttpd/env.py @@ -240,7 +240,7 @@ def _fix_shebang(py_file): def _add_aptest(self): module_dir = self.env.test_modules_dir - if not self.env.isWindows: + if not module_dir and not self.env.isWindows: local_dir = os.path.dirname(inspect.getfile(HttpdTestSetup)) p = subprocess.run([self.env.apxs, '-c', 'mod_aptest.c'], capture_output=True, From 3e2e6a22465d11340ff03601de7e9db4124793f9 Mon Sep 17 00:00:00 2001 From: Paul Lodge Date: Fri, 2 Oct 2026 14:09:49 +0200 Subject: [PATCH 2/2] Updated and corrected module creation path --- configure.in | 15 +++++++----- test/Makefile.in | 47 ++++++++++++++++++++------------------ test/modules/http1/env.py | 18 +++++++-------- test/modules/http2/env.py | 18 +++++++-------- test/pyhttpd/config.ini.in | 1 - test/pyhttpd/env.py | 16 ++++++------- 6 files changed, 60 insertions(+), 55 deletions(-) diff --git a/configure.in b/configure.in index 9f9554b9257..d06ce3e98b5 100644 --- a/configure.in +++ b/configure.in @@ -820,23 +820,25 @@ dnl Resolve --enable-test-apps after module config stubs have run dnl (nghttp2 detection for h2ws happens in modules/http2/config2.m4) if test "$enable_test_apps" = "yes" -a -d "./test"; then - dnl h2ws requires nghttp2 + AC_MSG_CHECKING([for nghttp2 to build h2ws test client]) if test "x$ac_cv_nghttp2" != "xyes"; then + AC_MSG_RESULT([no]) AC_MSG_ERROR([--enable-test-apps requires nghttp2 for h2ws client (use --with-nghttp2=PATH)]) fi + AC_MSG_RESULT([yes]) - dnl Test modules require DSO support + AC_MSG_CHECKING([for DSO support to build test modules]) if test "$enable_so" != "yes" -a "$enable_so" != "static"; then + AC_MSG_RESULT([no]) AC_MSG_ERROR([--enable-test-apps requires DSO support (--enable-so)]) fi + AC_MSG_RESULT([yes]) - TEST_MODULES_DIR="$abs_builddir/test/test-modules/.libs" + TEST_APPS_SUMMARY="yes (mod_aptest, mod_h1test, mod_h2test, h2ws)" other_targets="$other_targets test-apps" - AC_MSG_NOTICE([test apps will be built at make time]) else - TEST_MODULES_DIR="" + TEST_APPS_SUMMARY="no" fi -APACHE_SUBST(TEST_MODULES_DIR) PRE_SHARED_CMDS='echo ""' POST_SHARED_CMDS='echo ""' @@ -1162,4 +1164,5 @@ AC_MSG_NOTICE([summary of build options: LDFLAGS: ${APACHE_CONF_SEL_LDFLAGS} LIBS: ${APACHE_CONF_SEL_LIBS} C preprocessor: ${APACHE_CONF_SEL_CPP} + Test apps: ${TEST_APPS_SUMMARY} ]) diff --git a/test/Makefile.in b/test/Makefile.in index b84d8905f96..c224250a5d3 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -20,44 +20,43 @@ test: $(bin_PROGRAMS) # $(LINK) $(dbu_OBJECTS) $(PROGRAM_LDADD) # --- Test module builds (used by --enable-test-apps) --- +# Builds each module into its source directory, matching apxs -c output locations. -TM = test-modules +mod_aptest_DIR = $(top_srcdir)/test/pyhttpd/mod_aptest +mod_aptest_SRC = $(mod_aptest_DIR)/mod_aptest.c -mod_aptest_SRC = $(top_srcdir)/test/pyhttpd/mod_aptest/mod_aptest.c - -$(TM)/mod_aptest.slo: $(mod_aptest_SRC) - @mkdir -p $(TM) +$(mod_aptest_DIR)/mod_aptest.slo: $(mod_aptest_SRC) $(LIBTOOL) --mode=compile $(BASE_CC) $(SHLTCFLAGS) \ - -c $(mod_aptest_SRC) -o $(TM)/mod_aptest.lo && touch $@ + -c $(mod_aptest_SRC) -o $(mod_aptest_DIR)/mod_aptest.lo && touch $@ -$(TM)/mod_aptest.la: $(TM)/mod_aptest.slo +$(mod_aptest_DIR)/mod_aptest.la: $(mod_aptest_DIR)/mod_aptest.slo $(SH_LINK) -rpath $(libexecdir) -module -avoid-version \ - $(TM)/mod_aptest.lo + $(mod_aptest_DIR)/mod_aptest.lo -mod_h1test_SRC = $(top_srcdir)/test/modules/http1/mod_h1test/mod_h1test.c +mod_h1test_DIR = $(top_srcdir)/test/modules/http1/mod_h1test +mod_h1test_SRC = $(mod_h1test_DIR)/mod_h1test.c -$(TM)/mod_h1test.slo: $(mod_h1test_SRC) - @mkdir -p $(TM) +$(mod_h1test_DIR)/mod_h1test.slo: $(mod_h1test_SRC) $(LIBTOOL) --mode=compile $(BASE_CC) $(SHLTCFLAGS) \ - -c $(mod_h1test_SRC) -o $(TM)/mod_h1test.lo && touch $@ + -c $(mod_h1test_SRC) -o $(mod_h1test_DIR)/mod_h1test.lo && touch $@ -$(TM)/mod_h1test.la: $(TM)/mod_h1test.slo +$(mod_h1test_DIR)/mod_h1test.la: $(mod_h1test_DIR)/mod_h1test.slo $(SH_LINK) -rpath $(libexecdir) -module -avoid-version \ - $(TM)/mod_h1test.lo + $(mod_h1test_DIR)/mod_h1test.lo -mod_h2test_SRC = $(top_srcdir)/test/modules/http2/mod_h2test/mod_h2test.c +mod_h2test_DIR = $(top_srcdir)/test/modules/http2/mod_h2test +mod_h2test_SRC = $(mod_h2test_DIR)/mod_h2test.c -$(TM)/mod_h2test.slo: $(mod_h2test_SRC) - @mkdir -p $(TM) +$(mod_h2test_DIR)/mod_h2test.slo: $(mod_h2test_SRC) $(LIBTOOL) --mode=compile $(BASE_CC) $(SHLTCFLAGS) \ - -I$(top_srcdir)/test/modules/http2/mod_h2test \ - -c $(mod_h2test_SRC) -o $(TM)/mod_h2test.lo && touch $@ + -I$(mod_h2test_DIR) \ + -c $(mod_h2test_SRC) -o $(mod_h2test_DIR)/mod_h2test.lo && touch $@ -$(TM)/mod_h2test.la: $(TM)/mod_h2test.slo +$(mod_h2test_DIR)/mod_h2test.la: $(mod_h2test_DIR)/mod_h2test.slo $(SH_LINK) -rpath $(libexecdir) -module -avoid-version \ - $(TM)/mod_h2test.lo + $(mod_h2test_DIR)/mod_h2test.lo -test-modules: $(TM)/mod_aptest.la $(TM)/mod_h1test.la $(TM)/mod_h2test.la +test-modules: $(mod_aptest_DIR)/mod_aptest.la $(mod_h1test_DIR)/mod_h1test.la $(mod_h2test_DIR)/mod_h2test.la h2ws-client: cd clients && $(MAKE) $(MFLAGS) h2ws @@ -68,6 +67,10 @@ test-apps: test-modules h2ws-client clean: rm -rf gen test-modules + cd clients && $(MAKE) $(MFLAGS) clean + rm -rf pyhttpd/mod_aptest/.libs pyhttpd/mod_aptest/*.o pyhttpd/mod_aptest/*.lo pyhttpd/mod_aptest/*.slo pyhttpd/mod_aptest/*.la + rm -rf modules/http1/mod_h1test/.libs modules/http1/mod_h1test/*.o modules/http1/mod_h1test/*.lo modules/http1/mod_h1test/*.slo modules/http1/mod_h1test/*.la + rm -rf modules/http2/mod_h2test/.libs modules/http2/mod_h2test/*.o modules/http2/mod_h2test/*.lo modules/http2/mod_h2test/*.slo modules/http2/mod_h2test/*.la find . -name __pycache__ | xargs rm -rf distclean: diff --git a/test/modules/http1/env.py b/test/modules/http1/env.py index 620d1a43c23..f54fcf690e6 100644 --- a/test/modules/http1/env.py +++ b/test/modules/http1/env.py @@ -27,16 +27,16 @@ def _add_h1test(self): module_dir = self.env.test_modules_dir if not module_dir and not self.env.isWindows: local_dir = os.path.dirname(inspect.getfile(H1TestSetup)) - p = subprocess.run([self.env.apxs, '-c', 'mod_h1test.c'], - capture_output=True, - cwd=os.path.join(local_dir, 'mod_h1test')) - - rv = p.returncode - if rv != 0: - log.error(f"compiling md_h1test failed: {p.stderr}") - raise Exception(f"compiling md_h1test failed: {p.stderr}") - module_dir = f"{local_dir}/mod_h1test/.libs" + if not os.path.exists(f"{module_dir}/mod_h1test.so"): + p = subprocess.run([self.env.apxs, '-c', 'mod_h1test.c'], + capture_output=True, + cwd=os.path.join(local_dir, 'mod_h1test')) + + rv = p.returncode + if rv != 0: + log.error(f"compiling md_h1test failed: {p.stderr}") + raise Exception(f"compiling md_h1test failed: {p.stderr}") modules_conf = os.path.join(self.env.server_dir, 'conf/modules.conf') with open(modules_conf, 'a') as fd: diff --git a/test/modules/http2/env.py b/test/modules/http2/env.py index 496f9a80ae3..0e41a2fa135 100644 --- a/test/modules/http2/env.py +++ b/test/modules/http2/env.py @@ -28,16 +28,16 @@ def _add_h2test(self): module_dir = self.env.test_modules_dir if not module_dir and not self.env.isWindows: local_dir = os.path.dirname(inspect.getfile(H2TestSetup)) - p = subprocess.run([self.env.apxs, '-c', 'mod_h2test.c'], - capture_output=True, - cwd=os.path.join(local_dir, 'mod_h2test')) - - rv = p.returncode - if rv != 0: - log.error(f"compiling md_h2test failed: {p.stderr}") - raise Exception(f"compiling md_h2test failed: {p.stderr}") - module_dir = f"{local_dir}/mod_h2test/.libs" + if not os.path.exists(f"{module_dir}/mod_h2test.so"): + p = subprocess.run([self.env.apxs, '-c', 'mod_h2test.c'], + capture_output=True, + cwd=os.path.join(local_dir, 'mod_h2test')) + + rv = p.returncode + if rv != 0: + log.error(f"compiling md_h2test failed: {p.stderr}") + raise Exception(f"compiling md_h2test failed: {p.stderr}") modules_conf = os.path.join(self.env.server_dir, 'conf/modules.conf') with open(modules_conf, 'a') as fd: diff --git a/test/pyhttpd/config.ini.in b/test/pyhttpd/config.ini.in index 8591fb663cc..3f42248f65b 100644 --- a/test/pyhttpd/config.ini.in +++ b/test/pyhttpd/config.ini.in @@ -13,7 +13,6 @@ libexecdir = @libexecdir@ apr_bindir = @APR_BINDIR@ apxs = @bindir@/apxs apachectl = @sbindir@/apachectl -pre_built_test_binaries_dir = @TEST_MODULES_DIR@ [httpd] version = @HTTPD_VERSION@ diff --git a/test/pyhttpd/env.py b/test/pyhttpd/env.py index 45d69c0ef9d..ef006a62d88 100644 --- a/test/pyhttpd/env.py +++ b/test/pyhttpd/env.py @@ -242,15 +242,15 @@ def _add_aptest(self): module_dir = self.env.test_modules_dir if not module_dir and not self.env.isWindows: local_dir = os.path.dirname(inspect.getfile(HttpdTestSetup)) - p = subprocess.run([self.env.apxs, '-c', 'mod_aptest.c'], - capture_output=True, - cwd=os.path.join(local_dir, 'mod_aptest')) - rv = p.returncode - if rv != 0: - log.error(f"compiling mod_aptest failed: {p.stderr}") - raise Exception(f"compiling mod_aptest failed: {p.stderr}") - module_dir = os.path.join(local_dir, "mod_aptest", ".libs") + if not os.path.exists(os.path.join(module_dir, "mod_aptest.so")): + p = subprocess.run([self.env.apxs, '-c', 'mod_aptest.c'], + capture_output=True, + cwd=os.path.join(local_dir, 'mod_aptest')) + rv = p.returncode + if rv != 0: + log.error(f"compiling mod_aptest failed: {p.stderr}") + raise Exception(f"compiling mod_aptest failed: {p.stderr}") modules_conf = os.path.join(self.env.server_dir, 'conf/modules.conf') with open(modules_conf, 'a') as fd: