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/12/14 11:26:53 UTC

svn commit: r1895945 [1/4] - in /httpd/httpd/branches/2.4.x: ./ test/ test/modules/http2/ test/modules/http2/conf/ test/modules/http2/data/ test/modules/http2/htdocs/ test/modules/http2/htdocs/cgi/ test/modules/http2/htdocs/test1/ test/modules/http2/ht...

Author: icing
Date: Tue Dec 14 11:26:52 2021
New Revision: 1895945

URL: http://svn.apache.org/viewvc?rev=1895945&view=rev
Log:
  * test: updated pytest test/modules/http2 suite from trunk
    with skips for cases where backports have not been done.


Added:
    httpd/httpd/branches/2.4.x/test/conftest.py
    httpd/httpd/branches/2.4.x/test/modules/http2/__init__.py
    httpd/httpd/branches/2.4.x/test/modules/http2/env.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_005_files.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_501_proxy_serverheader.py
    httpd/httpd/branches/2.4.x/test/pyhttpd/
    httpd/httpd/branches/2.4.x/test/pyhttpd/__init__.py
    httpd/httpd/branches/2.4.x/test/pyhttpd/certs.py
    httpd/httpd/branches/2.4.x/test/pyhttpd/conf/
    httpd/httpd/branches/2.4.x/test/pyhttpd/conf.py
    httpd/httpd/branches/2.4.x/test/pyhttpd/conf/httpd.conf.template
    httpd/httpd/branches/2.4.x/test/pyhttpd/conf/mime.types
    httpd/httpd/branches/2.4.x/test/pyhttpd/conf/stop.conf.template
    httpd/httpd/branches/2.4.x/test/pyhttpd/conf/test.conf
    httpd/httpd/branches/2.4.x/test/pyhttpd/config.ini.in
    httpd/httpd/branches/2.4.x/test/pyhttpd/curl.py
    httpd/httpd/branches/2.4.x/test/pyhttpd/env.py
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/alive.json
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/forbidden.html
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/index.html
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/001.html
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/002.jpg   (with props)
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/003/
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/003.html
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/003/003_img.jpg   (with props)
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/004/
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/004.html
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/004/gophertiles.jpg   (with props)
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/006/
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/006.html
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/006/006.css
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/006/006.js
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/006/header.html
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/007/
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/007.html
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/007/007.py
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/009.py
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/alive.json
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test1/index.html
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test2/
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test2/006/
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test2/006/006.css   (with props)
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test2/10%abnormal.txt
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test2/alive.json
    httpd/httpd/branches/2.4.x/test/pyhttpd/htdocs/test2/x%2f.test
    httpd/httpd/branches/2.4.x/test/pyhttpd/log.py
    httpd/httpd/branches/2.4.x/test/pyhttpd/nghttp.py
    httpd/httpd/branches/2.4.x/test/pyhttpd/result.py
Removed:
    httpd/httpd/branches/2.4.x/test/modules/http2/conf/
    httpd/httpd/branches/2.4.x/test/modules/http2/config.ini.in
    httpd/httpd/branches/2.4.x/test/modules/http2/data/
    httpd/httpd/branches/2.4.x/test/modules/http2/h2_certs.py
    httpd/httpd/branches/2.4.x/test/modules/http2/h2_conf.py
    httpd/httpd/branches/2.4.x/test/modules/http2/h2_curl.py
    httpd/httpd/branches/2.4.x/test/modules/http2/h2_env.py
    httpd/httpd/branches/2.4.x/test/modules/http2/h2_nghttp.py
    httpd/httpd/branches/2.4.x/test/modules/http2/h2_result.py
    httpd/httpd/branches/2.4.x/test/modules/http2/htdocs/alive.json
    httpd/httpd/branches/2.4.x/test/modules/http2/htdocs/forbidden.html
    httpd/httpd/branches/2.4.x/test/modules/http2/htdocs/index.html
    httpd/httpd/branches/2.4.x/test/modules/http2/htdocs/test1/
    httpd/httpd/branches/2.4.x/test/modules/http2/htdocs/test2/
    httpd/httpd/branches/2.4.x/test/modules/http2/test_000_infra.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_005_status.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_203_encoding.py
Modified:
    httpd/httpd/branches/2.4.x/configure.in
    httpd/httpd/branches/2.4.x/test/   (props changed)
    httpd/httpd/branches/2.4.x/test/Makefile.in
    httpd/httpd/branches/2.4.x/test/modules/http2/conftest.py
    httpd/httpd/branches/2.4.x/test/modules/http2/htdocs/cgi/echo.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_001_httpd_alive.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_002_curl_basics.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_003_get.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_004_post.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_006_assets.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_100_conn_reuse.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_101_ssl_reneg.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_102_require.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_103_upgrade.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_104_padding.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_105_timeout.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_106_shutdown.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_200_header_invalid.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_201_header_conditional.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_202_trailer.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_300_interim.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_400_push.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_401_early_hints.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_500_proxy.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_600_h2proxy.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_700_load_get.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_710_load_post_static.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_711_load_post_cgi.py
    httpd/httpd/branches/2.4.x/test/modules/http2/test_712_buffering.py

Modified: httpd/httpd/branches/2.4.x/configure.in
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/configure.in?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/configure.in (original)
+++ httpd/httpd/branches/2.4.x/configure.in Tue Dec 14 11:26:52 2021
@@ -844,8 +844,8 @@ if test -d ./test; then
     APACHE_FAST_OUTPUT(test/Makefile)
 fi
 if test -d ./test/modules/http2; then
-    APACHE_FAST_OUTPUT(test/modules/http2/Makefile)
-    AC_CONFIG_FILES([test/modules/http2/config.ini])
+    APACHE_FAST_OUTPUT(test/Makefile)
+    AC_CONFIG_FILES([test/pyhttpd/config.ini])
 fi
 
 dnl ## Finalize the variables

Propchange: httpd/httpd/branches/2.4.x/test/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Tue Dec 14 11:26:52 2021
@@ -18,3 +18,4 @@ sni
 httpdunit
 httpdunit.cases
 .pytest_cache
+gen

Modified: httpd/httpd/branches/2.4.x/test/Makefile.in
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/Makefile.in?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/Makefile.in (original)
+++ httpd/httpd/branches/2.4.x/test/Makefile.in Tue Dec 14 11:26:52 2021
@@ -18,3 +18,9 @@ test: $(bin_PROGRAMS)
 # dbu_OBJECTS = dbu.lo
 # dbu: $(dbu_OBJECTS)
 #	$(LINK) $(dbu_OBJECTS) $(PROGRAM_LDADD)
+
+clean:
+	rm -rf gen
+
+distclean:
+	rm -f pyhttpd/config.ini
\ No newline at end of file

Added: httpd/httpd/branches/2.4.x/test/conftest.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/conftest.py?rev=1895945&view=auto
==============================================================================
--- httpd/httpd/branches/2.4.x/test/conftest.py (added)
+++ httpd/httpd/branches/2.4.x/test/conftest.py Tue Dec 14 11:26:52 2021
@@ -0,0 +1,12 @@
+import sys
+import os
+
+sys.path.append(os.path.join(os.path.dirname(__file__), '.'))
+
+from pyhttpd.env import HttpdTestEnv
+
+def pytest_report_header(config, startdir):
+    env = HttpdTestEnv()
+    return f"[apache httpd: {env.get_httpd_version()}, mpm: {env.mpm_module}, {env.prefix}]"
+
+

Added: httpd/httpd/branches/2.4.x/test/modules/http2/__init__.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/__init__.py?rev=1895945&view=auto
==============================================================================
    (empty)

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/conftest.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/conftest.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/conftest.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/conftest.py Tue Dec 14 11:26:52 2021
@@ -2,14 +2,16 @@ import logging
 import os
 
 import pytest
+import sys
 
-from h2_certs import CertificateSpec, H2TestCA
-from h2_env import H2TestEnv
+sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
+
+from .env import H2TestEnv
 
 
 def pytest_report_header(config, startdir):
-    env = H2TestEnv(setup_dirs=False)
-    return f"mod_h2 [apache: {env.get_httpd_version()}, mpm: {env.mpm_type}, {env.prefix}]"
+    env = H2TestEnv()
+    return f"mod_h2 [apache: {env.get_httpd_version()}, mpm: {env.mpm_module}, {env.prefix}]"
 
 
 def pytest_addoption(parser):
@@ -25,7 +27,7 @@ def pytest_generate_tests(metafunc):
         metafunc.parametrize('repeat', range(count))
 
 
-@pytest.fixture(scope="session")
+@pytest.fixture(scope="package")
 def env(pytestconfig) -> H2TestEnv:
     level = logging.INFO
     console = logging.StreamHandler()
@@ -34,24 +36,17 @@ def env(pytestconfig) -> H2TestEnv:
     logging.getLogger('').addHandler(console)
     logging.getLogger('').setLevel(level=level)
     env = H2TestEnv(pytestconfig=pytestconfig)
-    cert_specs = [
-        CertificateSpec(domains=env.domains, key_type='rsa4096'),
-        CertificateSpec(domains=env.domains_noh2, key_type='rsa2048'),
-    ]
-    ca = H2TestCA.create_root(name=env.http_tld,
-                              store_dir=os.path.join(env.server_dir, 'ca'), key_type="rsa4096")
-    ca.issue_certs(cert_specs)
-    env.set_ca(ca)
+    env.setup_httpd()
     env.apache_access_log_clear()
-    env.apache_error_log_clear()
+    env.httpd_error_log.clear_log()
     return env
 
 
-@pytest.fixture(autouse=True, scope="session")
+@pytest.fixture(autouse=True, scope="package")
 def _session_scope(env):
     yield
     assert env.apache_stop() == 0
-    errors, warnings = env.apache_errors_and_warnings()
+    errors, warnings = env.httpd_error_log.get_missed()
     assert (len(errors), len(warnings)) == (0, 0),\
             f"apache logged {len(errors)} errors and {len(warnings)} warnings: \n"\
             "{0}\n{1}\n".format("\n".join(errors), "\n".join(warnings))

Added: httpd/httpd/branches/2.4.x/test/modules/http2/env.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/env.py?rev=1895945&view=auto
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/env.py (added)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/env.py Tue Dec 14 11:26:52 2021
@@ -0,0 +1,141 @@
+import inspect
+import logging
+import os
+import re
+import subprocess
+from typing import Dict, Any
+
+from pyhttpd.certs import CertificateSpec
+from pyhttpd.conf import HttpdConf
+from pyhttpd.env import HttpdTestEnv, HttpdTestSetup
+
+log = logging.getLogger(__name__)
+
+
+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", "ssl"])
+
+    def make(self):
+        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(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:
+            # load our test module which is not installed
+            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):
+        super().__init__(pytestconfig=pytestconfig)
+        self.add_httpd_conf([
+                             "H2MinWorkers 1",
+                             "H2MaxWorkers 64",
+                             "Protocols h2 http/1.1 h2c",
+                         ])
+        self.add_httpd_log_modules(["http2", "proxy_http2", "h2test"])
+        self.add_cert_specs([
+            CertificateSpec(domains=[
+                f"push.{self._http_tld}",
+                f"hints.{self._http_tld}",
+                f"ssl.{self._http_tld}",
+                f"pad0.{self._http_tld}",
+                f"pad1.{self._http_tld}",
+                f"pad2.{self._http_tld}",
+                f"pad3.{self._http_tld}",
+                f"pad8.{self._http_tld}",
+            ]),
+            CertificateSpec(domains=[f"noh2.{self.http_tld}"], key_type='rsa2048'),
+        ])
+
+        self.httpd_error_log.set_ignored_lognos([
+            'AH02032',
+            'AH01276',
+            'AH01630',
+            'AH00135',
+            'AH02261',  # Re-negotiation handshake failed (our test_101)
+            'AH03490',  # scoreboard full, happens on limit tests
+        ])
+        self.httpd_error_log.add_ignored_patterns([
+            re.compile(r'.*malformed header from script \'hecho.py\': Bad header: x.*'),
+            re.compile(r'.*:tls_post_process_client_hello:.*'),
+            re.compile(r'.*:tls_process_client_certificate:.*'),
+            re.compile(r'.*have incompatible TLS configurations.'),
+        ])
+
+    def setup_httpd(self, setup: HttpdTestSetup = None):
+        super().setup_httpd(setup=H2TestSetup(env=self))
+
+
+class H2Conf(HttpdConf):
+
+    def __init__(self, env: HttpdTestEnv, extras: Dict[str, Any] = None):
+        super().__init__(env=env, extras=HttpdConf.merge_extras(extras, {
+            f"cgi.{env.http_tld}": [
+                "SSLOptions +StdEnvVars",
+                "AddHandler cgi-script .py",
+            ]
+        }))
+
+    def start_vhost(self, domains, port=None, doc_root="htdocs", with_ssl=None,
+                    ssl_module=None, with_certificates=None):
+        super().start_vhost(domains=domains, port=port, doc_root=doc_root,
+                            with_ssl=with_ssl, ssl_module=ssl_module,
+                            with_certificates=with_certificates)
+        if f"noh2.{self.env.http_tld}" in domains:
+            protos = ["http/1.1"]
+        elif port == self.env.https_port or with_ssl is True:
+            protos = ["h2", "http/1.1"]
+        else:
+            protos = ["h2c", "http/1.1"]
+        if f"test2.{self.env.http_tld}" in domains:
+            protos = reversed(protos)
+        self.add(f"Protocols {' '.join(protos)}")
+        return self
+
+    def add_vhost_noh2(self):
+        domains = [f"noh2.{self.env.http_tld}", f"noh2-alias.{self.env.http_tld}"]
+        self.start_vhost(domains=domains, port=self.env.https_port, doc_root="htdocs/noh2")
+        self.add(["Protocols http/1.1", "SSLOptions +StdEnvVars"])
+        self.end_vhost()
+        self.start_vhost(domains=domains, port=self.env.http_port, doc_root="htdocs/noh2")
+        self.add(["Protocols http/1.1", "SSLOptions +StdEnvVars"])
+        self.end_vhost()
+        return self
+
+    def add_vhost_test1(self, proxy_self=False, h2proxy_self=False):
+        return super().add_vhost_test1(proxy_self=proxy_self, h2proxy_self=h2proxy_self)
+
+    def add_vhost_test2(self):
+        return super().add_vhost_test2()

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/htdocs/cgi/echo.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/htdocs/cgi/echo.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/htdocs/cgi/echo.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/htdocs/cgi/echo.py Tue Dec 14 11:26:52 2021
@@ -9,6 +9,7 @@ for line in sys.stdin:
     
 # Just echo what we get
 print("Status: 200")
+print(f"Request-Length: {len(content)}")
 print("Content-Type: application/data\n")
 sys.stdout.write(content)
 

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/test_001_httpd_alive.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_001_httpd_alive.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_001_httpd_alive.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_001_httpd_alive.py Tue Dec 14 11:26:52 2021
@@ -1,28 +1,21 @@
 import pytest
 
-from h2_conf import HttpdConf
+from .env import H2Conf
 
 
-class TestStore:
+class TestBasicAlive:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        HttpdConf(env).add_vhost_test1().install()
+        H2Conf(env).add_vhost_test1().install()
         assert env.apache_restart() == 0
 
     # we expect to see the document from the generic server
-    def test_001_01(self, env):
-        r = env.curl_get(f"https://{env.domain_test1}:{env.https_port}/alive.json", 5)
+    def test_h2_001_01(self, env):
+        url = env.mkurl("https", "test1", "/alive.json")
+        r = env.curl_get(url, 5)
         assert r.exit_code == 0, r.stderr + r.stdout
         assert r.response["json"]
-        assert True == r.response["json"]["alive"]
-        assert "test1" == r.response["json"]["host"]
-
-    # we expect to see the document from the generic server
-    def test_001_02(self, env):
-        r = env.curl_get(f"https://{env.domain_test1}:{env.https_port}/alive.json", 5)
-        assert r.exit_code == 0, r.stderr
-        assert r.response["json"]
-        assert True == r.response["json"]["alive"]
-        assert "test1" == r.response["json"]["host"]
+        assert r.response["json"]["alive"] is True
+        assert r.response["json"]["host"] == "test1"
 

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/test_002_curl_basics.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_002_curl_basics.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_002_curl_basics.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_002_curl_basics.py Tue Dec 14 11:26:52 2021
@@ -1,68 +1,70 @@
 import pytest
 
-from h2_conf import HttpdConf
+from .env import H2Conf
 
 
-class TestStore:
+class TestCurlBasics:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        HttpdConf(env).add_vhost_test1().add_vhost_test2().install()
+        conf = H2Conf(env)
+        conf.add_vhost_test1()
+        conf.add_vhost_test2()
+        conf.install()
         assert env.apache_restart() == 0
 
     # check that we see the correct documents when using the test1 server name over http:
-    def test_002_01(self, env):
+    def test_h2_002_01(self, env):
         url = env.mkurl("http", "test1", "/alive.json")
         r = env.curl_get(url, 5)
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         assert "HTTP/1.1" == r.response["protocol"]
-        assert True == r.response["json"]["alive"]
-        assert "test1" == r.response["json"]["host"]
+        assert r.response["json"]["alive"] is True
+        assert r.response["json"]["host"] == "test1"
 
     # check that we see the correct documents when using the test1 server name over https:
-    def test_002_02(self, env):
+    def test_h2_002_02(self, env):
         url = env.mkurl("https", "test1", "/alive.json")
         r = env.curl_get(url, 5)
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         assert r.response["json"]["alive"] is True
         assert "test1" == r.response["json"]["host"]
-        assert "application/json" == r.response["header"]["content-type"]
+        assert r.response["header"]["content-type"] == "application/json"
 
     # enforce HTTP/1.1
-    def test_002_03(self, env):
+    def test_h2_002_03(self, env):
         url = env.mkurl("https", "test1", "/alive.json")
-        r = env.curl_get(url, 5, [ "--http1.1" ])
-        assert 200 == r.response["status"]
-        assert "HTTP/1.1" == r.response["protocol"]
+        r = env.curl_get(url, 5, options=["--http1.1"])
+        assert r.response["status"] == 200
+        assert r.response["protocol"] == "HTTP/1.1"
 
     # enforce HTTP/2
-    def test_002_04(self, env):
+    def test_h2_002_04(self, env):
         url = env.mkurl("https", "test1", "/alive.json")
-        r = env.curl_get(url, 5, [ "--http2" ])
-        assert 200 == r.response["status"]
-        assert "HTTP/2" == r.response["protocol"]
+        r = env.curl_get(url, 5, options=["--http2"])
+        assert r.response["status"] == 200
+        assert r.response["protocol"] == "HTTP/2"
 
     # default is HTTP/2 on this host
-    def test_002_04b(self, env):
+    def test_h2_002_04b(self, env):
         url = env.mkurl("https", "test1", "/alive.json")
         r = env.curl_get(url, 5)
-        assert 200 == r.response["status"]
-        assert "HTTP/2" == r.response["protocol"]
-        assert "test1" == r.response["json"]["host"]
+        assert r.response["status"] == 200
+        assert r.response["protocol"] == "HTTP/2"
+        assert r.response["json"]["host"] == "test1"
 
     # although, without ALPN, we cannot select it
-    def test_002_05(self, env):
+    def test_h2_002_05(self, env):
         url = env.mkurl("https", "test1", "/alive.json")
-        r = env.curl_get(url, 5, [ "--no-alpn" ])
-        assert 200 == r.response["status"]
-        assert "HTTP/1.1" == r.response["protocol"]
-        assert "test1" == r.response["json"]["host"]
+        r = env.curl_get(url, 5, options=["--no-alpn"])
+        assert r.response["status"] == 200
+        assert r.response["protocol"] == "HTTP/1.1"
+        assert r.response["json"]["host"] == "test1"
 
     # default is HTTP/1.1 on the other
-    def test_002_06(self, env):
+    def test_h2_002_06(self, env):
         url = env.mkurl("https", "test2", "/alive.json")
         r = env.curl_get(url, 5)
-        assert 200 == r.response["status"]
-        assert "HTTP/1.1" == r.response["protocol"]
-        assert "test2" == r.response["json"]["host"]
-
+        assert r.response["status"] == 200
+        assert r.response["protocol"] == "HTTP/1.1"
+        assert r.response["json"]["host"] == "test2"

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/test_003_get.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_003_get.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_003_get.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_003_get.py Tue Dec 14 11:26:52 2021
@@ -1,14 +1,14 @@
 import re
 import pytest
 
-from h2_conf import HttpdConf
+from .env import H2Conf
 
 
-class TestStore:
+class TestGet:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        HttpdConf(env).add_vhost_cgi(
+        H2Conf(env).add_vhost_cgi(
             proxy_self=True, h2proxy_self=True
         ).add_vhost_test1(
             proxy_self=True, h2proxy_self=True
@@ -16,19 +16,19 @@ class TestStore:
         assert env.apache_restart() == 0
 
     # check SSL environment variables from CGI script
-    def test_003_01(self, env):
+    def test_h2_003_01(self, env):
         url = env.mkurl("https", "cgi", "/hello.py")
-        r = env.curl_get(url, 5, ["--tlsv1.2"])
-        assert 200 == r.response["status"]
-        assert "HTTP/2.0" == r.response["json"]["protocol"]
-        assert "on" == r.response["json"]["https"]
+        r = env.curl_get(url, 5, options=["--tlsv1.2"])
+        assert r.response["status"] == 200
+        assert r.response["json"]["protocol"] == "HTTP/2.0"
+        assert r.response["json"]["https"] == "on"
         tls_version = r.response["json"]["ssl_protocol"]
         assert tls_version in ["TLSv1.2", "TLSv1.3"]
-        assert "on" == r.response["json"]["h2"]
-        assert "off" == r.response["json"]["h2push"]
+        assert r.response["json"]["h2"] == "on"
+        assert r.response["json"]["h2push"] == "off"
 
-        r = env.curl_get(url, 5, ["--http1.1", "--tlsv1.2"])
-        assert 200 == r.response["status"]
+        r = env.curl_get(url, 5, options=["--http1.1", "--tlsv1.2"])
+        assert r.response["status"] == 200
         assert "HTTP/1.1" == r.response["json"]["protocol"]
         assert "on" == r.response["json"]["https"]
         tls_version = r.response["json"]["ssl_protocol"]
@@ -37,52 +37,52 @@ class TestStore:
         assert "" == r.response["json"]["h2push"]
 
     # retrieve a html file from the server and compare it to its source
-    def test_003_02(self, env):
-        with open(env.test_src("htdocs/test1/index.html"), mode='rb') as file:
+    def test_h2_003_02(self, env):
+        with open(env.htdocs_src("test1/index.html"), mode='rb') as file:
             src = file.read()
 
         url = env.mkurl("https", "test1", "/index.html")
         r = env.curl_get(url, 5)
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         assert "HTTP/2" == r.response["protocol"]
         assert src == r.response["body"]
 
         url = env.mkurl("https", "test1", "/index.html")
-        r = env.curl_get(url, 5, ["--http1.1"])
-        assert 200 == r.response["status"]
+        r = env.curl_get(url, 5, options=["--http1.1"])
+        assert r.response["status"] == 200
         assert "HTTP/1.1" == r.response["protocol"]
         assert src == r.response["body"]
 
     # retrieve chunked content from a cgi script
     def check_necho(self, env, n, text):
         url = env.mkurl("https", "cgi", "/necho.py")
-        r = env.curl_get(url, 5, ["-F", f"count={n}", "-F", f"text={text}"])
-        assert 200 == r.response["status"]
+        r = env.curl_get(url, 5, options=["-F", f"count={n}", "-F", f"text={text}"])
+        assert r.response["status"] == 200
         exp = ""
         for i in range(n):
             exp += text + "\n"
         assert exp == r.response["body"].decode('utf-8')
     
-    def test_003_10(self, env):
+    def test_h2_003_10(self, env):
         self.check_necho(env, 10, "0123456789")
 
-    def test_003_11(self, env):
+    def test_h2_003_11(self, env):
         self.check_necho(env, 100, "0123456789")
 
-    def test_003_12(self, env):
+    def test_h2_003_12(self, env):
         self.check_necho(env, 1000, "0123456789")
 
-    def test_003_13(self, env):
+    def test_h2_003_13(self, env):
         self.check_necho(env, 10000, "0123456789")
 
-    def test_003_14(self, env):
+    def test_h2_003_14(self, env):
         self.check_necho(env, 100000, "0123456789")
 
     # github issue #126
-    def test_003_20(self, env):
+    def test_h2_003_20(self, env):
         url = env.mkurl("https", "test1", "/006/")
         r = env.curl_get(url, 5)
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         body = r.response["body"].decode('utf-8')
         # our doctype varies between branches and in time, lets not compare
         body = re.sub(r'^<!DOCTYPE[^>]+>', '', body)
@@ -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>
@@ -111,10 +111,10 @@ class TestStore:
         s = re.sub(r'^vary:.*\n', '', s, flags=re.MULTILINE)
         return re.sub(r'^accept-ranges:.*\n', '', s, flags=re.MULTILINE)
         
-    def test_003_21(self, env):
+    def test_h2_003_21(self, env):
         url = env.mkurl("https", "test1", "/index.html")
-        r = env.curl_get(url, 5, ["-I"])
-        assert 200 == r.response["status"]
+        r = env.curl_get(url, 5, options=["-I"])
+        assert r.response["status"] == 200
         assert "HTTP/2" == r.response["protocol"]
         s = self.clean_header(r.response["body"].decode('utf-8'))
         assert '''HTTP/2 200 
@@ -123,8 +123,8 @@ content-type: text/html
 
 ''' == s
 
-        r = env.curl_get(url, 5, ["-I", url])
-        assert 200 == r.response["status"]
+        r = env.curl_get(url, 5, options=["-I", url])
+        assert r.response["status"] == 200
         assert "HTTP/2" == r.response["protocol"]
         s = self.clean_header(r.response["body"].decode('utf-8'))
         assert '''HTTP/2 200 
@@ -141,39 +141,39 @@ content-type: text/html
     @pytest.mark.parametrize("path", [
         "/004.html", "/proxy/004.html", "/h2proxy/004.html"
     ])
-    def test_003_30(self, env, path):
+    def test_h2_003_30(self, env, path):
         url = env.mkurl("https", "test1", path)
         r = env.curl_get(url, 5)
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         assert "HTTP/2" == r.response["protocol"]
         h = r.response["header"]
         assert "last-modified" in h
         lastmod = h["last-modified"]
-        r = env.curl_get(url, 5, ['-H', ("if-modified-since: %s" % lastmod)])
+        r = env.curl_get(url, 5, options=['-H', ("if-modified-since: %s" % lastmod)])
         assert 304 == r.response["status"]
 
     # test conditionals: if-etag
     @pytest.mark.parametrize("path", [
         "/004.html", "/proxy/004.html", "/h2proxy/004.html"
     ])
-    def test_003_31(self, env, path):
+    def test_h2_003_31(self, env, path):
         url = env.mkurl("https", "test1", path)
         r = env.curl_get(url, 5)
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         assert "HTTP/2" == r.response["protocol"]
         h = r.response["header"]
         assert "etag" in h
         etag = h["etag"]
-        r = env.curl_get(url, 5, ['-H', ("if-none-match: %s" % etag)])
+        r = env.curl_get(url, 5, options=['-H', ("if-none-match: %s" % etag)])
         assert 304 == r.response["status"]
 
     # test various response body lengths to work correctly 
-    def test_003_40(self, env):
+    def test_h2_003_40(self, env):
         n = 1001
         while n <= 1025024:
             url = env.mkurl("https", "cgi", f"/mnot164.py?count={n}&text=X")
             r = env.curl_get(url, 5)
-            assert 200 == r.response["status"]
+            assert r.response["status"] == 200
             assert "HTTP/2" == r.response["protocol"]
             assert n == len(r.response["body"])
             n *= 2
@@ -182,10 +182,10 @@ content-type: text/html
     @pytest.mark.parametrize("n", [
         0, 1, 1291, 1292, 80000, 80123, 81087, 98452
     ])
-    def test_003_41(self, env, n):
+    def test_h2_003_41(self, env, n):
         url = env.mkurl("https", "cgi", f"/mnot164.py?count={n}&text=X")
         r = env.curl_get(url, 5)
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         assert "HTTP/2" == r.response["protocol"]
         assert n == len(r.response["body"])
         
@@ -193,11 +193,11 @@ content-type: text/html
     @pytest.mark.parametrize("path", [
         "/004.html", "/proxy/004.html", "/h2proxy/004.html"
     ])
-    def test_003_50(self, env, path):
+    def test_h2_003_50(self, env, path):
         # check that the resource supports ranges and we see its raw content-length
         url = env.mkurl("https", "test1", path)
         r = env.curl_get(url, 5)
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         assert "HTTP/2" == r.response["protocol"]
         h = r.response["header"]
         assert "accept-ranges" in h

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/test_004_post.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_004_post.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_004_post.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_004_post.py Tue Dec 14 11:26:52 2021
@@ -1,57 +1,64 @@
+import difflib
 import email.parser
+import inspect
 import json
 import os
 import re
+import sys
+
 import pytest
 
-from h2_conf import HttpdConf
+from .env import H2Conf
 
 
-class TestStore:
+class TestPost:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        env.setup_data_1k_1m()
-        HttpdConf(env).add_vhost_cgi().install()
+        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")
         fpath = os.path.join(env.gen_dir, fname)
         r = env.curl_upload(url, fpath, options=options)
-        assert r.exit_code == 0, r.stderr
-        assert r.response["status"] >= 200 and r.response["status"] < 300
+        assert r.exit_code == 0, f"{r}"
+        assert 200 <= r.response["status"] < 300
 
         r2 = env.curl_get(r.response["header"]["location"])
         assert r2.exit_code == 0
         assert r2.response["status"] == 200
-        with open(env.test_src(fpath), mode='rb') as file:
+        with open(self.local_src(fpath), mode='rb') as file:
             src = file.read()
         assert src == r2.response["body"]
 
-    def test_004_01(self, env):
-        self.curl_upload_and_verify(env, "data-1k", ["--http1.1"])
+    def test_h2_004_01(self, env):
+        self.curl_upload_and_verify(env, "data-1k", ["-vvv", "--http1.1"])
         self.curl_upload_and_verify(env, "data-1k", ["--http2"])
 
-    def test_004_02(self, env):
+    def test_h2_004_02(self, env):
         self.curl_upload_and_verify(env, "data-10k", ["--http1.1"])
         self.curl_upload_and_verify(env, "data-10k", ["--http2"])
 
-    def test_004_03(self, env):
+    def test_h2_004_03(self, env):
         self.curl_upload_and_verify(env, "data-100k", ["--http1.1"])
         self.curl_upload_and_verify(env, "data-100k", ["--http2"])
 
-    def test_004_04(self, env):
+    def test_h2_004_04(self, env):
         self.curl_upload_and_verify(env, "data-1m", ["--http1.1"])
         self.curl_upload_and_verify(env, "data-1m", ["--http2"])
 
-    def test_004_05(self, env):
+    def test_h2_004_05(self, env):
         self.curl_upload_and_verify(env, "data-1k", ["-v", "--http1.1", "-H", "Expect: 100-continue"])
         self.curl_upload_and_verify(env, "data-1k", ["-v", "--http2", "-H", "Expect: 100-continue"])
 
     @pytest.mark.skipif(True, reason="python3 regresses in chunked inputs to cgi")
-    def test_004_06(self, env):
+    def test_h2_004_06(self, env):
         self.curl_upload_and_verify(env, "data-1k", ["--http1.1", "-H", "Content-Length: "])
         self.curl_upload_and_verify(env, "data-1k", ["--http2", "-H", "Content-Length: "])
 
@@ -63,7 +70,7 @@ class TestStore:
         ("H2_STREAM_ID", "1"),
         ("H2_STREAM_TAG", r'\d+-1'),
     ])
-    def test_004_07(self, env, name, value):
+    def test_h2_004_07(self, env, name, value):
         url = env.mkurl("https", "cgi", "/env.py")
         r = env.curl_post_value(url, "name", name)
         assert r.exit_code == 0
@@ -72,26 +79,6 @@ class TestStore:
         assert m
         assert re.match(value, m.group(1)) 
 
-    # verify that we parse nghttp output correctly
-    def check_nghttp_body(self, env, ref_input, nghttp_output):
-        with open(env.test_src(os.path.join(env.gen_dir, ref_input)), mode='rb') as f:
-            refbody = f.read()
-        with open(env.test_src(nghttp_output), mode='rb') as f:
-            text = f.read()
-        o = env.nghttp().parse_output(text)
-        assert "response" in o
-        assert "body" in o["response"]
-        if refbody != o["response"]["body"]:
-            with open(env.test_src(os.path.join(env.gen_dir, '%s.parsed' % ref_input)), mode='bw') as f:
-                f.write(o["response"]["body"])
-        assert len(refbody) == len(o["response"]["body"])
-        assert refbody == o["response"]["body"]
-    
-    def test_004_20(self, env):
-        self.check_nghttp_body(env, 'data-1k', 'data/nghttp-output-1k-1.txt')
-        self.check_nghttp_body(env, 'data-10k', 'data/nghttp-output-10k-1.txt')
-        self.check_nghttp_body(env, 'data-100k', 'data/nghttp-output-100k-1.txt')
-
     # POST some data using nghttp and see it echo'ed properly back
     def nghttp_post_and_verify(self, env, fname, options=None):
         url = env.mkurl("https", "cgi", "/echo.py")
@@ -101,20 +88,30 @@ class TestStore:
         assert r.exit_code == 0
         assert r.response["status"] >= 200 and r.response["status"] < 300
 
-        with open(env.test_src(fpath), mode='rb') as file:
+        with open(self.local_src(fpath), mode='rb') as file:
             src = file.read()
-        assert src == r.response["body"]
+        assert 'request-length' in r.response["header"]
+        assert int(r.response["header"]['request-length']) == len(src)
+        if len(r.response["body"]) != len(src):
+            sys.stderr.writelines(difflib.unified_diff(
+                src.decode().splitlines(True),
+                r.response["body"].decode().splitlines(True),
+                fromfile='source',
+                tofile='response'
+            ))
+            assert len(r.response["body"]) == len(src)
+        assert r.response["body"] == src, f"expected '{src}', got '{r.response['body']}'"
 
     @pytest.mark.parametrize("name", [
         "data-1k", "data-10k", "data-100k", "data-1m"
     ])
-    def test_004_21(self, env, name):
+    def test_h2_004_21(self, env, name):
         self.nghttp_post_and_verify(env, name, [])
 
     @pytest.mark.parametrize("name", [
-        "data-1k", "data-10k", "data-100k", "data-1m"
+        "data-1k", "data-10k", "data-100k", "data-1m",
     ])
-    def test_004_22(self, env, name, repeat):
+    def test_h2_004_22(self, env, name, repeat):
         self.nghttp_post_and_verify(env, name, ["--no-content-length"])
 
     # upload and GET again using nghttp, compare to original content
@@ -130,29 +127,29 @@ class TestStore:
         r2 = env.nghttp().get(r.response["header"]["location"])
         assert r2.exit_code == 0
         assert r2.response["status"] == 200
-        with open(env.test_src(fpath), mode='rb') as file:
+        with open(self.local_src(fpath), mode='rb') as file:
             src = file.read()
         assert src == r2.response["body"]
 
     @pytest.mark.parametrize("name", [
         "data-1k", "data-10k", "data-100k", "data-1m"
     ])
-    def test_004_23(self, env, name, repeat):
+    def test_h2_004_23(self, env, name, repeat):
         self.nghttp_upload_and_verify(env, name, [])
 
     @pytest.mark.parametrize("name", [
         "data-1k", "data-10k", "data-100k", "data-1m"
     ])
-    def test_004_24(self, env, name, repeat):
+    def test_h2_004_24(self, env, name, repeat):
         self.nghttp_upload_and_verify(env, name, ["--expect-continue"])
 
     @pytest.mark.parametrize("name", [
         "data-1k", "data-10k", "data-100k", "data-1m"
     ])
-    def test_004_25(self, env, name, repeat):
+    def test_h2_004_25(self, env, name, repeat):
         self.nghttp_upload_and_verify(env, name, ["--no-content-length"])
 
-    def test_004_30(self, env):
+    def test_h2_004_30(self, env):
         # issue: #203
         resource = "data-1k"
         full_length = 1000
@@ -161,18 +158,18 @@ class TestStore:
         logfile = os.path.join(env.server_logs_dir, "test_004_30")
         if os.path.isfile(logfile):
             os.remove(logfile)
-        HttpdConf(env).add("""
+        H2Conf(env).add("""
 LogFormat "{ \\"request\\": \\"%r\\", \\"status\\": %>s, \\"bytes_resp_B\\": %B, \\"bytes_tx_O\\": %O, \\"bytes_rx_I\\": %I, \\"bytes_rx_tx_S\\": %S }" issue_203
 CustomLog logs/test_004_30 issue_203
         """).add_vhost_cgi().install()
         assert env.apache_restart() == 0
         url = env.mkurl("https", "cgi", "/files/{0}".format(resource))
-        r = env.curl_get(url, 5, ["--http2"])
-        assert 200 == r.response["status"]
-        r = env.curl_get(url, 5, ["--http1.1", "-H", "Range: bytes=0-{0}".format(chunk-1)])
+        r = env.curl_get(url, 5, options=["--http2"])
+        assert r.response["status"] == 200
+        r = env.curl_get(url, 5, options=["--http1.1", "-H", "Range: bytes=0-{0}".format(chunk-1)])
         assert 206 == r.response["status"]
         assert chunk == len(r.response["body"].decode('utf-8'))
-        r = env.curl_get(url, 5, ["--http2", "-H", "Range: bytes=0-{0}".format(chunk-1)])
+        r = env.curl_get(url, 5, options=["--http2", "-H", "Range: bytes=0-{0}".format(chunk-1)])
         assert 206 == r.response["status"]
         assert chunk == len(r.response["body"].decode('utf-8'))
         # now check what response lengths have actually been reported
@@ -190,7 +187,7 @@ CustomLog logs/test_004_30 issue_203
         assert log_h2['bytes_resp_B'] == chunk
         assert log_h2['bytes_tx_O'] > chunk
         
-    def test_004_40(self, env):
+    def test_h2_004_40(self, env):
         # echo content using h2test_module "echo" handler
         def post_and_verify(fname, options=None):
             url = env.mkurl("https", "cgi", "/h2test/echo")
@@ -211,7 +208,7 @@ CustomLog logs/test_004_30 issue_203
                 if fname == part.get_filename():
                     filepart = part
             assert filepart
-            with open(env.test_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)
         

Added: httpd/httpd/branches/2.4.x/test/modules/http2/test_005_files.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_005_files.py?rev=1895945&view=auto
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_005_files.py (added)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_005_files.py Tue Dec 14 11:26:52 2021
@@ -0,0 +1,47 @@
+import os
+import pytest
+
+from .env import H2Conf
+
+
+def mk_text_file(fpath: str, lines: int):
+    t110 = ""
+    for _ in range(11):
+        t110 += "0123456789"
+    with open(fpath, "w") as fd:
+        for i in range(lines):
+            fd.write("{0:015d}: ".format(i))  # total 128 bytes per line
+            fd.write(t110)
+            fd.write("\n")
+
+
+class TestFiles:
+
+    URI_PATHS = []
+
+    @pytest.fixture(autouse=True, scope='class')
+    def _class_scope(self, env):
+        docs_a = os.path.join(env.server_docs_dir, "cgi/files")
+        uris = []
+        file_count = 32
+        file_sizes = [1, 10, 100, 10000]
+        for i in range(file_count):
+            fsize = file_sizes[i % len(file_sizes)]
+            if fsize is None:
+                raise Exception("file sizes?: {0} {1}".format(i, fsize))
+            fname = "{0}-{1}k.txt".format(i, fsize)
+            mk_text_file(os.path.join(docs_a, fname), 8 * fsize)
+            self.URI_PATHS.append(f"/files/{fname}")
+
+        H2Conf(env).add_vhost_cgi(
+            proxy_self=True, h2proxy_self=True
+        ).add_vhost_test1(
+            proxy_self=True, h2proxy_self=True
+        ).install()
+        assert env.apache_restart() == 0
+
+    def test_h2_005_01(self, env):
+        url = env.mkurl("https", "cgi", self.URI_PATHS[2])
+        r = env.curl_get(url)
+        assert r.response, r.stderr + r.stdout
+        assert r.response["status"] == 200

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/test_006_assets.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_006_assets.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_006_assets.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_006_assets.py Tue Dec 14 11:26:52 2021
@@ -1,17 +1,17 @@
 import pytest
 
-from h2_conf import HttpdConf
+from .env import H2Conf
 
 
-class TestStore:
+class TestAssets:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        HttpdConf(env).add_vhost_test1().install()
+        H2Conf(env).add_vhost_test1().install()
         assert env.apache_restart() == 0
 
     # single page without any assets
-    def test_006_01(self, env):
+    def test_h2_006_01(self, env):
         url = env.mkurl("https", "test1", "/001.html")
         r = env.nghttp().assets(url,  options=["-Haccept-encoding: none"])
         assert 0 == r.exit_code
@@ -21,7 +21,7 @@ class TestStore:
         ]
 
     # single image without any assets
-    def test_006_02(self, env):
+    def test_h2_006_02(self, env):
         url = env.mkurl("https", "test1", "/002.jpg")
         r = env.nghttp().assets(url,  options=["-Haccept-encoding: none"])
         assert 0 == r.exit_code
@@ -31,7 +31,7 @@ class TestStore:
         ]
         
     # gophertiles, yea!
-    def test_006_03(self, env):
+    def test_h2_006_03(self, env):
         # create the tiles files we originally had checked in
         exp_assets = [
             {"status": 200, "size": "10K", "path": "/004.html"},
@@ -51,7 +51,7 @@ class TestStore:
         assert r.assets == exp_assets
             
     # page with js and css
-    def test_006_04(self, env):
+    def test_h2_006_04(self, env):
         url = env.mkurl("https", "test1", "/006.html")
         r = env.nghttp().assets(url, options=["-Haccept-encoding: none"])
         assert 0 == r.exit_code
@@ -63,7 +63,7 @@ class TestStore:
         ]
 
     # page with image, try different window size
-    def test_006_05(self, env):
+    def test_h2_006_05(self, env):
         url = env.mkurl("https", "test1", "/003.html")
         r = env.nghttp().assets(url, options=["--window-bits=24", "-Haccept-encoding: none"])
         assert 0 == r.exit_code

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/test_100_conn_reuse.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_100_conn_reuse.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_100_conn_reuse.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_100_conn_reuse.py Tue Dec 14 11:26:52 2021
@@ -1,17 +1,17 @@
 import pytest
 
-from h2_conf import HttpdConf
+from .env import H2Conf
 
 
-class TestStore:
+class TestConnReuse:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        HttpdConf(env).add_vhost_noh2().add_vhost_test1().add_vhost_cgi().install()
+        H2Conf(env).add_vhost_noh2().add_vhost_test1().add_vhost_cgi().install()
         assert env.apache_restart() == 0
 
     # make sure the protocol selection on the different hosts work as expected
-    def test_100_01(self, env):
+    def test_h2_100_01(self, env):
         # this host defaults to h2, but we can request h1
         url = env.mkurl("https", "cgi", "/hello.py")
         assert "2" == env.curl_protocol_version( url )
@@ -23,34 +23,34 @@ class TestStore:
         assert "1.1" == env.curl_protocol_version( url, options=[ "--http2" ] )
 
     # access a ServerAlias, after using ServerName in SNI
-    def test_100_02(self, env):
+    def test_h2_100_02(self, env):
         url = env.mkurl("https", "cgi", "/hello.py")
         hostname = ("cgi-alias.%s" % env.http_tld)
-        r = env.curl_get(url, 5, [ "-H", "Host:%s" % hostname ])
-        assert 200 == r.response["status"]
+        r = env.curl_get(url, 5, options=[ "-H", "Host:%s" % hostname ])
+        assert r.response["status"] == 200
         assert "HTTP/2" == r.response["protocol"]
         assert hostname == r.response["json"]["host"]
 
     # access another vhost, after using ServerName in SNI, that uses same SSL setup
-    def test_100_03(self, env):
+    def test_h2_100_03(self, env):
         url = env.mkurl("https", "cgi", "/")
         hostname = ("test1.%s" % env.http_tld)
-        r = env.curl_get(url, 5, [ "-H", "Host:%s" % hostname ])
-        assert 200 == r.response["status"]
+        r = env.curl_get(url, 5, options=[ "-H", "Host:%s" % hostname ])
+        assert r.response["status"] == 200
         assert "HTTP/2" == r.response["protocol"]
         assert "text/html" == r.response["header"]["content-type"]
 
     # access another vhost, after using ServerName in SNI, 
     # that has different SSL certificate. This triggers a 421 (misdirected request) response.
-    def test_100_04(self, env):
+    def test_h2_100_04(self, env):
         url = env.mkurl("https", "cgi", "/hello.py")
         hostname = ("noh2.%s" % env.http_tld)
-        r = env.curl_get(url, 5, [ "-H", "Host:%s" % hostname ])
+        r = env.curl_get(url, 5, options=[ "-H", "Host:%s" % hostname ])
         assert 421 == r.response["status"]
 
     # access an unknown vhost, after using ServerName in SNI
-    def test_100_05(self, env):
+    def test_h2_100_05(self, env):
         url = env.mkurl("https", "cgi", "/hello.py")
         hostname = ("unknown.%s" % env.http_tld)
-        r = env.curl_get(url, 5, [ "-H", "Host:%s" % hostname ])
+        r = env.curl_get(url, 5, options=[ "-H", "Host:%s" % hostname ])
         assert 421 == r.response["status"]

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/test_101_ssl_reneg.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_101_ssl_reneg.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_101_ssl_reneg.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_101_ssl_reneg.py Tue Dec 14 11:26:52 2021
@@ -1,43 +1,46 @@
 import re
 import pytest
 
-from h2_conf import HttpdConf
+from .env import H2Conf, H2TestEnv
 
 
-class TestStore:
+@pytest.mark.skipif(H2TestEnv.get_ssl_module() != "mod_ssl", reason="only for mod_ssl")
+class TestSslRenegotiation:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        HttpdConf(env).add(
-            f"""
-            SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384
-            <Directory \"{env.server_dir}/htdocs/ssl-client-verify\"> 
-                Require all granted
-                SSLVerifyClient require
-                SSLVerifyDepth 0
-            </Directory>"""
-        ).start_vhost(
-            env.https_port, "ssl", with_ssl=True
-        ).add(
-            f"""
-            Protocols h2 http/1.1"
-            <Location /renegotiate/cipher>
-                SSLCipherSuite ECDHE-RSA-CHACHA20-POLY1305
-            </Location>
-            <Location /renegotiate/err-doc-cipher>
-                SSLCipherSuite ECDHE-RSA-CHACHA20-POLY1305
-                ErrorDocument 403 /forbidden.html
-            </Location>
-            <Location /renegotiate/verify>
-                SSLVerifyClient require
-            </Location>
-            <Directory \"{env.server_dir}/htdocs/sslrequire\"> 
-                SSLRequireSSL
-            </Directory>
-            <Directory \"{env.server_dir}/htdocs/requiressl\"> 
-                Require ssl
-            </Directory>"""
-        ).end_vhost().install()
+        domain = f"ssl.{env.http_tld}"
+        conf = H2Conf(env, extras={
+            'base': [
+                "SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384",
+                f"<Directory \"{env.server_dir}/htdocs/ssl-client-verify\">",
+                "    Require all granted",
+                "    SSLVerifyClient require",
+                "    SSLVerifyDepth 0",
+                "</Directory>"
+            ],
+            domain: [
+                "Protocols h2 http/1.1",
+                "<Location /renegotiate/cipher>",
+                "    SSLCipherSuite ECDHE-RSA-CHACHA20-POLY1305",
+                "</Location>",
+                "<Location /renegotiate/err-doc-cipher>",
+                "    SSLCipherSuite ECDHE-RSA-CHACHA20-POLY1305",
+                "    ErrorDocument 403 /forbidden.html",
+                "</Location>",
+                "<Location /renegotiate/verify>",
+                "    SSLVerifyClient require",
+                "</Location>",
+                f"<Directory \"{env.server_dir}/htdocs/sslrequire\">",
+                "    SSLRequireSSL",
+                "</Directory>",
+                f"<Directory \"{env.server_dir}/htdocs/requiressl\">",
+                "    Require ssl",
+                "</Directory>",
+        ]})
+        conf.add_vhost(domains=[domain], port=env.https_port,
+                       doc_root=f"{env.server_dir}/htdocs")
+        conf.install()
         # the dir needs to exists for the configuration to have effect
         env.mkpath("%s/htdocs/ssl-client-verify" % env.server_dir)
         env.mkpath("%s/htdocs/renegotiate/cipher" % env.server_dir)
@@ -46,15 +49,15 @@ class TestStore:
         assert env.apache_restart() == 0
 
     # access a resource with SSL renegotiation, using HTTP/1.1
-    def test_101_01(self, env):
+    def test_h2_101_01(self, env):
         url = env.mkurl("https", "ssl", "/renegotiate/cipher/")
         r = env.curl_get(url, options=["-v", "--http1.1", "--tlsv1.2", "--tls-max", "1.2"])
-        assert 0 == r.exit_code
+        assert 0 == r.exit_code, f"{r}"
         assert r.response
         assert 403 == r.response["status"]
         
     # try to renegotiate the cipher, should fail with correct code
-    def test_101_02(self, env):
+    def test_h2_101_02(self, env):
         url = env.mkurl("https", "ssl", "/renegotiate/cipher/")
         r = env.curl_get(url, options=[
             "-vvv", "--tlsv1.2", "--tls-max", "1.2", "--ciphers", "ECDHE-RSA-AES256-GCM-SHA384"
@@ -65,7 +68,7 @@ class TestStore:
         
     # try to renegotiate a client certificate from Location 
     # needs to fail with correct code
-    def test_101_03(self, env):
+    def test_h2_101_03(self, env):
         url = env.mkurl("https", "ssl", "/renegotiate/verify/")
         r = env.curl_get(url, options=["-vvv", "--tlsv1.2", "--tls-max", "1.2"])
         assert 0 != r.exit_code
@@ -74,16 +77,16 @@ class TestStore:
         
     # try to renegotiate a client certificate from Directory 
     # needs to fail with correct code
-    def test_101_04(self, env):
+    def test_h2_101_04(self, env):
         url = env.mkurl("https", "ssl", "/ssl-client-verify/index.html")
         r = env.curl_get(url, options=["-vvv", "--tlsv1.2", "--tls-max", "1.2"])
-        assert 0 != r.exit_code
+        assert 0 != r.exit_code, f"{r}"
         assert not r.response
         assert re.search(r'HTTP_1_1_REQUIRED \(err 13\)', r.stderr)
         
     # make 10 requests on the same connection, none should produce a status code
     # reported by erki@example.ee
-    def test_101_05(self, env):
+    def test_h2_101_05(self, env):
         r = env.run([env.h2load, "-n", "10", "-c", "1", "-m", "1", "-vvvv",
                      f"{env.https_base_url}/ssl-client-verify/index.html"])
         assert 0 == r.exit_code
@@ -99,7 +102,7 @@ class TestStore:
 
     # Check that "SSLRequireSSL" works on h2 connections
     # See <https://bz.apache.org/bugzilla/show_bug.cgi?id=62654>
-    def test_101_10a(self, env):
+    def test_h2_101_10a(self, env):
         url = env.mkurl("https", "ssl", "/sslrequire/index.html")
         r = env.curl_get(url)
         assert 0 == r.exit_code
@@ -108,7 +111,7 @@ class TestStore:
 
     # Check that "require ssl" works on h2 connections
     # See <https://bz.apache.org/bugzilla/show_bug.cgi?id=62654>
-    def test_101_10b(self, env):
+    def test_h2_101_10b(self, env):
         url = env.mkurl("https", "ssl", "/requiressl/index.html")
         r = env.curl_get(url)
         assert 0 == r.exit_code
@@ -116,7 +119,7 @@ class TestStore:
         assert 404 == r.response["status"]
         
     # Check that status works with ErrorDoc, see pull #174, fixes #172
-    def test_101_11(self, env):
+    def test_h2_101_11(self, env):
         url = env.mkurl("https", "ssl", "/renegotiate/err-doc-cipher")
         r = env.curl_get(url, options=[
             "-vvv", "--tlsv1.2", "--tls-max", "1.2", "--ciphers", "ECDHE-RSA-AES256-GCM-SHA384"

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/test_102_require.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_102_require.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_102_require.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_102_require.py Tue Dec 14 11:26:52 2021
@@ -1,13 +1,15 @@
 import pytest
 
-from h2_conf import HttpdConf
+from .env import H2Conf
 
 
-class TestStore:
+class TestRequire:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        conf = HttpdConf(env).start_vhost(env.https_port, "ssl", with_ssl=True)
+        domain = f"ssl.{env.http_tld}"
+        conf = H2Conf(env)
+        conf.start_vhost(domains=[domain], port=env.https_port)
         conf.add("""
               Protocols h2 http/1.1
               SSLOptions +StdEnvVars
@@ -20,17 +22,17 @@ class TestStore:
         conf.end_vhost()
         conf.install()
         # the dir needs to exists for the configuration to have effect
-        env.mkpath("%s/htdocs/ssl-client-verify" % env.server_dir)
+        env.mkpath(f"{env.server_dir}/htdocs/ssl-client-verify")
         assert env.apache_restart() == 0
 
-    def test_102_01(self, env):
+    def test_h2_102_01(self, env):
         url = env.mkurl("https", "ssl", "/h2only.html")
         r = env.curl_get(url)
         assert 0 == r.exit_code
         assert r.response
         assert 404 == r.response["status"]
         
-    def test_102_02(self, env):
+    def test_h2_102_02(self, env):
         url = env.mkurl("https", "ssl", "/noh2.html")
         r = env.curl_get(url)
         assert 0 == r.exit_code

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/test_103_upgrade.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_103_upgrade.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_103_upgrade.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_103_upgrade.py Tue Dec 14 11:26:52 2021
@@ -1,22 +1,20 @@
 import pytest
 
-from h2_conf import HttpdConf
+from .env import H2Conf
 
 
-class TestStore:
+class TestUpgrade:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        HttpdConf(env).add_vhost_test1().add_vhost_test2().add_vhost_noh2(
-        ).start_vhost(
-            env.https_port, "test3", doc_root="htdocs/test1", with_ssl=True
+        H2Conf(env).add_vhost_test1().add_vhost_test2().add_vhost_noh2(
+        ).start_vhost(domains=[f"test3.{env.http_tld}"], port=env.https_port, doc_root="htdocs/test1"
         ).add(
             """
             Protocols h2 http/1.1
             Header unset Upgrade"""
         ).end_vhost(
-        ).start_vhost(
-            env.http_port, "test1b", doc_root="htdocs/test1", with_ssl=False
+        ).start_vhost(domains=[f"test1b.{env.http_tld}"], port=env.http_port, doc_root="htdocs/test1"
         ).add(
             """
             Protocols h2c http/1.1
@@ -29,7 +27,7 @@ class TestStore:
         assert env.apache_restart() == 0
 
     # accessing http://test1, will not try h2 and advertise h2 in the response
-    def test_103_01(self, env):
+    def test_h2_103_01(self, env):
         url = env.mkurl("http", "test1", "/index.html")
         r = env.curl_get(url)
         assert 0 == r.exit_code
@@ -38,7 +36,7 @@ class TestStore:
         assert "h2c" == r.response["header"]["upgrade"]
         
     # accessing http://noh2, will not advertise, because noh2 host does not have it enabled
-    def test_103_02(self, env):
+    def test_h2_103_02(self, env):
         url = env.mkurl("http", "noh2", "/index.html")
         r = env.curl_get(url)
         assert 0 == r.exit_code
@@ -46,7 +44,7 @@ class TestStore:
         assert "upgrade" not in r.response["header"]
         
     # accessing http://test2, will not advertise, because h2 has less preference than http/1.1
-    def test_103_03(self, env):
+    def test_h2_103_03(self, env):
         url = env.mkurl("http", "test2", "/index.html")
         r = env.curl_get(url)
         assert 0 == r.exit_code
@@ -54,7 +52,7 @@ class TestStore:
         assert "upgrade" not in r.response["header"]
 
     # accessing https://noh2, will not advertise, because noh2 host does not have it enabled
-    def test_103_04(self, env):
+    def test_h2_103_04(self, env):
         url = env.mkurl("https", "noh2", "/index.html")
         r = env.curl_get(url)
         assert 0 == r.exit_code
@@ -62,7 +60,7 @@ class TestStore:
         assert "upgrade" not in r.response["header"]
 
     # accessing https://test2, will not advertise, because h2 has less preference than http/1.1
-    def test_103_05(self, env):
+    def test_h2_103_05(self, env):
         url = env.mkurl("https", "test2", "/index.html")
         r = env.curl_get(url)
         assert 0 == r.exit_code
@@ -70,7 +68,7 @@ class TestStore:
         assert "upgrade" not in r.response["header"]
         
     # accessing https://test1, will advertise h2 in the response
-    def test_103_06(self, env):
+    def test_h2_103_06(self, env):
         url = env.mkurl("https", "test1", "/index.html")
         r = env.curl_get(url, options=["--http1.1"])
         assert 0 == r.exit_code
@@ -79,7 +77,7 @@ class TestStore:
         assert "h2" == r.response["header"]["upgrade"]
         
     # accessing https://test3, will not send Upgrade since it is suppressed
-    def test_103_07(self, env):
+    def test_h2_103_07(self, env):
         url = env.mkurl("https", "test3", "/index.html")
         r = env.curl_get(url, options=["--http1.1"])
         assert 0 == r.exit_code
@@ -87,33 +85,33 @@ class TestStore:
         assert "upgrade" not in r.response["header"]
 
     # upgrade to h2c for a request, where h2c is preferred
-    def test_103_20(self, env):
+    def test_h2_103_20(self, env):
         url = env.mkurl("http", "test1", "/index.html")
         r = env.nghttp().get(url, options=["-u"])
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
 
     # upgrade to h2c for a request where http/1.1 is preferred, but the clients upgrade
     # wish is honored nevertheless
-    def test_103_21(self, env):
+    def test_h2_103_21(self, env):
         url = env.mkurl("http", "test2", "/index.html")
         r = env.nghttp().get(url, options=["-u"])
         assert 404 == r.response["status"]
 
     # ugrade to h2c on a host where h2c is not enabled will fail
-    def test_103_22(self, env):
+    def test_h2_103_22(self, env):
         url = env.mkurl("http", "noh2", "/index.html")
         r = env.nghttp().get(url, options=["-u"])
         assert not r.response
 
     # ugrade to h2c on a host where h2c is preferred, but Upgrade is disabled
-    def test_103_23(self, env):
+    def test_h2_103_23(self, env):
         url = env.mkurl("http", "test1b", "/index.html")
         r = env.nghttp().get(url, options=["-u"])
         assert not r.response
 
     # ugrade to h2c on a host where h2c is preferred, but Upgrade is disabled on the server,
     # but allowed for a specific location
-    def test_103_24(self, env):
+    def test_h2_103_24(self, env):
         url = env.mkurl("http", "test1b", "/006.html")
         r = env.nghttp().get(url, options=["-u"])
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/test_104_padding.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_104_padding.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_104_padding.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_104_padding.py Tue Dec 14 11:26:52 2021
@@ -1,6 +1,6 @@
 import pytest
 
-from h2_conf import HttpdConf
+from .env import H2Conf
 
 
 def frame_padding(payload, padbits):
@@ -8,34 +8,31 @@ 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):
-        conf = HttpdConf(env)
-        conf.add_vhost_cgi()
-        conf.start_vhost(env.https_port, "pad0", doc_root="htdocs/cgi", with_ssl=True)
-        conf.add("Protocols h2 http/1.1")
+        conf = H2Conf(env)
+        conf.start_vhost(domains=[f"ssl.{env.http_tld}"], port=env.https_port, doc_root="htdocs/cgi")
+        conf.add("AddHandler cgi-script .py")
+        conf.end_vhost()
+        conf.start_vhost(domains=[f"pad0.{env.http_tld}"], port=env.https_port, doc_root="htdocs/cgi")
         conf.add("H2Padding 0")
         conf.add("AddHandler cgi-script .py")
         conf.end_vhost()
-        conf.start_vhost(env.https_port, "pad1", doc_root="htdocs/cgi", with_ssl=True)
-        conf.add("Protocols h2 http/1.1")
+        conf.start_vhost(domains=[f"pad1.{env.http_tld}"], port=env.https_port, doc_root="htdocs/cgi")
         conf.add("H2Padding 1")
         conf.add("AddHandler cgi-script .py")
         conf.end_vhost()
-        conf.start_vhost(env.https_port, "pad2", doc_root="htdocs/cgi", with_ssl=True)
-        conf.add("Protocols h2 http/1.1")
+        conf.start_vhost(domains=[f"pad2.{env.http_tld}"], port=env.https_port, doc_root="htdocs/cgi")
         conf.add("H2Padding 2")
         conf.add("AddHandler cgi-script .py")
         conf.end_vhost()
-        conf.start_vhost(env.https_port, "pad3", doc_root="htdocs/cgi", with_ssl=True)
-        conf.add("Protocols h2 http/1.1")
+        conf.start_vhost(domains=[f"pad3.{env.http_tld}"], port=env.https_port, doc_root="htdocs/cgi")
         conf.add("H2Padding 3")
         conf.add("AddHandler cgi-script .py")
         conf.end_vhost()
-        conf.start_vhost(env.https_port, "pad8", doc_root="htdocs/cgi", with_ssl=True)
-        conf.add("Protocols h2 http/1.1")
+        conf.start_vhost(domains=[f"pad8.{env.http_tld}"], port=env.https_port, doc_root="htdocs/cgi")
         conf.add("H2Padding 8")
         conf.add("AddHandler cgi-script .py")
         conf.end_vhost()
@@ -43,58 +40,58 @@ class TestStore:
         assert env.apache_restart() == 0
 
     # default paddings settings: 0 bits
-    def test_104_01(self, env):
-        url = env.mkurl("https", "cgi", "/echo.py")
+    def test_h2_104_01(self, env):
+        url = env.mkurl("https", "ssl", "/echo.py")
         # we get 2 frames back: one with data and an empty one with EOF
         # check the number of padding bytes is as expected
         for data in ["x", "xx", "xxx", "xxxx", "xxxxx", "xxxxxx", "xxxxxxx", "xxxxxxxx"]:
             r = env.nghttp().post_data(url, data, 5)
-            assert 200 == r.response["status"]
+            assert r.response["status"] == 200
             assert r.results["paddings"] == [
                 frame_padding(len(data)+1, 0), 
                 frame_padding(0, 0)
             ]
 
     # 0 bits of padding
-    def test_104_02(self, env):
+    def test_h2_104_02(self, env):
         url = env.mkurl("https", "pad0", "/echo.py")
         for data in ["x", "xx", "xxx", "xxxx", "xxxxx", "xxxxxx", "xxxxxxx", "xxxxxxxx"]:
             r = env.nghttp().post_data(url, data, 5)
-            assert 200 == r.response["status"]
+            assert r.response["status"] == 200
             assert r.results["paddings"] == [0, 0]
 
     # 1 bit of padding
-    def test_104_03(self, env):
+    def test_h2_104_03(self, env):
         url = env.mkurl("https", "pad1", "/echo.py")
         for data in ["x", "xx", "xxx", "xxxx", "xxxxx", "xxxxxx", "xxxxxxx", "xxxxxxxx"]:
             r = env.nghttp().post_data(url, data, 5)
-            assert 200 == r.response["status"]
+            assert r.response["status"] == 200
             for i in r.results["paddings"]:
                 assert i in range(0, 2)
 
     # 2 bits of padding
-    def test_104_04(self, env):
+    def test_h2_104_04(self, env):
         url = env.mkurl("https", "pad2", "/echo.py")
         for data in ["x", "xx", "xxx", "xxxx", "xxxxx", "xxxxxx", "xxxxxxx", "xxxxxxxx"]:
             r = env.nghttp().post_data(url, data, 5)
-            assert 200 == r.response["status"]
+            assert r.response["status"] == 200
             for i in r.results["paddings"]:
                 assert i in range(0, 4)
 
     # 3 bits of padding
-    def test_104_05(self, env):
+    def test_h2_104_05(self, env):
         url = env.mkurl("https", "pad3", "/echo.py")
         for data in ["x", "xx", "xxx", "xxxx", "xxxxx", "xxxxxx", "xxxxxxx", "xxxxxxxx"]:
             r = env.nghttp().post_data(url, data, 5)
-            assert 200 == r.response["status"]
+            assert r.response["status"] == 200
             for i in r.results["paddings"]:
                 assert i in range(0, 8)
 
     # 8 bits of padding
-    def test_104_06(self, env):
+    def test_h2_104_06(self, env):
         url = env.mkurl("https", "pad8", "/echo.py")
         for data in ["x", "xx", "xxx", "xxxx", "xxxxx", "xxxxxx", "xxxxxxx", "xxxxxxxx"]:
             r = env.nghttp().post_data(url, data, 5)
-            assert 200 == r.response["status"]
+            assert r.response["status"] == 200
             for i in r.results["paddings"]:
                 assert i in range(0, 256)

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/test_105_timeout.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_105_timeout.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_105_timeout.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_105_timeout.py Tue Dec 14 11:26:52 2021
@@ -3,15 +3,15 @@ import time
 
 import pytest
 
-from h2_conf import HttpdConf
-from h2_curl import CurlPiper
+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_105_01(self, env):
-        conf = HttpdConf(env)
+    def test_h2_105_01(self, env):
+        conf = H2Conf(env)
         conf.add("""
             AcceptFilter http none
             Timeout 1.5
@@ -44,8 +44,8 @@ class TestStore:
         sock.close()
 
     # Check that mod_reqtimeout handshake setting takes effect
-    def test_105_02(self, env):
-        conf = HttpdConf(env)
+    def test_h2_105_02(self, env):
+        conf = H2Conf(env)
         conf.add("""
             AcceptFilter http none
             Timeout 10
@@ -80,8 +80,8 @@ class TestStore:
 
     # Check that mod_reqtimeout handshake setting do no longer apply to handshaked 
     # connections. See <https://github.com/icing/mod_h2/issues/196>.
-    def test_105_03(self, env):
-        conf = HttpdConf(env)
+    def test_h2_105_03(self, env):
+        conf = H2Conf(env)
         conf.add("""
             Timeout 10
             RequestReadTimeout handshake=1 header=5 body=10
@@ -90,17 +90,17 @@ class TestStore:
         conf.install()
         assert env.apache_restart() == 0
         url = env.mkurl("https", "cgi", "/necho.py")
-        r = env.curl_get(url, 5, [
+        r = env.curl_get(url, 5, options=[
             "-vvv",
             "-F", ("count=%d" % 100),
             "-F", ("text=%s" % "abcdefghijklmnopqrstuvwxyz"),
             "-F", ("wait1=%f" % 1.5),
         ])
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
 
-    def test_105_10(self, env):
+    def test_h2_105_10(self, env):
         # just a check without delays if all is fine
-        conf = HttpdConf(env)
+        conf = H2Conf(env)
         conf.add_vhost_cgi()
         conf.install()
         assert env.apache_restart() == 0
@@ -111,11 +111,11 @@ class TestStore:
         assert piper.exitcode == 0
         assert len("".join(stdout)) == 3 * 8192
 
-    @pytest.mark.skipif(True, reason="new feature in upcoming http2")
-    def test_105_11(self, env):
+    @pytest.mark.skip(reason="only in 2.5.x")
+    def test_h2_105_11(self, env):
         # short connection timeout, longer stream delay
         # receiving the first response chunk, then timeout
-        conf = HttpdConf(env)
+        conf = H2Conf(env)
         conf.add_vhost_cgi()
         conf.add("Timeout 1")
         conf.install()
@@ -126,11 +126,11 @@ class TestStore:
         stdout, stderr = piper.close()
         assert len("".join(stdout)) == 8192
 
-    @pytest.mark.skipif(True, reason="new feature in upcoming http2")
-    def test_105_12(self, env):
+    @pytest.mark.skip(reason="only in 2.5.x")
+    def test_h2_105_12(self, env):
         # long connection timeout, short stream timeout
         # sending a slow POST
-        conf = HttpdConf(env)
+        conf = H2Conf(env)
         conf.add_vhost_cgi()
         conf.add("Timeout 10")
         conf.add("H2StreamTimeout 1")

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/test_106_shutdown.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_106_shutdown.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_106_shutdown.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_106_shutdown.py Tue Dec 14 11:26:52 2021
@@ -7,20 +7,20 @@ from threading import Thread
 
 import pytest
 
-from h2_conf import HttpdConf
-from h2_result import ExecResult
+from .env import H2Conf
+from pyhttpd.result import ExecResult
 
 
 class TestShutdown:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        conf = HttpdConf(env)
+        conf = H2Conf(env)
         conf.add_vhost_cgi()
         conf.install()
         assert env.apache_restart() == 0
 
-    def test_106_01(self, env):
+    def test_h2_106_01(self, env):
         url = env.mkurl("https", "cgi", "/necho.py")
         lines = 100000
         text = "123456789"
@@ -32,7 +32,7 @@ class TestShutdown:
                     "-F", f"text={text}",
                     "-F", f"wait2={wait2}",
                     ]
-            self.r = env.curl_get(url, 5, args)
+            self.r = env.curl_get(url, 5, options=args)
 
         t = Thread(target=long_request)
         t.start()
@@ -40,6 +40,29 @@ class TestShutdown:
         assert env.apache_reload() == 0
         t.join()
         # noinspection PyTypeChecker
+        time.sleep(1)
         r: ExecResult = self.r
-        assert r.response["status"] == 200
-        assert len(r.response["body"]) == (lines * (len(text)+1))
+        assert r.exit_code == 0
+        assert r.response, f"no response via {r.args} in {r.stderr}\nstdout: {len(r.stdout)} bytes"
+        assert r.response["status"] == 200, f"{r}"
+        assert len(r.response["body"]) == (lines * (len(text)+1)), f"{r}"
+
+    def test_h2_106_02(self, env):
+        # PR65731: invalid GOAWAY frame at session start when
+        # MaxRequestsPerChild is reached
+        # Create a low limit and only 2 children, so we'll encounter this easily
+        conf = H2Conf(env, extras={
+            'base': [
+                "ServerLimit 2",
+                "MaxRequestsPerChild 3"
+            ]
+        })
+        conf.add_vhost_test1()
+        conf.install()
+        assert env.apache_restart() == 0
+        url = env.mkurl("https", "test1", "/index.html")
+        for i in range(7):
+            r = env.curl_get(url, options=['-vvv'])
+            assert r.exit_code == 0, f"failed on {i}. request: {r.stdout} {r.stderr}"
+            assert r.response["status"] == 200
+            assert "HTTP/2" == r.response["protocol"]
\ No newline at end of file

Modified: httpd/httpd/branches/2.4.x/test/modules/http2/test_200_header_invalid.py
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.4.x/test/modules/http2/test_200_header_invalid.py?rev=1895945&r1=1895944&r2=1895945&view=diff
==============================================================================
--- httpd/httpd/branches/2.4.x/test/modules/http2/test_200_header_invalid.py (original)
+++ httpd/httpd/branches/2.4.x/test/modules/http2/test_200_header_invalid.py Tue Dec 14 11:26:52 2021
@@ -1,19 +1,19 @@
 import pytest
 
-from h2_conf import HttpdConf
+from .env import H2Conf
 
 
-class TestStore:
+class TestInvalidHeaders:
 
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
-        HttpdConf(env).add_vhost_cgi().install()
+        H2Conf(env).add_vhost_cgi().install()
         assert env.apache_restart() == 0
 
     # let the hecho.py CGI echo chars < 0x20 in field name
     # for almost all such characters, the stream gets aborted with a h2 error and 
     # there will be no http status, cr and lf are handled special
-    def test_200_01(self, env):
+    def test_h2_200_01(self, env):
         url = env.mkurl("https", "cgi", "/hecho.py")
         for x in range(1, 32):
             r = env.curl_post_data(url, "name=x%%%02xx&value=yz" % x)
@@ -29,7 +29,7 @@ class TestStore:
     # let the hecho.py CGI echo chars < 0x20 in field value
     # for almost all such characters, the stream gets aborted with a h2 error and 
     # there will be no http status, cr and lf are handled special
-    def test_200_02(self, env):
+    def test_h2_200_02(self, env):
         url = env.mkurl("https", "cgi", "/hecho.py")
         for x in range(1, 32):
             if 9 != x:
@@ -41,7 +41,7 @@ class TestStore:
                     assert 0 != r.exit_code, "unexpected exit code for char 0x%02x" % x
 
     # let the hecho.py CGI echo 0x10 and 0x7f in field name and value
-    def test_200_03(self, env):
+    def test_h2_200_03(self, env):
         url = env.mkurl("https", "cgi", "/hecho.py")
         for h in ["10", "7f"]:
             r = env.curl_post_data(url, "name=x%%%s&value=yz" % h)
@@ -50,24 +50,24 @@ class TestStore:
             assert 0 != r.exit_code
     
     # test header field lengths check, LimitRequestLine (default 8190)
-    def test_200_10(self, env):
+    def test_h2_200_10(self, env):
         url = env.mkurl("https", "cgi", "/")
         val = "1234567890"  # 10 chars
         for i in range(3):  # make a 10000 char string
             val = "%s%s%s%s%s%s%s%s%s%s" % (val, val, val, val, val, val, val, val, val, val)
         # LimitRequestLine 8190 ok, one more char -> 431
         r = env.curl_get(url, options=["-H", "x: %s" % (val[:8187])])
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         r = env.curl_get(url, options=["-H", "x: %sx" % (val[:8188])])
         assert 431 == r.response["status"]
         # same with field name
         r = env.curl_get(url, options=["-H", "y%s: 1" % (val[:8186])])
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         r = env.curl_get(url, options=["-H", "y%s: 1" % (val[:8188])])
         assert 431 == r.response["status"]
 
     # test header field lengths check, LimitRequestFieldSize (default 8190)
-    def test_200_11(self, env):
+    def test_h2_200_11(self, env):
         url = env.mkurl("https", "cgi", "/")
         val = "1234567890"  # 10 chars
         for i in range(3):  # make a 10000 char string
@@ -75,7 +75,7 @@ class TestStore:
         # LimitRequestFieldSize 8190 ok, one more char -> 400 in HTTP/1.1
         # (we send 4000+4185 since they are concatenated by ", " and start with "x: "
         r = env.curl_get(url, options=["-H", "x: %s" % (val[:4000]),  "-H", "x: %s" % (val[:4185])])
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         r = env.curl_get(url, options=["--http1.1", "-H", "x: %s" % (val[:4000]),  "-H", "x: %s" % (val[:4189])])
         assert 400 == r.response["status"]
         r = env.curl_get(url, options=["-H", "x: %s" % (val[:4000]),  "-H", "x: %s" % (val[:4191])])
@@ -83,31 +83,31 @@ class TestStore:
 
     # test header field count, LimitRequestFields (default 100)
     # see #201: several headers with same name are mered and count only once
-    def test_200_12(self, env):
+    def test_h2_200_12(self, env):
         url = env.mkurl("https", "cgi", "/")
         opt = []
         for i in range(98):  # curl sends 2 headers itself (user-agent and accept)
             opt += ["-H", "x: 1"]
         r = env.curl_get(url, options=opt)
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         r = env.curl_get(url, options=(opt + ["-H", "y: 2"]))
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
 
     # test header field count, LimitRequestFields (default 100)
     # different header names count each
-    def test_200_13(self, env):
+    def test_h2_200_13(self, env):
         url = env.mkurl("https", "cgi", "/")
         opt = []
         for i in range(98):  # curl sends 2 headers itself (user-agent and accept)
             opt += ["-H", "x{0}: 1".format(i)]
         r = env.curl_get(url, options=opt)
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         r = env.curl_get(url, options=(opt + ["-H", "y: 2"]))
         assert 431 == r.response["status"]
 
     # test "LimitRequestFields 0" setting, see #200
-    def test_200_14(self, env):
-        conf = HttpdConf(env)
+    def test_h2_200_14(self, env):
+        conf = H2Conf(env)
         conf.add("""
             LimitRequestFields 20
             """)
@@ -120,7 +120,7 @@ class TestStore:
             opt += ["-H", "x{0}: 1".format(i)]
         r = env.curl_get(url, options=opt)
         assert 431 == r.response["status"]
-        conf = HttpdConf(env)
+        conf = H2Conf(env)
         conf.add("""
             LimitRequestFields 0
             """)
@@ -132,11 +132,11 @@ class TestStore:
         for i in range(100):
             opt += ["-H", "x{0}: 1".format(i)]
         r = env.curl_get(url, options=opt)
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
 
     # the uri limits
-    def test_200_15(self, env):
-        conf = HttpdConf(env)
+    def test_h2_200_15(self, env):
+        conf = H2Conf(env)
         conf.add("""
             LimitRequestLine 48
             """)
@@ -145,7 +145,7 @@ class TestStore:
         assert env.apache_restart() == 0
         url = env.mkurl("https", "cgi", "/")
         r = env.curl_get(url)
-        assert 200 == r.response["status"]
+        assert r.response["status"] == 200
         url = env.mkurl("https", "cgi", "/" + (48*"x"))
         r = env.curl_get(url)
         assert 414 == r.response["status"]
@@ -159,8 +159,8 @@ class TestStore:
         assert not r.response
 
     # invalid chars in method
-    def test_200_16(self, env):
-        conf = HttpdConf(env)
+    def test_h2_200_16(self, env):
+        conf = H2Conf(env)
         conf.add_vhost_cgi()
         conf.install()
         assert env.apache_restart() == 0
@@ -168,10 +168,12 @@ class TestStore:
         opt = ["-H:method: GET /hello.py"]
         r = env.nghttp().get(url, options=opt)
         assert r.exit_code == 0, r
-        if r.response:
+        # nghttp version >= 1.45.0 check pseudo headers and RST streams,
+        # which means we see no response.
+        if r.response is not None:
             assert r.response["status"] == 400
         url = env.mkurl("https", "cgi", "/proxy/hello.py")
         r = env.nghttp().get(url, options=opt)
         assert r.exit_code == 0, r
-        if r.response:
+        if r.response is not None:
             assert r.response["status"] == 400