You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ic...@apache.org on 2021/11/08 12:33:47 UTC

svn commit: r1894832 - in /httpd/httpd/trunk/test: modules/core/ modules/http2/ modules/http2/data/ modules/http2/htdocs/ modules/http2/htdocs/cgi/ modules/http2/htdocs/noh2/ modules/md/ pyhttpd/ pyhttpd/htdocs/cgi/ pyhttpd/htdocs/noh2/ pyhttpd/htdocs/...

Author: icing
Date: Mon Nov  8 12:33:46 2021
New Revision: 1894832

URL: http://svn.apache.org/viewvc?rev=1894832&view=rev
Log:
 * test: just general cleanup and separation
   - base modules loaded minimized
   - h2's htdocs/cgi setup now in test/modules/http2
   - less args to constructors, more methods


Added:
    httpd/httpd/trunk/test/modules/http2/htdocs/
    httpd/httpd/trunk/test/modules/http2/htdocs/cgi/
      - copied from r1894831, httpd/httpd/trunk/test/pyhttpd/htdocs/cgi/
    httpd/httpd/trunk/test/modules/http2/htdocs/noh2/
      - copied from r1894831, httpd/httpd/trunk/test/pyhttpd/htdocs/noh2/
Removed:
    httpd/httpd/trunk/test/modules/core/env.py
    httpd/httpd/trunk/test/modules/http2/data/
    httpd/httpd/trunk/test/pyhttpd/htdocs/cgi/
    httpd/httpd/trunk/test/pyhttpd/htdocs/noh2/
    httpd/httpd/trunk/test/pyhttpd/htdocs/ssl/
    httpd/httpd/trunk/test/pyhttpd/htdocs/test1/apache.org-files/
    httpd/httpd/trunk/test/pyhttpd/htdocs/test1/apache.org.html
Modified:
    httpd/httpd/trunk/test/modules/core/conftest.py
    httpd/httpd/trunk/test/modules/core/test_001_encoding.py
    httpd/httpd/trunk/test/modules/http2/conftest.py
    httpd/httpd/trunk/test/modules/http2/env.py
    httpd/httpd/trunk/test/modules/http2/test_001_httpd_alive.py
    httpd/httpd/trunk/test/modules/http2/test_002_curl_basics.py
    httpd/httpd/trunk/test/modules/http2/test_003_get.py
    httpd/httpd/trunk/test/modules/http2/test_004_post.py
    httpd/httpd/trunk/test/modules/http2/test_006_assets.py
    httpd/httpd/trunk/test/modules/http2/test_100_conn_reuse.py
    httpd/httpd/trunk/test/modules/http2/test_101_ssl_reneg.py
    httpd/httpd/trunk/test/modules/http2/test_102_require.py
    httpd/httpd/trunk/test/modules/http2/test_103_upgrade.py
    httpd/httpd/trunk/test/modules/http2/test_104_padding.py
    httpd/httpd/trunk/test/modules/http2/test_105_timeout.py
    httpd/httpd/trunk/test/modules/http2/test_200_header_invalid.py
    httpd/httpd/trunk/test/modules/http2/test_201_header_conditional.py
    httpd/httpd/trunk/test/modules/http2/test_202_trailer.py
    httpd/httpd/trunk/test/modules/http2/test_300_interim.py
    httpd/httpd/trunk/test/modules/http2/test_400_push.py
    httpd/httpd/trunk/test/modules/http2/test_401_early_hints.py
    httpd/httpd/trunk/test/modules/http2/test_500_proxy.py
    httpd/httpd/trunk/test/modules/http2/test_501_proxy_serverheader.py
    httpd/httpd/trunk/test/modules/http2/test_600_h2proxy.py
    httpd/httpd/trunk/test/modules/http2/test_700_load_get.py
    httpd/httpd/trunk/test/modules/http2/test_710_load_post_static.py
    httpd/httpd/trunk/test/modules/http2/test_711_load_post_cgi.py
    httpd/httpd/trunk/test/modules/http2/test_712_buffering.py
    httpd/httpd/trunk/test/modules/md/conftest.py
    httpd/httpd/trunk/test/modules/md/md_acme.py
    httpd/httpd/trunk/test/modules/md/md_env.py
    httpd/httpd/trunk/test/modules/md/test_502_acmev2_drive.py
    httpd/httpd/trunk/test/pyhttpd/conf.py
    httpd/httpd/trunk/test/pyhttpd/env.py

Modified: httpd/httpd/trunk/test/modules/core/conftest.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/core/conftest.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/core/conftest.py (original)
+++ httpd/httpd/trunk/test/modules/core/conftest.py Mon Nov  8 12:33:46 2021
@@ -4,25 +4,26 @@ import os
 import pytest
 import sys
 
-sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
+from pyhttpd.env import HttpdTestEnv
 
-from .env import CoreTestEnv
+sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
 
 
 def pytest_report_header(config, startdir):
-    env = CoreTestEnv(setup_dirs=False)
+    env = HttpdTestEnv()
     return f"core [apache: {env.get_httpd_version()}, mpm: {env.mpm_module}, {env.prefix}]"
 
 
 @pytest.fixture(scope="package")
-def env(pytestconfig) -> CoreTestEnv:
+def env(pytestconfig) -> HttpdTestEnv:
     level = logging.INFO
     console = logging.StreamHandler()
     console.setLevel(level)
     console.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
     logging.getLogger('').addHandler(console)
     logging.getLogger('').setLevel(level=level)
-    env = CoreTestEnv(pytestconfig=pytestconfig)
+    env = HttpdTestEnv(pytestconfig=pytestconfig)
+    env.setup_httpd()
     env.apache_access_log_clear()
     env.httpd_error_log.clear_log()
     return env

Modified: httpd/httpd/trunk/test/modules/core/test_001_encoding.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/core/test_001_encoding.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/core/test_001_encoding.py (original)
+++ httpd/httpd/trunk/test/modules/core/test_001_encoding.py Mon Nov  8 12:33:46 2021
@@ -18,7 +18,7 @@ class TestEncoding:
         </Directory>
         """,
             f"test2.{env.http_tld}": "AllowEncodedSlashes on",
-            f"cgi.{env.http_tld}": f"ScriptAlias /cgi-bin/ {env.gen_dir}",
+            f"test1.{env.http_tld}": f"ScriptAlias /cgi-bin/ {env.gen_dir}",
         })
         conf.add_vhost_test1()
         conf.add_vhost_test2()
@@ -73,7 +73,7 @@ class TestEncoding:
         ["/cgi-bin/%25%32%65%25%32%65/%25%32%65%25%32%65/h2_env.py", 404],
     ])
     def test_core_001_04(self, env, path, status):
-        url = env.mkurl("https", "cgi", path)
+        url = env.mkurl("https", "test1", path)
         r = env.curl_get(url)
         assert r.response["status"] == status
         if status == 400:

Modified: httpd/httpd/trunk/test/modules/http2/conftest.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/conftest.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/conftest.py (original)
+++ httpd/httpd/trunk/test/modules/http2/conftest.py Mon Nov  8 12:33:46 2021
@@ -10,7 +10,7 @@ from .env import H2TestEnv
 
 
 def pytest_report_header(config, startdir):
-    env = H2TestEnv(setup_dirs=False)
+    env = H2TestEnv()
     return f"mod_h2 [apache: {env.get_httpd_version()}, mpm: {env.mpm_module}, {env.prefix}]"
 
 
@@ -36,6 +36,7 @@ def env(pytestconfig) -> H2TestEnv:
     logging.getLogger('').addHandler(console)
     logging.getLogger('').setLevel(level=level)
     env = H2TestEnv(pytestconfig=pytestconfig)
+    env.setup_httpd()
     env.apache_access_log_clear()
     env.httpd_error_log.clear_log()
     return env

Modified: httpd/httpd/trunk/test/modules/http2/env.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/env.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/env.py (original)
+++ httpd/httpd/trunk/test/modules/http2/env.py Mon Nov  8 12:33:46 2021
@@ -16,15 +16,19 @@ class H2TestSetup(HttpdTestSetup):
 
     def __init__(self, env: 'HttpdTestEnv'):
         super().__init__(env=env)
+        self.add_source_dir(os.path.dirname(inspect.getfile(H2TestSetup)))
+        self.add_modules(["http2", "proxy_http2", "cgid", "autoindex"])
 
     def make(self):
-        super().make(add_modules=["http2", "proxy_http2"])
+        super().make()
         self._add_h2test()
+        self._setup_data_1k_1m()
 
     def _add_h2test(self):
+        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(self.env.local_dir, 'mod_h2test'))
+                           cwd=os.path.join(local_dir, 'mod_h2test'))
         rv = p.returncode
         if rv != 0:
             log.error(f"compiling md_h2test failed: {p.stderr}")
@@ -33,20 +37,34 @@ class H2TestSetup(HttpdTestSetup):
         modules_conf = os.path.join(self.env.server_dir, 'conf/modules.conf')
         with open(modules_conf, 'a') as fd:
             # load our test module which is not installed
-            fd.write(f"LoadModule h2test_module   \"{self.env.local_dir}/mod_h2test/.libs/mod_h2test.so\"\n")
+            fd.write(f"LoadModule h2test_module   \"{local_dir}/mod_h2test/.libs/mod_h2test.so\"\n")
+
+    def _setup_data_1k_1m(self):
+        s90 = "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678\n"
+        with open(os.path.join(self.env.gen_dir, "data-1k"), 'w') as f:
+            for i in range(10):
+                f.write(f"{i:09d}-{s90}")
+        with open(os.path.join(self.env.gen_dir, "data-10k"), 'w') as f:
+            for i in range(100):
+                f.write(f"{i:09d}-{s90}")
+        with open(os.path.join(self.env.gen_dir, "data-100k"), 'w') as f:
+            for i in range(1000):
+                f.write(f"{i:09d}-{s90}")
+        with open(os.path.join(self.env.gen_dir, "data-1m"), 'w') as f:
+            for i in range(10000):
+                f.write(f"{i:09d}-{s90}")
 
 
 class H2TestEnv(HttpdTestEnv):
 
-    def __init__(self, pytestconfig=None, setup_dirs=True):
-        super().__init__(pytestconfig=pytestconfig,
-                         local_dir=os.path.dirname(inspect.getfile(H2TestEnv)),
-                         add_base_conf=[
+    def __init__(self, pytestconfig=None):
+        super().__init__(pytestconfig=pytestconfig)
+        self.add_httpd_conf([
                              "H2MinWorkers 1",
                              "H2MaxWorkers 64",
                              "Protocols h2 http/1.1 h2c",
-                         ],
-                         interesting_modules=["http2", "proxy_http2", "h2test"])
+                         ])
+        self.add_httpd_log_modules(["http2", "proxy_http2", "h2test"])
         self.add_cert_specs([
             CertificateSpec(domains=[
                 f"push.{self._http_tld}",
@@ -74,27 +92,8 @@ class H2TestEnv(HttpdTestEnv):
             re.compile(r'.*:tls_process_client_certificate:.*'),
         ])
 
-        if setup_dirs:
-            self._setup = H2TestSetup(env=self)
-            self._setup.make()
-            self.issue_certs()
-            self.setup_data_1k_1m()
-
-
-    def setup_data_1k_1m(self):
-        s90 = "01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678\n"
-        with open(os.path.join(self.gen_dir, "data-1k"), 'w') as f:
-            for i in range(10):
-                f.write(f"{i:09d}-{s90}")
-        with open(os.path.join(self.gen_dir, "data-10k"), 'w') as f:
-            for i in range(100):
-                f.write(f"{i:09d}-{s90}")
-        with open(os.path.join(self.gen_dir, "data-100k"), 'w') as f:
-            for i in range(1000):
-                f.write(f"{i:09d}-{s90}")
-        with open(os.path.join(self.gen_dir, "data-1m"), 'w') as f:
-            for i in range(10000):
-                f.write(f"{i:09d}-{s90}")
+    def setup_httpd(self, setup: HttpdTestSetup = None):
+        super().setup_httpd(setup=H2TestSetup(env=self))
 
 
 class H2Conf(HttpdConf):
@@ -135,4 +134,3 @@ class H2Conf(HttpdConf):
 
     def add_vhost_test2(self):
         return super().add_vhost_test2()
-

Modified: httpd/httpd/trunk/test/modules/http2/test_001_httpd_alive.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_001_httpd_alive.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_001_httpd_alive.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_001_httpd_alive.py Mon Nov  8 12:33:46 2021
@@ -3,7 +3,7 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestBasicAlive:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_002_curl_basics.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_002_curl_basics.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_002_curl_basics.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_002_curl_basics.py Mon Nov  8 12:33:46 2021
@@ -3,7 +3,7 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestCurlBasics:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_003_get.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_003_get.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_003_get.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_003_get.py Mon Nov  8 12:33:46 2021
@@ -4,7 +4,7 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestGet:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
@@ -92,7 +92,7 @@ class TestStore:
   <title>Index of /006</title>
  </head>
  <body>
-<title>My Header Title</title>
+<h1>Index of /006</h1>
 <ul><li><a href="/"> Parent Directory</a></li>
 <li><a href="006.css"> 006.css</a></li>
 <li><a href="006.js"> 006.js</a></li>

Modified: httpd/httpd/trunk/test/modules/http2/test_004_post.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_004_post.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_004_post.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_004_post.py Mon Nov  8 12:33:46 2021
@@ -1,5 +1,6 @@
 import difflib
 import email.parser
+import inspect
 import json
 import os
 import re
@@ -10,14 +11,17 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestPost:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        env.setup_data_1k_1m()
+        TestPost._local_dir = os.path.dirname(inspect.getfile(TestPost))
         H2Conf(env).add_vhost_cgi().install()
         assert env.apache_restart() == 0
 
+    def local_src(self, fname):
+        return os.path.join(TestPost._local_dir, fname)
+
     # upload and GET again using curl, compare to original content
     def curl_upload_and_verify(self, env, fname, options=None):
         url = env.mkurl("https", "cgi", "/upload.py")
@@ -29,7 +33,7 @@ class TestStore:
         r2 = env.curl_get(r.response["header"]["location"])
         assert r2.exit_code == 0
         assert r2.response["status"] == 200
-        with open(env.local_src(fpath), mode='rb') as file:
+        with open(self.local_src(fpath), mode='rb') as file:
             src = file.read()
         assert src == r2.response["body"]
 
@@ -84,7 +88,7 @@ class TestStore:
         assert r.exit_code == 0
         assert r.response["status"] >= 200 and r.response["status"] < 300
 
-        with open(env.local_src(fpath), mode='rb') as file:
+        with open(self.local_src(fpath), mode='rb') as file:
             src = file.read()
         assert 'request-length' in r.response["header"]
         assert int(r.response["header"]['request-length']) == len(src)
@@ -123,7 +127,7 @@ class TestStore:
         r2 = env.nghttp().get(r.response["header"]["location"])
         assert r2.exit_code == 0
         assert r2.response["status"] == 200
-        with open(env.local_src(fpath), mode='rb') as file:
+        with open(self.local_src(fpath), mode='rb') as file:
             src = file.read()
         assert src == r2.response["body"]
 
@@ -204,7 +208,7 @@ CustomLog logs/test_004_30 issue_203
                 if fname == part.get_filename():
                     filepart = part
             assert filepart
-            with open(env.local_src(fpath), mode='rb') as file:
+            with open(self.local_src(fpath), mode='rb') as file:
                 src = file.read()
             assert src == filepart.get_payload(decode=True)
         

Modified: httpd/httpd/trunk/test/modules/http2/test_006_assets.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_006_assets.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_006_assets.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_006_assets.py Mon Nov  8 12:33:46 2021
@@ -3,7 +3,7 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestAssets:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_100_conn_reuse.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_100_conn_reuse.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_100_conn_reuse.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_100_conn_reuse.py Mon Nov  8 12:33:46 2021
@@ -3,7 +3,7 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestConnReuse:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_101_ssl_reneg.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_101_ssl_reneg.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_101_ssl_reneg.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_101_ssl_reneg.py Mon Nov  8 12:33:46 2021
@@ -4,7 +4,7 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestSslRenegotiation:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_102_require.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_102_require.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_102_require.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_102_require.py Mon Nov  8 12:33:46 2021
@@ -3,7 +3,7 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestRequire:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_103_upgrade.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_103_upgrade.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_103_upgrade.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_103_upgrade.py Mon Nov  8 12:33:46 2021
@@ -3,7 +3,7 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestUpgrade:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_104_padding.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_104_padding.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_104_padding.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_104_padding.py Mon Nov  8 12:33:46 2021
@@ -8,7 +8,7 @@ def frame_padding(payload, padbits):
     return ((payload + 9 + mask) & ~mask) - (payload + 9)
         
 
-class TestStore:
+class TestPadding:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_105_timeout.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_105_timeout.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_105_timeout.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_105_timeout.py Mon Nov  8 12:33:46 2021
@@ -7,7 +7,7 @@ from .env import H2Conf
 from pyhttpd.curl import CurlPiper
 
 
-class TestStore:
+class TestTimeout:
 
     # Check that base servers 'Timeout' setting is observed on SSL handshake
     def test_h2_105_01(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_200_header_invalid.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_200_header_invalid.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_200_header_invalid.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_200_header_invalid.py Mon Nov  8 12:33:46 2021
@@ -3,7 +3,7 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestInvalidHeaders:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_201_header_conditional.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_201_header_conditional.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_201_header_conditional.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_201_header_conditional.py Mon Nov  8 12:33:46 2021
@@ -3,7 +3,7 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestConditionalHeaders:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_202_trailer.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_202_trailer.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_202_trailer.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_202_trailer.py Mon Nov  8 12:33:46 2021
@@ -13,7 +13,7 @@ def setup_data(env):
 
 # The trailer tests depend on "nghttp" as no other client seems to be able to send those
 # rare things.
-class TestStore:
+class TestTrailers:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_300_interim.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_300_interim.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_300_interim.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_300_interim.py Mon Nov  8 12:33:46 2021
@@ -3,7 +3,7 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestInterimResponses:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_400_push.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_400_push.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_400_push.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_400_push.py Mon Nov  8 12:33:46 2021
@@ -5,7 +5,7 @@ from .env import H2Conf
 
 
 # The push tests depend on "nghttp"
-class TestStore:
+class TestPush:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_401_early_hints.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_401_early_hints.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_401_early_hints.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_401_early_hints.py Mon Nov  8 12:33:46 2021
@@ -4,7 +4,7 @@ from .env import H2Conf
 
 
 # The push tests depend on "nghttp"
-class TestStore:
+class TestEarlyHints:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_500_proxy.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_500_proxy.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_500_proxy.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_500_proxy.py Mon Nov  8 12:33:46 2021
@@ -1,3 +1,4 @@
+import inspect
 import os
 import re
 import pytest
@@ -5,14 +6,17 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestProxy:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        env.setup_data_1k_1m()
+        TestProxy._local_dir = os.path.dirname(inspect.getfile(TestProxy))
         H2Conf(env).add_vhost_cgi(proxy_self=True).install()
         assert env.apache_restart() == 0
 
+    def local_src(self, fname):
+        return os.path.join(TestProxy._local_dir, fname)
+
     def setup_method(self, method):
         print("setup_method: %s" % method.__name__)
 
@@ -41,7 +45,7 @@ class TestStore:
         r2 = env.curl_get(re.sub(r'http:', 'https:', r.response["header"]["location"]))
         assert r2.exit_code == 0
         assert r2.response["status"] == 200
-        with open(env.local_src(fpath), mode='rb') as file:
+        with open(self.local_src(fpath), mode='rb') as file:
             src = file.read()
         assert src == r2.response["body"]
 
@@ -58,7 +62,7 @@ class TestStore:
         r = env.nghttp().upload(url, fpath, options=options)
         assert r.exit_code == 0
         assert 200 <= r.response["status"] < 300
-        with open(env.local_src(fpath), mode='rb') as file:
+        with open(self.local_src(fpath), mode='rb') as file:
             src = file.read()
         assert src == r.response["body"]
 
@@ -88,7 +92,7 @@ class TestStore:
         r2 = env.nghttp().get(re.sub(r'http:', 'https:', r.response["header"]["location"]))
         assert r2.exit_code == 0
         assert r2.response["status"] == 200
-        with open(env.local_src(fpath), mode='rb') as file:
+        with open(self.local_src(fpath), mode='rb') as file:
             src = file.read()
         assert src == r2.response["body"]
 

Modified: httpd/httpd/trunk/test/modules/http2/test_501_proxy_serverheader.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_501_proxy_serverheader.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_501_proxy_serverheader.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_501_proxy_serverheader.py Mon Nov  8 12:33:46 2021
@@ -3,7 +3,7 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestProxyServerHeader:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_600_h2proxy.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_600_h2proxy.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_600_h2proxy.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_600_h2proxy.py Mon Nov  8 12:33:46 2021
@@ -3,11 +3,10 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestH2Proxy:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        env.setup_data_1k_1m()
         conf = H2Conf(env)
         conf.add_vhost_cgi(h2proxy_self=True)
         if env.verbosity > 1:

Modified: httpd/httpd/trunk/test/modules/http2/test_700_load_get.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_700_load_get.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_700_load_get.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_700_load_get.py Mon Nov  8 12:33:46 2021
@@ -3,7 +3,7 @@ import pytest
 from .env import H2Conf
 
 
-class TestStore:
+class TestLoadGet:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_710_load_post_static.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_710_load_post_static.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_710_load_post_static.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_710_load_post_static.py Mon Nov  8 12:33:46 2021
@@ -4,11 +4,10 @@ import os
 from .env import H2Conf
 
 
-class TestStore:
+class TestLoadPostStatic:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        env.setup_data_1k_1m()
         H2Conf(env).add_vhost_test1().install()
         assert env.apache_restart() == 0
 

Modified: httpd/httpd/trunk/test/modules/http2/test_711_load_post_cgi.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_711_load_post_cgi.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_711_load_post_cgi.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_711_load_post_cgi.py Mon Nov  8 12:33:46 2021
@@ -4,11 +4,10 @@ import os
 from .env import H2Conf
 
 
-class TestStore:
+class TestLoadCgi:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        env.setup_data_1k_1m()
         H2Conf(env).add_vhost_cgi(proxy_self=True, h2proxy_self=True).install()
         assert env.apache_restart() == 0
 

Modified: httpd/httpd/trunk/test/modules/http2/test_712_buffering.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_712_buffering.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_712_buffering.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_712_buffering.py Mon Nov  8 12:33:46 2021
@@ -10,7 +10,6 @@ class TestBuffering:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        env.setup_data_1k_1m()
         conf = H2Conf(env)
         conf.add_vhost_cgi(h2proxy_self=True).install()
         assert env.apache_restart() == 0

Modified: httpd/httpd/trunk/test/modules/md/conftest.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/conftest.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/conftest.py (original)
+++ httpd/httpd/trunk/test/modules/md/conftest.py Mon Nov  8 12:33:46 2021
@@ -2,12 +2,10 @@ import logging
 import os
 import re
 import sys
-from datetime import timedelta
 import pytest
 
 sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
 
-from .md_certs import CertificateSpec, MDTestCA
 from .md_conf import HttpdConf
 from .md_env import MDTestEnv
 from .md_acme import MDPebbleRunner, MDBoulderRunner
@@ -32,6 +30,7 @@ def env(pytestconfig) -> MDTestEnv:
     logging.getLogger('').addHandler(console)
     logging.getLogger('').setLevel(level=level)
     env = MDTestEnv(pytestconfig=pytestconfig)
+    env.setup_httpd()
     env.apache_access_log_clear()
     env.httpd_error_log.clear_log()
     return env

Modified: httpd/httpd/trunk/test/modules/md/md_acme.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/md_acme.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/md_acme.py (original)
+++ httpd/httpd/trunk/test/modules/md/md_acme.py Mon Nov  8 12:33:46 2021
@@ -97,7 +97,7 @@ class MDPebbleRunner(ACMEServer):
         shutil.copyfile(self.env.ca.cert_file, dest)
         end = datetime.now() + timedelta(seconds=20)
         while datetime.now() < end:
-            r = self.env.curl_get('https://localhost:15000/roots/0', insecure=True, debug_log=False)
+            r = self.env.curl_get('https://localhost:15000/roots/0', insecure=True)
             if r.exit_code == 0:
                 with open(dest, 'a') as fd:
                     fd.write(r.stdout)

Modified: httpd/httpd/trunk/test/modules/md/md_env.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/md_env.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/md_env.py (original)
+++ httpd/httpd/trunk/test/modules/md/md_env.py Mon Nov  8 12:33:46 2021
@@ -24,13 +24,16 @@ log = logging.getLogger(__name__)
 
 class MDTestSetup(HttpdTestSetup):
 
-    def __init__(self, env: 'HttpdTestEnv'):
+    def __init__(self, env: 'MDTestEnv'):
         super().__init__(env=env)
+        self.mdenv = env
+        self.add_modules(["watchdog", "proxy_connect", "md"])
 
     def make(self):
-        super().make(add_modules=["proxy_connect", "md"])
-        if "pebble" == self.env.acme_server:
+        super().make()
+        if "pebble" == self.mdenv.acme_server:
             self._make_pebble_conf()
+        self.mdenv.clear_store()
 
     def _make_pebble_conf(self):
         our_dir = os.path.dirname(inspect.getfile(MDTestSetup))
@@ -82,17 +85,16 @@ class MDTestEnv(HttpdTestEnv):
 
     @classmethod
     def has_a2md(cls):
-        dir = os.path.dirname(inspect.getfile(HttpdTestEnv))
+        d = os.path.dirname(inspect.getfile(HttpdTestEnv))
         config = ConfigParser(interpolation=ExtendedInterpolation())
-        config.read(os.path.join(dir, 'config.ini'))
+        config.read(os.path.join(d, 'config.ini'))
         bin_dir = config.get('global', 'bindir')
         a2md_bin = os.path.join(bin_dir, 'a2md')
         return os.path.isfile(a2md_bin)
 
-    def __init__(self, pytestconfig=None, setup_dirs=True):
-        super().__init__(pytestconfig=pytestconfig,
-                         local_dir=os.path.dirname(inspect.getfile(MDTestEnv)),
-                         interesting_modules=["md"])
+    def __init__(self, pytestconfig=None):
+        super().__init__(pytestconfig=pytestconfig)
+        self.add_httpd_log_modules(["md"])
         self._acme_server = self.get_acme_server()
         self._acme_tos = "accepted"
         self._acme_ca_pemfile = os.path.join(self.gen_dir, "apache/acme-ca.pem")
@@ -119,11 +121,8 @@ class MDTestEnv(HttpdTestEnv):
             CertificateSpec(domains=["localhost"], key_type='rsa2048'),
         ])
 
-        if setup_dirs:
-            self._setup = MDTestSetup(env=self)
-            self._setup.make()
-            self.issue_certs()
-            self.clear_store()
+    def setup_httpd(self, setup: HttpdTestSetup = None):
+        super().setup_httpd(setup=MDTestSetup(env=self))
 
     def set_store_dir_default(self):
         dirpath = "md"
@@ -134,8 +133,10 @@ class MDTestEnv(HttpdTestEnv):
     def set_store_dir(self, dirpath):
         self._store_dir = os.path.join(self.server_dir, dirpath)
         if self.acme_url:
-            self.a2md_stdargs([self.a2md_bin, "-a", self.acme_url, "-d", self._store_dir,  "-C", self.acme_ca_pemfile, "-j"])
-            self.a2md_rawargs([self.a2md_bin, "-a", self.acme_url, "-d", self._store_dir,  "-C", self.acme_ca_pemfile])
+            self.a2md_stdargs([self.a2md_bin, "-a", self.acme_url,
+                               "-d", self._store_dir,  "-C", self.acme_ca_pemfile, "-j"])
+            self.a2md_rawargs([self.a2md_bin, "-a", self.acme_url,
+                               "-d", self._store_dir,  "-C", self.acme_ca_pemfile])
 
     def get_apxs_var(self, name: str) -> str:
         p = subprocess.run([self._apxs, "-q", name], capture_output=True, text=True)
@@ -430,12 +431,11 @@ class MDTestEnv(HttpdTestEnv):
         assert r.exit_code == 0
         return r.stdout
 
-    def get_json_content(self, domain, path, use_https=True, insecure=False,
-                         debug_log=True):
+    def get_json_content(self, domain, path, use_https=True, insecure=False):
         schema = "https" if use_https else "http"
         port = self.https_port if use_https else self.http_port
         url = f"{schema}://{domain}:{port}{path}"
-        r = self.curl_get(url, insecure=insecure, debug_log=debug_log)
+        r = self.curl_get(url, insecure=insecure)
         if r.exit_code != 0:
             log.error(f"curl get on {url} returned {r.exit_code}"
                       f"\nstdout: {r.stdout}"
@@ -446,11 +446,11 @@ class MDTestEnv(HttpdTestEnv):
     def get_certificate_status(self, domain) -> Dict:
         return self.get_json_content(domain, "/.httpd/certificate-status", insecure=True)
 
-    def get_md_status(self, domain, via_domain=None, use_https=True, debug_log=False) -> Dict:
+    def get_md_status(self, domain, via_domain=None, use_https=True) -> Dict:
         if via_domain is None:
             via_domain = self._default_domain
         return self.get_json_content(via_domain, f"/md-status/{domain}",
-                                     use_https=use_https, debug_log=debug_log)
+                                     use_https=use_https)
 
     def get_server_status(self, query="/", via_domain=None, use_https=True):
         if via_domain is None:
@@ -521,7 +521,6 @@ class MDTestEnv(HttpdTestEnv):
                         and md['renewal']['errors'] >= errors:
                     return md
             time.sleep(0.1)
-        return None
 
     def await_file(self, fpath, timeout=60):
         try_until = time.time() + timeout
@@ -603,4 +602,4 @@ class MDTestEnv(HttpdTestEnv):
         dirpath = path
         if not path:
             dirpath = os.path.join(self.store_domains(), name_list[0])
-        return MDCertUtil.create_self_signed_cert(dirpath, name_list, valid_days, serial)
\ No newline at end of file
+        return MDCertUtil.create_self_signed_cert(dirpath, name_list, valid_days, serial)

Modified: httpd/httpd/trunk/test/modules/md/test_502_acmev2_drive.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/test_502_acmev2_drive.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/test_502_acmev2_drive.py (original)
+++ httpd/httpd/trunk/test/modules/md/test_502_acmev2_drive.py Mon Nov  8 12:33:46 2021
@@ -370,7 +370,7 @@ class TestDrivev2:
         env.run(["openssl", "s_client",
                  f"-connect", "localhost:{env.https_port}",
                  "-servername", "example.com", "-crlf"
-                 ], input="GET https:// HTTP/1.1\nHost: example.com\n\n")
+                 ], intext="GET https:// HTTP/1.1\nHost: example.com\n\n")
         assert env.apache_restart() == 0
 
     # --------- critical state change -> drive again ---------

Modified: httpd/httpd/trunk/test/pyhttpd/conf.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/pyhttpd/conf.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/pyhttpd/conf.py (original)
+++ httpd/httpd/trunk/test/pyhttpd/conf.py Mon Nov  8 12:33:46 2021
@@ -104,7 +104,6 @@ class HttpdConf(object):
         self.add([
             "<Location /006>",
             "    Options +Indexes",
-            "    HeaderName /006/header.html",
             "</Location>",
         ])
         self.add_proxies("test1", proxy_self, h2proxy_self)
@@ -121,7 +120,6 @@ class HttpdConf(object):
         self.add([
             "<Location /006>",
             "    Options +Indexes",
-            "    HeaderName /006/header.html",
             "</Location>",
         ])
         self.end_vhost()

Modified: httpd/httpd/trunk/test/pyhttpd/env.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/pyhttpd/env.py?rev=1894832&r1=1894831&r2=1894832&view=diff
==============================================================================
--- httpd/httpd/trunk/test/pyhttpd/env.py (original)
+++ httpd/httpd/trunk/test/pyhttpd/env.py Mon Nov  8 12:33:46 2021
@@ -35,7 +35,6 @@ class HttpdTestSetup:
         "logio",
         "unixd",
         "version",
-        "watchdog",
         "authn_core",
         "authz_host",
         "authz_groupfile",
@@ -56,32 +55,35 @@ class HttpdTestSetup:
         "setenvif",
         "slotmem_shm",
         "status",
-        "autoindex",
-        "cgid",
         "dir",
         "alias",
         "rewrite",
         "deflate",
         "proxy",
         "proxy_http",
-        "proxy_balancer",
-        "proxy_hcheck",
     ]
 
     def __init__(self, env: 'HttpdTestEnv'):
         self.env = env
+        self._source_dirs = [os.path.dirname(inspect.getfile(HttpdTestSetup))]
+        self._modules = HttpdTestSetup.MODULES.copy()
 
-    def make(self, modules: List[str] = None, add_modules: List[str] = None):
+    def add_source_dir(self, source_dir):
+        self._source_dirs.append(source_dir)
+
+    def add_modules(self, modules: List[str]):
+        for m in modules:
+            if m not in self._modules:
+                self._modules.append(m)
+
+    def make(self):
         self._make_dirs()
         self._make_conf()
-        mod_names = modules.copy() if modules else self.MODULES.copy()
-        if add_modules:
-            mod_names.extend(add_modules)
-        if self.env.mpm_module is not None and self.env.mpm_module not in mod_names:
-            mod_names.append(self.env.mpm_module)
-        if self.env.ssl_module is not None and self.env.ssl_module not in mod_names:
-            mod_names.append(self.env.ssl_module)
-        self._make_modules_conf(modules=mod_names)
+        if self.env.mpm_module is not None:
+            self.add_modules([self.env.mpm_module])
+        if self.env.ssl_module is not None:
+            self.add_modules([self.env.ssl_module])
+        self._make_modules_conf()
         self._make_htdocs()
         self.env.clear_curl_headerfiles()
 
@@ -93,18 +95,22 @@ class HttpdTestSetup:
             os.makedirs(self.env.server_logs_dir)
 
     def _make_conf(self):
-        our_dir = os.path.dirname(inspect.getfile(Dummy))
-        conf_src_dir = os.path.join(our_dir, 'conf')
+        # remove anything from another run/test suite
         conf_dest_dir = os.path.join(self.env.server_dir, 'conf')
-        if not os.path.exists(conf_dest_dir):
-            os.makedirs(conf_dest_dir)
-        for name in os.listdir(conf_src_dir):
-            src_path = os.path.join(conf_src_dir, name)
-            m = re.match(r'(.+).template', name)
-            if m:
-                self._make_template(src_path, os.path.join(conf_dest_dir, m.group(1)))
-            elif os.path.isfile(src_path):
-                shutil.copy(src_path, os.path.join(conf_dest_dir, name))
+        if os.path.isdir(conf_dest_dir):
+            shutil.rmtree(conf_dest_dir)
+        for d in self._source_dirs:
+            conf_src_dir = os.path.join(d, 'conf')
+            if os.path.isdir(conf_src_dir):
+                if not os.path.exists(conf_dest_dir):
+                    os.makedirs(conf_dest_dir)
+                for name in os.listdir(conf_src_dir):
+                    src_path = os.path.join(conf_src_dir, name)
+                    m = re.match(r'(.+).template', name)
+                    if m:
+                        self._make_template(src_path, os.path.join(conf_dest_dir, m.group(1)))
+                    elif os.path.isfile(src_path):
+                        shutil.copy(src_path, os.path.join(conf_dest_dir, name))
 
     def _make_template(self, src, dest):
         var_map = dict()
@@ -115,12 +121,12 @@ class HttpdTestSetup:
         with open(dest, 'w') as fd:
             fd.write(t.substitute(var_map))
 
-    def _make_modules_conf(self, modules: List[str]):
+    def _make_modules_conf(self):
         modules_conf = os.path.join(self.env.server_dir, 'conf/modules.conf')
         with open(modules_conf, 'w') as fd:
             # issue load directives for all modules we want that are shared
             missing_mods = list()
-            for m in modules:
+            for m in self._modules:
                 mod_path = os.path.join(self.env.libexec_dir, f"mod_{m}.so")
                 if os.path.isfile(mod_path):
                     fd.write(f"LoadModule {m}_module   \"{mod_path}\"\n")
@@ -133,18 +139,23 @@ class HttpdTestSetup:
                             f"DSOs: {self.env.dso_modules}")
 
     def _make_htdocs(self):
-        our_dir = os.path.dirname(inspect.getfile(Dummy))
         if not os.path.exists(self.env.server_docs_dir):
             os.makedirs(self.env.server_docs_dir)
-        shutil.copytree(os.path.join(our_dir, 'htdocs'),
-                        os.path.join(self.env.server_dir, 'htdocs'),
-                        dirs_exist_ok=True)
-        cgi_dir = os.path.join(self.env.server_dir, 'htdocs/cgi')
-        for name in os.listdir(cgi_dir):
-            if re.match(r'.+\.py', name):
-                cgi_file = os.path.join(cgi_dir, name)
-                st = os.stat(cgi_file)
-                os.chmod(cgi_file, st.st_mode | stat.S_IEXEC)
+        dest_dir = os.path.join(self.env.server_dir, 'htdocs')
+        # remove anything from another run/test suite
+        if os.path.isdir(dest_dir):
+            shutil.rmtree(dest_dir)
+        for d in self._source_dirs:
+            srcdocs = os.path.join(d, 'htdocs')
+            if os.path.isdir(srcdocs):
+                shutil.copytree(srcdocs, dest_dir, dirs_exist_ok=True)
+        # make all contained .py scripts executable
+        for dirpath, _dirnames, filenames in os.walk(dest_dir):
+            for fname in filenames:
+                if re.match(r'.+\.py', fname):
+                    py_file = os.path.join(dirpath, fname)
+                    st = os.stat(py_file)
+                    os.chmod(py_file, st.st_mode | stat.S_IEXEC)
 
 
 class HttpdTestEnv:
@@ -153,11 +164,8 @@ class HttpdTestEnv:
     def get_ssl_module(cls):
         return os.environ['SSL'] if 'SSL' in os.environ else 'ssl'
 
-    def __init__(self, pytestconfig=None,
-                 local_dir=None, add_base_conf: List[str] = None,
-                 interesting_modules: List[str] = None):
+    def __init__(self, pytestconfig=None):
         self._our_dir = os.path.dirname(inspect.getfile(Dummy))
-        self._local_dir = local_dir if local_dir else self._our_dir
         self.config = ConfigParser(interpolation=ExtendedInterpolation())
         self.config.read(os.path.join(self._our_dir, 'config.ini'))
 
@@ -196,24 +204,12 @@ class HttpdTestEnv:
         self._http_base = f"http://{self._httpd_addr}:{self.http_port}"
         self._https_base = f"https://{self._httpd_addr}:{self.https_port}"
 
+        self._verbosity = pytestconfig.option.verbose if pytestconfig is not None else 0
         self._test_conf = os.path.join(self._server_conf_dir, "test.conf")
         self._httpd_base_conf = []
-        if add_base_conf:
-            self._httpd_base_conf.extend(add_base_conf)
-
-        self._verbosity = pytestconfig.option.verbose if pytestconfig is not None else 0
-        if self._verbosity >= 2:
-            log_level = "trace2"
-            self._httpd_base_conf .append(f"LogLevel core:trace5 {self.mpm_module}:trace5")
-        elif self._verbosity >= 1:
-            log_level = "debug"
-        else:
-            log_level = "info"
-        if interesting_modules:
-            l = "LogLevel"
-            for name in interesting_modules:
-                l += f" {name}:{log_level}"
-            self._httpd_base_conf.append(l)
+        self._httpd_log_modules = []
+        self._log_interesting = None
+        self._setup = None
 
         self._ca = None
         self._cert_specs = [CertificateSpec(domains=[
@@ -226,6 +222,35 @@ class HttpdTestEnv:
         self._verify_certs = False
         self._curl_headerfiles_n = 0
 
+    def add_httpd_conf(self, lines: List[str]):
+        self._httpd_base_conf.extend(lines)
+
+    def add_httpd_log_modules(self, modules: List[str]):
+        self._httpd_log_modules.extend(modules)
+
+    def issue_certs(self):
+        if self._ca is None:
+            self._ca = HttpdTestCA.create_root(name=self.http_tld,
+                                               store_dir=os.path.join(self.server_dir, 'ca'),
+                                               key_type="rsa4096")
+        self._ca.issue_certs(self._cert_specs)
+
+    def setup_httpd(self, setup: HttpdTestSetup = None):
+        """Create the server environment with config, htdocs and certificates"""
+        self._setup = setup if setup is not None else HttpdTestSetup(env=self)
+        self._setup.make()
+        self.issue_certs()
+        if self._httpd_log_modules:
+            if self._verbosity >= 2:
+                log_level = "trace2"
+            elif self._verbosity >= 1:
+                log_level = "debug"
+            else:
+                log_level = "info"
+            self._log_interesting = "LogLevel"
+            for name in self._httpd_log_modules:
+                self._log_interesting += f" {name}:{log_level}"
+
     @property
     def apxs(self) -> str:
         return self._apxs
@@ -283,10 +308,6 @@ class HttpdTestEnv:
         return self._gen_dir
 
     @property
-    def local_dir(self) -> str:
-        return self._local_dir
-
-    @property
     def test_dir(self) -> str:
         return self._test_dir
 
@@ -319,16 +340,9 @@ class HttpdTestEnv:
         return self._server_docs_dir
 
     @property
-    def httpd_base_conf(self) -> List[str]:
-        return self._httpd_base_conf
-
-    @property
     def httpd_error_log(self) -> HttpdErrorLog:
         return self._error_log
 
-    def local_src(self, path):
-        return os.path.join(self.local_dir, path)
-
     def htdocs_src(self, path):
         return os.path.join(self._our_dir, 'htdocs', path)
 
@@ -347,13 +361,6 @@ class HttpdTestEnv:
     def add_cert_specs(self, specs: List[CertificateSpec]):
         self._cert_specs.extend(specs)
 
-    def issue_certs(self):
-        if self._ca is None:
-            self._ca = HttpdTestCA.create_root(name=self.http_tld,
-                                               store_dir=os.path.join(self.server_dir, 'ca'),
-                                               key_type="rsa4096")
-        self._ca.issue_certs(self._cert_specs)
-
     def get_credentials_for_name(self, dns_name) -> List['Credentials']:
         for spec in self._cert_specs:
             if dns_name in spec.domains:
@@ -396,12 +403,12 @@ class HttpdTestEnv:
         if not os.path.exists(path):
             return os.makedirs(path)
 
-    def run(self, args, input=None, debug_log=True):
+    def run(self, args, intext=None, debug_log=True):
         if debug_log:
             log.debug(f"run: {args}")
         start = datetime.now()
         p = subprocess.run(args, stderr=subprocess.PIPE, stdout=subprocess.PIPE,
-                           input=input.encode() if input else None)
+                           input=intext.encode() if intext else None)
         return ExecResult(args=args, exit_code=p.returncode,
                           stdout=p.stdout, stderr=p.stderr,
                           duration=datetime.now() - start)
@@ -413,7 +420,11 @@ class HttpdTestEnv:
     def install_test_conf(self, lines: List[str]):
         with open(self._test_conf, 'w') as fd:
             fd.write('\n'.join(self._httpd_base_conf))
-            fd.write('\n')
+            if self._verbosity >= 2:
+                fd.write(f"LogLevel core:trace5 {self.mpm_module}:trace5\n")
+            if self._log_interesting:
+                fd.write(self._log_interesting)
+            fd.write('\n\n')
             fd.write('\n'.join(lines))
             fd.write('\n')
 
@@ -427,7 +438,7 @@ class HttpdTestEnv:
         while datetime.now() < try_until:
             # noinspection PyBroadException
             try:
-                r = self.curl_get(url, insecure=True, debug_log=False)
+                r = self.curl_get(url, insecure=True)
                 if r.exit_code == 0:
                     return True
                 time.sleep(.1)
@@ -452,7 +463,7 @@ class HttpdTestEnv:
         while datetime.now() < try_until:
             # noinspection PyBroadException
             try:
-                r = self.curl_get(url, debug_log=False)
+                r = self.curl_get(url)
                 if r.exit_code != 0:
                     return True
                 time.sleep(.1)
@@ -596,7 +607,7 @@ class HttpdTestEnv:
         return r
 
     def curl_raw(self, urls, timeout=10, options=None, insecure=False,
-                 debug_log=True, force_resolve=True):
+                 force_resolve=True):
         xopt = ['-vvvv']
         if options:
             xopt.extend(options)
@@ -611,9 +622,8 @@ class HttpdTestEnv:
         os.remove(headerfile)
         return r
 
-    def curl_get(self, url, insecure=False, debug_log=True, options=None):
-        return self.curl_raw([url], insecure=insecure,
-                             options=options, debug_log=debug_log)
+    def curl_get(self, url, insecure=False, options=None):
+        return self.curl_raw([url], insecure=insecure, options=options)
 
     def curl_upload(self, url, fpath, timeout=5, options=None):
         if not options: