You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by yl...@apache.org on 2023/07/07 08:21:22 UTC

svn commit: r1910844 [1/2] - in /httpd/httpd/trunk/test: ./ modules/core/ modules/http1/ modules/http2/ modules/md/ modules/proxy/ modules/tls/ pyhttpd/

Author: ylavic
Date: Fri Jul  7 08:21:21 2023
New Revision: 1910844

URL: http://svn.apache.org/viewvc?rev=1910844&view=rev
Log:
pytests: Ignore log errors/warnings per function.

It's easier to control errors at the function scope and it avoids ignored
errors/warnings to propagate to the following tests (i.e. mask further
unexpected errors).

github: closes #371


Modified:
    httpd/httpd/trunk/test/conftest.py
    httpd/httpd/trunk/test/modules/core/conftest.py
    httpd/httpd/trunk/test/modules/core/test_001_encoding.py
    httpd/httpd/trunk/test/modules/http1/conftest.py
    httpd/httpd/trunk/test/modules/http1/env.py
    httpd/httpd/trunk/test/modules/http1/test_003_get.py
    httpd/httpd/trunk/test/modules/http1/test_004_post.py
    httpd/httpd/trunk/test/modules/http1/test_006_unsafe.py
    httpd/httpd/trunk/test/modules/http1/test_007_strict.py
    httpd/httpd/trunk/test/modules/http2/conftest.py
    httpd/httpd/trunk/test/modules/http2/env.py
    httpd/httpd/trunk/test/modules/http2/test_007_ssi.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_105_timeout.py
    httpd/httpd/trunk/test/modules/http2/test_106_shutdown.py
    httpd/httpd/trunk/test/modules/http2/test_200_header_invalid.py
    httpd/httpd/trunk/test/modules/http2/test_203_rfc9113.py
    httpd/httpd/trunk/test/modules/http2/test_500_proxy.py
    httpd/httpd/trunk/test/modules/http2/test_800_websockets.py
    httpd/httpd/trunk/test/modules/md/conftest.py
    httpd/httpd/trunk/test/modules/md/test_300_conf_validate.py
    httpd/httpd/trunk/test/modules/md/test_702_auto.py
    httpd/httpd/trunk/test/modules/md/test_720_wildcard.py
    httpd/httpd/trunk/test/modules/md/test_730_static.py
    httpd/httpd/trunk/test/modules/md/test_740_acme_errors.py
    httpd/httpd/trunk/test/modules/md/test_741_setup_errors.py
    httpd/httpd/trunk/test/modules/md/test_750_eab.py
    httpd/httpd/trunk/test/modules/md/test_780_tailscale.py
    httpd/httpd/trunk/test/modules/md/test_790_failover.py
    httpd/httpd/trunk/test/modules/md/test_900_notify.py
    httpd/httpd/trunk/test/modules/md/test_901_message.py
    httpd/httpd/trunk/test/modules/md/test_920_status.py
    httpd/httpd/trunk/test/modules/proxy/conftest.py
    httpd/httpd/trunk/test/modules/proxy/env.py
    httpd/httpd/trunk/test/modules/proxy/test_02_unix.py
    httpd/httpd/trunk/test/modules/tls/conftest.py
    httpd/httpd/trunk/test/modules/tls/test_03_sni.py
    httpd/httpd/trunk/test/modules/tls/test_06_ciphers.py
    httpd/httpd/trunk/test/modules/tls/test_14_proxy_ssl.py
    httpd/httpd/trunk/test/modules/tls/test_15_proxy_tls.py
    httpd/httpd/trunk/test/pyhttpd/env.py
    httpd/httpd/trunk/test/pyhttpd/log.py

Modified: httpd/httpd/trunk/test/conftest.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/conftest.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/conftest.py (original)
+++ httpd/httpd/trunk/test/conftest.py Fri Jul  7 08:21:21 2023
@@ -23,9 +23,25 @@ def pytest_generate_tests(metafunc):
         metafunc.fixturenames.append('tmp_ct')
         metafunc.parametrize('repeat', range(count))
 
+
 @pytest.fixture(autouse=True, scope="function")
 def _function_scope(env, request):
     env.set_current_test_name(request.node.name)
     yield
+    env.check_error_log()
     env.set_current_test_name(None)
 
+
+@pytest.fixture(autouse=True, scope="module")
+def _module_scope(env):
+    yield
+    env.check_error_log()
+
+
+@pytest.fixture(autouse=True, scope="package")
+def _package_scope(env):
+    env.httpd_error_log.clear_ignored_matches()
+    env.httpd_error_log.clear_ignored_lognos()
+    yield
+    assert env.apache_stop() == 0
+    env.check_error_log()

Modified: httpd/httpd/trunk/test/modules/core/conftest.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/core/conftest.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/core/conftest.py (original)
+++ httpd/httpd/trunk/test/modules/core/conftest.py Fri Jul  7 08:21:21 2023
@@ -28,18 +28,3 @@ def env(pytestconfig) -> CoreTestEnv:
     env.apache_access_log_clear()
     env.httpd_error_log.clear_log()
     return env
-
-
-@pytest.fixture(autouse=True, scope="package")
-def _session_scope(env):
-    env.httpd_error_log.set_ignored_lognos([
-        'AH10244',  # core: invalid URI path
-        'AH01264',  # mod_cgid script not found
-    ])
-    yield
-    assert env.apache_stop() == 0
-    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))
-

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=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/core/test_001_encoding.py (original)
+++ httpd/httpd/trunk/test/modules/core/test_001_encoding.py Fri Jul  7 08:21:21 2023
@@ -1,12 +1,11 @@
 import pytest
+from typing import List, Optional
 
 from pyhttpd.conf import HttpdConf
 
 
 class TestEncoding:
 
-    EXP_AH10244_ERRS = 0
-
     @pytest.fixture(autouse=True, scope='class')
     def _class_scope(self, env):
         conf = HttpdConf(env, extras={
@@ -57,29 +56,29 @@ class TestEncoding:
         assert r.response["status"] == 200
 
     # check path traversals
-    @pytest.mark.parametrize(["path", "status"], [
-        ["/../echo.py", 400],
-        ["/nothing/../../echo.py", 400],
-        ["/cgi-bin/../../echo.py", 400],
-        ["/nothing/%2e%2e/%2e%2e/echo.py", 400],
-        ["/cgi-bin/%2e%2e/%2e%2e/echo.py", 400],
-        ["/nothing/%%32%65%%32%65/echo.py", 400],
-        ["/cgi-bin/%%32%65%%32%65/echo.py", 400],
-        ["/nothing/%%32%65%%32%65/%%32%65%%32%65/h2_env.py", 400],
-        ["/cgi-bin/%%32%65%%32%65/%%32%65%%32%65/h2_env.py", 400],
-        ["/nothing/%25%32%65%25%32%65/echo.py", 404],
-        ["/cgi-bin/%25%32%65%25%32%65/echo.py", 404],
-        ["/nothing/%25%32%65%25%32%65/%25%32%65%25%32%65/h2_env.py", 404],
-        ["/cgi-bin/%25%32%65%25%32%65/%25%32%65%25%32%65/h2_env.py", 404],
+    @pytest.mark.parametrize(["path", "status", "lognos"], [
+        ["/../echo.py", 400, ["AH10244"]],
+        ["/nothing/../../echo.py", 400, ["AH10244"]],
+        ["/cgi-bin/../../echo.py", 400, ["AH10244"]],
+        ["/nothing/%2e%2e/%2e%2e/echo.py", 400, ["AH10244"]],
+        ["/cgi-bin/%2e%2e/%2e%2e/echo.py", 400, ["AH10244"]],
+        ["/nothing/%%32%65%%32%65/echo.py", 400, ["AH10244"]],
+        ["/cgi-bin/%%32%65%%32%65/echo.py", 400, ["AH10244"]],
+        ["/nothing/%%32%65%%32%65/%%32%65%%32%65/h2_env.py", 400, ["AH10244"]],
+        ["/cgi-bin/%%32%65%%32%65/%%32%65%%32%65/h2_env.py", 400, ["AH10244"]],
+        ["/nothing/%25%32%65%25%32%65/echo.py", 404, ["AH01264"]],
+        ["/cgi-bin/%25%32%65%25%32%65/echo.py", 404, ["AH01264"]],
+        ["/nothing/%25%32%65%25%32%65/%25%32%65%25%32%65/h2_env.py", 404, ["AH01264"]],
+        ["/cgi-bin/%25%32%65%25%32%65/%25%32%65%25%32%65/h2_env.py", 404, ["AH01264"]],
     ])
-    def test_core_001_04(self, env, path, status):
+    def test_core_001_04(self, env, path, status, lognos: Optional[List[str]]):
         url = env.mkurl("https", "test1", path)
         r = env.curl_get(url)
         assert r.response["status"] == status
-        if status == 400:
-            TestEncoding.EXP_AH10244_ERRS += 1
-            # the log will have a core:err about invalid URI path
-
+        #
+        if lognos is not None:
+            env.httpd_error_log.ignore_recent(lognos = lognos)
+ 
     # check handling of %2f url encodings that are not decoded by default
     @pytest.mark.parametrize(["host", "path", "status"], [
         ["test1", "/006%2f006.css", 404],

Modified: httpd/httpd/trunk/test/modules/http1/conftest.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http1/conftest.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http1/conftest.py (original)
+++ httpd/httpd/trunk/test/modules/http1/conftest.py Fri Jul  7 08:21:21 2023
@@ -34,14 +34,3 @@ def env(pytestconfig) -> H1TestEnv:
     env.apache_access_log_clear()
     env.httpd_error_log.clear_log()
     return env
-
-
-@pytest.fixture(autouse=True, scope="package")
-def _session_scope(env):
-    yield
-    assert env.apache_stop() == 0
-    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))
-

Modified: httpd/httpd/trunk/test/modules/http1/env.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http1/env.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http1/env.py (original)
+++ httpd/httpd/trunk/test/modules/http1/env.py Fri Jul  7 08:21:21 2023
@@ -1,7 +1,6 @@
 import inspect
 import logging
 import os
-import re
 import subprocess
 from typing import Dict, Any
 
@@ -61,13 +60,6 @@ class H1TestEnv(HttpdTestEnv):
         super().__init__(pytestconfig=pytestconfig)
         self.add_httpd_log_modules(["http", "core"])
 
-        self.httpd_error_log.set_ignored_lognos([
-            'AH00135', # unsafe/strict tests send invalid methods
-            'AH02430', # test of invalid chars in response headers
-        ])
-        self.httpd_error_log.add_ignored_patterns([
-        ])
-
     def setup_httpd(self, setup: HttpdTestSetup = None):
         super().setup_httpd(setup=H1TestSetup(env=self))
 

Modified: httpd/httpd/trunk/test/modules/http1/test_003_get.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http1/test_003_get.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http1/test_003_get.py (original)
+++ httpd/httpd/trunk/test/modules/http1/test_003_get.py Fri Jul  7 08:21:21 2023
@@ -1,4 +1,3 @@
-import re
 import socket
 
 import pytest

Modified: httpd/httpd/trunk/test/modules/http1/test_004_post.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http1/test_004_post.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http1/test_004_post.py (original)
+++ httpd/httpd/trunk/test/modules/http1/test_004_post.py Fri Jul  7 08:21:21 2023
@@ -3,7 +3,6 @@ import email.parser
 import inspect
 import json
 import os
-import re
 import sys
 
 import pytest

Modified: httpd/httpd/trunk/test/modules/http1/test_006_unsafe.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http1/test_006_unsafe.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http1/test_006_unsafe.py (original)
+++ httpd/httpd/trunk/test/modules/http1/test_006_unsafe.py Fri Jul  7 08:21:21 2023
@@ -1,6 +1,6 @@
 import re
 import socket
-from typing import Optional
+from typing import List, Optional
 
 import pytest
 
@@ -23,88 +23,88 @@ class TestRequestUnsafe:
     #   1:       any HTTP success
     #   200-500: specific HTTP status code
     #   None:   HTTPD should drop connection without error message
-    @pytest.mark.parametrize(["intext", "status"], [
-        ["GET / HTTP/1.0\r\n\r\n", 1],
-        ["GET / HTTP/1.0\n\n", 1],
-        ["get / HTTP/1.0\r\n\r\n", 501],
-        ["G ET / HTTP/1.0\r\n\r\n", 400],
-        ["G\0ET / HTTP/1.0\r\n\r\n", 400],
-        ["G/T / HTTP/1.0\r\n\r\n", 501],
-        ["GET /\0 HTTP/1.0\r\n\r\n", 400],
-        ["GET / HTTP/1.0\0\r\n\r\n", 400],
-        ["GET\f/ HTTP/1.0\r\n\r\n", 400],
-        ["GET\r/ HTTP/1.0\r\n\r\n", 400],
-        ["GET\t/ HTTP/1.0\r\n\r\n", 400],
-        ["GET / HTT/1.0\r\n\r\n", 0],
-        ["GET / HTTP/1.0\r\nHost: localhost\r\n\r\n", 1],
-        ["GET / HTTP/2.0\r\nHost: localhost\r\n\r\n", 1],
-        ["GET / HTTP/1.2\r\nHost: localhost\r\n\r\n", 1],
-        ["GET / HTTP/1.11\r\nHost: localhost\r\n\r\n", 400],
-        ["GET / HTTP/10.0\r\nHost: localhost\r\n\r\n", 400],
-        ["GET / HTTP/1.0  \r\nHost: localhost\r\n\r\n", 200],
-        ["GET / HTTP/1.0 x\r\nHost: localhost\r\n\r\n", 400],
-        ["GET / HTTP/\r\nHost: localhost\r\n\r\n", 0],
-        ["GET / HTTP/0.9\r\n\r\n", 0],
-        ["GET / HTTP/0.8\r\n\r\n", 0],
-        ["GET /\x01 HTTP/1.0\r\n\r\n", 400],
-        ["GET / HTTP/1.0\r\nFoo: bar\r\n\r\n", 200],
-        ["GET / HTTP/1.0\r\nFoo:bar\r\n\r\n", 200],
-        ["GET / HTTP/1.0\r\nFoo: b\0ar\r\n\r\n", 400],
-        ["GET / HTTP/1.0\r\nFoo: b\x01ar\r\n\r\n", 200],
-        ["GET / HTTP/1.0\r\nFoo\r\n\r\n", 400],
-        ["GET / HTTP/1.0\r\nFoo bar\r\n\r\n", 400],
-        ["GET / HTTP/1.0\r\n: bar\r\n\r\n", 400],
-        ["GET / HTTP/1.0\r\nX: bar\r\n\r\n", 200],
-        ["GET / HTTP/1.0\r\nFoo bar:bash\r\n\r\n", 400],
-        ["GET / HTTP/1.0\r\nFoo :bar\r\n\r\n", 400],
-        ["GET / HTTP/1.0\r\n Foo:bar\r\n\r\n", 400],
-        ["GET / HTTP/1.0\r\nF\x01o: bar\r\n\r\n", 200],
-        ["GET / HTTP/1.0\r\nF\ro: bar\r\n\r\n", 400],
-        ["GET / HTTP/1.0\r\nF\to: bar\r\n\r\n", 400],
-        ["GET / HTTP/1.0\r\nFo: b\tar\r\n\r\n", 200],
-        ["GET / HTTP/1.0\r\nFo: bar\r\r\n\r\n", 400],
-        ["GET / HTTP/1.0\r\r", None],
-        ["GET /\r\n", 90],
-        ["GET /#frag HTTP/1.0\r\n", 400],
-        ["GET / HTTP/1.0\r\nHost: localhost\r\nHost: localhost\r\n\r\n", 200],
-        ["GET http://017700000001/ HTTP/1.0\r\n\r\n", 200],
-        ["GET http://0x7f.1/ HTTP/1.0\r\n\r\n", 200],
-        ["GET http://127.0.0.1/ HTTP/1.0\r\n\r\n", 200],
-        ["GET http://127.01.0.1/ HTTP/1.0\r\n\r\n", 200],
-        ["GET http://%3127.0.0.1/ HTTP/1.0\r\n\r\n", 200],
-        ["GET / HTTP/1.0\r\nHost: localhost:80\r\nHost: localhost:80\r\n\r\n", 200],
-        ["GET / HTTP/1.0\r\nHost: localhost:80 x\r\n\r", 400],
-        ["GET http://localhost:80/ HTTP/1.0\r\n\r\n", 200],
-        ["GET http://localhost:80x/ HTTP/1.0\r\n\r\n", 400],
-        ["GET http://localhost:80:80/ HTTP/1.0\r\n\r\n", 400],
-        ["GET http://localhost::80/ HTTP/1.0\r\n\r\n", 400],
-        ["GET http://foo@localhost:80/ HTTP/1.0\r\n\r\n", 200],
-        ["GET http://[::1]/ HTTP/1.0\r\n\r\n", 1],
-        ["GET http://[::1:2]/ HTTP/1.0\r\n\r\n", 1],
-        ["GET http://[4712::abcd]/ HTTP/1.0\r\n\r\n", 1],
-        ["GET http://[4712::abcd:1]/ HTTP/1.0\r\n\r\n", 1],
-        ["GET http://[4712::abcd::]/ HTTP/1.0\r\n\r\n", 400],
-        ["GET http://[4712:abcd::]/ HTTP/1.0\r\n\r\n", 1],
-        ["GET http://[4712::abcd]:8000/ HTTP/1.0\r\n\r\n", 1],
-        ["GET http://4713::abcd:8001/ HTTP/1.0\r\n\r\n", 400],
-        ["GET / HTTP/1.0\r\nHost: [::1]\r\n\r\n", 1],
-        ["GET / HTTP/1.0\r\nHost: [::1:2]\r\n\r\n", 1],
-        ["GET / HTTP/1.0\r\nHost: [4711::abcd]\r\n\r\n", 1],
-        ["GET / HTTP/1.0\r\nHost: [4711::abcd:1]\r\n\r\n", 1],
-        ["GET / HTTP/1.0\r\nHost: [4711:abcd::]\r\n\r\n", 1],
-        ["GET / HTTP/1.0\r\nHost: [4711::abcd]:8000\r\n\r\n", 1],
-        ["GET / HTTP/1.0\r\nHost: 4714::abcd:8001\r\n\r\n", 200],
-        ["GET / HTTP/1.0\r\nHost: abc\xa0\r\n\r\n", 200],
-        ["GET / HTTP/1.0\r\nHost: abc\\foo\r\n\r\n", 400],
-        ["GET http://foo/ HTTP/1.0\r\nHost: bar\r\n\r\n", 200],
-        ["GET http://foo:81/ HTTP/1.0\r\nHost: bar\r\n\r\n", 200],
-        ["GET http://[::1]:81/ HTTP/1.0\r\nHost: bar\r\n\r\n", 200],
-        ["GET http://10.0.0.1:81/ HTTP/1.0\r\nHost: bar\r\n\r\n", 200],
-        ["GET / HTTP/1.0\r\nHost: foo-bar.example.com\r\n\r\n", 200],
-        ["GET / HTTP/1.0\r\nHost: foo_bar.example.com\r\n\r\n", 200],
-        ["GET http://foo_bar/ HTTP/1.0\r\n\r\n", 200],
+    @pytest.mark.parametrize(["intext", "status", "lognos"], [
+        ["GET / HTTP/1.0\r\n\r\n", 1, None],
+        ["GET / HTTP/1.0\n\n", 1, None],
+        ["get / HTTP/1.0\r\n\r\n", 501, ["AH00135"]],
+        ["G ET / HTTP/1.0\r\n\r\n", 400, None],
+        ["G\0ET / HTTP/1.0\r\n\r\n", 400, None],
+        ["G/T / HTTP/1.0\r\n\r\n", 501, ["AH00135"]],
+        ["GET /\0 HTTP/1.0\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0\0\r\n\r\n", 400, None],
+        ["GET\f/ HTTP/1.0\r\n\r\n", 400, None],
+        ["GET\r/ HTTP/1.0\r\n\r\n", 400, None],
+        ["GET\t/ HTTP/1.0\r\n\r\n", 400, None],
+        ["GET / HTT/1.0\r\n\r\n", 0, None],
+        ["GET / HTTP/1.0\r\nHost: localhost\r\n\r\n", 1, None],
+        ["GET / HTTP/2.0\r\nHost: localhost\r\n\r\n", 1, None],
+        ["GET / HTTP/1.2\r\nHost: localhost\r\n\r\n", 1, None],
+        ["GET / HTTP/1.11\r\nHost: localhost\r\n\r\n", 400, None],
+        ["GET / HTTP/10.0\r\nHost: localhost\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0  \r\nHost: localhost\r\n\r\n", 200, None],
+        ["GET / HTTP/1.0 x\r\nHost: localhost\r\n\r\n", 400, None],
+        ["GET / HTTP/\r\nHost: localhost\r\n\r\n", 0, None],
+        ["GET / HTTP/0.9\r\n\r\n", 0, None],
+        ["GET / HTTP/0.8\r\n\r\n", 0, None],
+        ["GET /\x01 HTTP/1.0\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0\r\nFoo: bar\r\n\r\n", 200, None],
+        ["GET / HTTP/1.0\r\nFoo:bar\r\n\r\n", 200, None],
+        ["GET / HTTP/1.0\r\nFoo: b\0ar\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0\r\nFoo: b\x01ar\r\n\r\n", 200, None],
+        ["GET / HTTP/1.0\r\nFoo\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0\r\nFoo bar\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0\r\n: bar\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0\r\nX: bar\r\n\r\n", 200, None],
+        ["GET / HTTP/1.0\r\nFoo bar:bash\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0\r\nFoo :bar\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0\r\n Foo:bar\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0\r\nF\x01o: bar\r\n\r\n", 200, None],
+        ["GET / HTTP/1.0\r\nF\ro: bar\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0\r\nF\to: bar\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0\r\nFo: b\tar\r\n\r\n", 200, None],
+        ["GET / HTTP/1.0\r\nFo: bar\r\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0\r\r", None, None],
+        ["GET /\r\n", 0, None],
+        ["GET /#frag HTTP/1.0\r\n", 400, None],
+        ["GET / HTTP/1.0\r\nHost: localhost\r\nHost: localhost\r\n\r\n", 200, None],
+        ["GET http://017700000001/ HTTP/1.0\r\n\r\n", 200, None],
+        ["GET http://0x7f.1/ HTTP/1.0\r\n\r\n", 200, None],
+        ["GET http://127.0.0.1/ HTTP/1.0\r\n\r\n", 200, None],
+        ["GET http://127.01.0.1/ HTTP/1.0\r\n\r\n", 200, None],
+        ["GET http://%3127.0.0.1/ HTTP/1.0\r\n\r\n", 200, None],
+        ["GET / HTTP/1.0\r\nHost: localhost:80\r\nHost: localhost:80\r\n\r\n", 200, None],
+        ["GET / HTTP/1.0\r\nHost: localhost:80 x\r\n\r", 400, None],
+        ["GET http://localhost:80/ HTTP/1.0\r\n\r\n", 200, None],
+        ["GET http://localhost:80x/ HTTP/1.0\r\n\r\n", 400, None],
+        ["GET http://localhost:80:80/ HTTP/1.0\r\n\r\n", 400, None],
+        ["GET http://localhost::80/ HTTP/1.0\r\n\r\n", 400, None],
+        ["GET http://foo@localhost:80/ HTTP/1.0\r\n\r\n", 200, None],
+        ["GET http://[::1]/ HTTP/1.0\r\n\r\n", 1, None],
+        ["GET http://[::1:2]/ HTTP/1.0\r\n\r\n", 1, None],
+        ["GET http://[4712::abcd]/ HTTP/1.0\r\n\r\n", 1, None],
+        ["GET http://[4712::abcd:1]/ HTTP/1.0\r\n\r\n", 1, None],
+        ["GET http://[4712::abcd::]/ HTTP/1.0\r\n\r\n", 400, None],
+        ["GET http://[4712:abcd::,]/ HTTP/1.0\r\n\r\n", 1, None],
+        ["GET http://[4712::abcd]:8000/ HTTP/1.0\r\n\r\n", 1, None],
+        ["GET http://4713::abcd:8001/ HTTP/1.0\r\n\r\n", 400, None],
+        ["GET / HTTP/1.0\r\nHost: [::1]\r\n\r\n", 1, None],
+        ["GET / HTTP/1.0\r\nHost: [::1:2]\r\n\r\n", 1, None],
+        ["GET / HTTP/1.0\r\nHost: [4711::abcd]\r\n\r\n", 1, None],
+        ["GET / HTTP/1.0\r\nHost: [4711::abcd:1]\r\n\r\n", 1, None],
+        ["GET / HTTP/1.0\r\nHost: [4711:abcd::]\r\n\r\n", 1, None],
+        ["GET / HTTP/1.0\r\nHost: [4711::abcd]:8000\r\n\r\n", 1, None],
+        ["GET / HTTP/1.0\r\nHost: 4714::abcd:8001\r\n\r\n", 200, None],
+        ["GET / HTTP/1.0\r\nHost: abc\xa0\r\n\r\n", 200, None],
+        ["GET / HTTP/1.0\r\nHost: abc\\foo\r\n\r\n", 400, None],
+        ["GET http://foo/ HTTP/1.0\r\nHost: bar\r\n\r\n", 200, None],
+        ["GET http://foo:81/ HTTP/1.0\r\nHost: bar\r\n\r\n", 200, None],
+        ["GET http://[::1]:81/ HTTP/1.0\r\nHost: bar\r\n\r\n", 200, None],
+        ["GET http://10.0.0.1:81/ HTTP/1.0\r\nHost: bar\r\n\r\n", 200, None],
+        ["GET / HTTP/1.0\r\nHost: foo-bar.example.com\r\n\r\n", 200, None],
+        ["GET / HTTP/1.0\r\nHost: foo_bar.example.com\r\n\r\n", 200, None],
+        ["GET http://foo_bar/ HTTP/1.0\r\n\r\n", 200, None],
     ])
-    def test_h1_006_01(self, env, intext, status: Optional[int]):
+    def test_h1_006_01(self, env, intext, status: Optional[int], lognos: Optional[List[str]]):
         with socket.create_connection(('localhost', int(env.http_port))) as sock:
             # on some OS, the server does not see our connection until there is
             # something incoming
@@ -119,14 +119,16 @@ class TestRequestUnsafe:
                 rlines = msg.splitlines()
                 response = rlines[0]
                 m = re.match(r'^HTTP/1.1 (\d+)\s+(\S+)', response)
-                assert m or status == 90, f"unrecognized response: {rlines}"
+                assert m or status == 0, f"unrecognized response: {rlines}"
                 if status == 1:
                     assert int(m.group(1)) >= 200
-                elif status == 90:
+                elif status == 0:
                     # headerless 0.9 response, yuk
                     assert len(rlines) >= 1, f"{rlines}"
                 elif status > 0:
                     assert int(m.group(1)) == status, f"{rlines}"
                 else:
                     assert int(m.group(1)) >= 400, f"{rlines}"
-
+                #
+                if lognos is not None:
+                    env.httpd_error_log.ignore_recent(lognos = lognos)

Modified: httpd/httpd/trunk/test/modules/http1/test_007_strict.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http1/test_007_strict.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http1/test_007_strict.py (original)
+++ httpd/httpd/trunk/test/modules/http1/test_007_strict.py Fri Jul  7 08:21:21 2023
@@ -1,6 +1,6 @@
 import re
 import socket
-from typing import Optional
+from typing import List, Optional
 
 import pytest
 
@@ -68,17 +68,17 @@ class TestRequestStrict:
                 else:
                     assert int(m.group(1)) >= 400, f"{rlines}"
 
-    @pytest.mark.parametrize(["hvalue", "expvalue", "status"], [
-        ['"123"', '123', 200],
-        ['"123 "', '123 ', 200],       # trailing space stays
-        ['"123\t"', '123\t', 200],     # trailing tab stays
-        ['" 123"', '123', 200],        # leading space is stripped
-        ['"          123"', '123', 200],  # leading spaces are stripped
-        ['"\t123"', '123', 200],       # leading tab is stripped
-        ['"expr=%{unescape:123%0A 123}"', '', 500],  # illegal char
-        ['" \t "', '', 200],           # just ws
+    @pytest.mark.parametrize(["hvalue", "expvalue", "status", "lognos"], [
+        ['"123"', '123', 200, None],
+        ['"123 "', '123 ', 200, None],       # trailing space stays
+        ['"123\t"', '123\t', 200, None],     # trailing tab stays
+        ['" 123"', '123', 200, None],        # leading space is stripped
+        ['"          123"', '123', 200, None],  # leading spaces are stripped
+        ['"\t123"', '123', 200, None],       # leading tab is stripped
+        ['"expr=%{unescape:123%0A 123}"', '', 500, ["AH02430"]],  # illegal char
+        ['" \t "', '', 200, None],           # just ws
     ])
-    def test_h1_007_02(self, env, hvalue, expvalue, status):
+    def test_h1_007_02(self, env, hvalue, expvalue, status, lognos: Optional[List[str]]):
         hname = 'ap-test-007'
         conf = H1Conf(env, extras={
             f'test1.{env.http_tld}': [
@@ -95,6 +95,9 @@ class TestRequestStrict:
         assert r.response["status"] == status
         if int(status) < 400:
             assert r.response["header"][hname] == expvalue
+        #
+        if lognos is not None:
+            env.httpd_error_log.ignore_recent(lognos = lognos)
 
     @pytest.mark.parametrize(["hvalue", "expvalue"], [
         ['123', '123'],

Modified: httpd/httpd/trunk/test/modules/http2/conftest.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/conftest.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/conftest.py (original)
+++ httpd/httpd/trunk/test/modules/http2/conftest.py Fri Jul  7 08:21:21 2023
@@ -30,11 +30,8 @@ def env(pytestconfig) -> H2TestEnv:
 
 
 @pytest.fixture(autouse=True, scope="package")
-def _session_scope(env):
-    yield
-    assert env.apache_stop() == 0
-    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))
-
+def _h2_package_scope(env):
+    env.httpd_error_log.add_ignored_lognos([
+        'AH10400',  # warning that 'enablereuse' has not effect in certain configs
+        'AH00045',  # child did not exit in time, SIGTERM was sent
+    ])

Modified: httpd/httpd/trunk/test/modules/http2/env.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/env.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/env.py (original)
+++ httpd/httpd/trunk/test/modules/http2/env.py Fri Jul  7 08:21:21 2023
@@ -1,7 +1,6 @@
 import inspect
 import logging
 import os
-import re
 import subprocess
 from typing import Dict, Any
 
@@ -85,34 +84,6 @@ class H2TestEnv(HttpdTestEnv):
             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
-            'AH02429',  # invalid chars in response header names, see test_h2_200
-            'AH02430',  # invalid chars in response header values, see test_h2_200
-            'AH10373',  # SSL errors on uncompleted handshakes, see test_h2_105
-            'AH01247',  # mod_cgid sometimes freaks out on load tests
-            'AH01110',  # error by proxy reading response
-            'AH10400',  # warning that 'enablereuse' has not effect in certain configs test_h2_600
-            'AH00045',  # child did not exit in time, SIGTERM was sent
-        ])
-        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:.*'),
-            # OSSL 3 dropped the function name from the error description. Use the code instead:
-            # 0A0000C1 = no shared cipher -- Too restrictive SSLCipherSuite or using DSA server certificate?
-            re.compile(r'.*SSL Library Error: error:0A0000C1:.*'),
-            re.compile(r'.*:tls_process_client_certificate:.*'),
-            # OSSL 3 dropped the function name from the error description. Use the code instead:
-            # 0A0000C7 = peer did not return a certificate -- No CAs known to server for verification?
-            re.compile(r'.*SSL Library Error: error:0A0000C7:.*'),
-            re.compile(r'.*have incompatible TLS configurations.'),
-        ])
-
     def setup_httpd(self, setup: HttpdTestSetup = None):
         super().setup_httpd(setup=H2TestSetup(env=self))
 

Modified: httpd/httpd/trunk/test/modules/http2/test_007_ssi.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_007_ssi.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_007_ssi.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_007_ssi.py Fri Jul  7 08:21:21 2023
@@ -1,4 +1,3 @@
-import re
 import pytest
 
 from .env import H2Conf, H2TestEnv

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=1910844&r1=1910843&r2=1910844&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 Fri Jul  7 08:21:21 2023
@@ -48,6 +48,12 @@ class TestConnReuse:
         hostname = ("noh2.%s" % env.http_tld)
         r = env.curl_get(url, 5, options=[ "-H", "Host:%s" % hostname ])
         assert 421 == r.response["status"]
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH02032"   # Hostname provided via SNI and hostname provided via HTTP have no compatible SSL setup
+            ]
+        )
 
     # access an unknown vhost, after using ServerName in SNI
     def test_h2_100_05(self, env):
@@ -55,3 +61,9 @@ class TestConnReuse:
         hostname = ("unknown.%s" % env.http_tld)
         r = env.curl_get(url, 5, options=[ "-H", "Host:%s" % hostname ])
         assert 421 == r.response["status"]
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH02032"   # Hostname provided via SNI and hostname provided via HTTP have no compatible SSL setup
+            ]
+        )

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=1910844&r1=1910843&r2=1910844&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 Fri Jul  7 08:21:21 2023
@@ -56,6 +56,12 @@ class TestSslRenegotiation:
         assert 0 == r.exit_code, f"{r}"
         assert r.response
         assert 403 == r.response["status"]
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH01276" # No matching DirectoryIndex found
+            ]
+        )
         
     # try to renegotiate the cipher, should fail with correct code
     def test_h2_101_02(self, env):
@@ -66,6 +72,16 @@ class TestSslRenegotiation:
         assert 0 != r.exit_code
         assert not r.response
         assert re.search(r'HTTP_1_1_REQUIRED \(err 13\)', r.stderr)
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH02261"   # Re-negotiation handshake failed
+            ],
+            matches = [
+                r'.*:tls_post_process_client_hello:.*',
+                r'.*SSL Library Error:.*:SSL routines::no shared cipher.*'
+            ]
+        )
         
     # try to renegotiate a client certificate from Location 
     # needs to fail with correct code
@@ -75,6 +91,16 @@ class TestSslRenegotiation:
         assert 0 != r.exit_code
         assert not r.response
         assert re.search(r'HTTP_1_1_REQUIRED \(err 13\)', r.stderr)
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH02261"   # Re-negotiation handshake failed
+            ],
+            matches = [
+                r'.*:tls_process_client_certificate:.*',
+                r'.*SSL Library Error:.*:SSL routines::peer did not return a certificate.*'
+            ]
+        )
         
     # try to renegotiate a client certificate from Directory 
     # needs to fail with correct code
@@ -84,6 +110,16 @@ class TestSslRenegotiation:
         assert 0 != r.exit_code, f"{r}"
         assert not r.response
         assert re.search(r'HTTP_1_1_REQUIRED \(err 13\)', r.stderr)
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH02261"   # Re-negotiation handshake failed
+            ],
+            matches = [
+                r'.*:tls_process_client_certificate:.*',
+                r'.*SSL Library Error:.*:SSL routines::peer did not return a certificate.*'
+            ]
+        )
         
     # make 10 requests on the same connection, none should produce a status code
     # reported by erki@example.ee
@@ -128,3 +164,13 @@ class TestSslRenegotiation:
         assert 0 != r.exit_code
         assert not r.response
         assert re.search(r'HTTP_1_1_REQUIRED \(err 13\)', r.stderr)
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH02261"   # Re-negotiation handshake failed
+            ],
+            matches = [
+                r'.*:tls_post_process_client_hello:.*',
+                r'.*SSL Library Error:.*:SSL routines::no shared cipher.*'
+            ]
+        )

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=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_102_require.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_102_require.py Fri Jul  7 08:21:21 2023
@@ -39,3 +39,9 @@ class TestRequire:
         assert 0 == r.exit_code
         assert r.response
         assert 403 == r.response["status"]
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH01630"   # client denied by server configuration
+            ]
+        )

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=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_105_timeout.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_105_timeout.py Fri Jul  7 08:21:21 2023
@@ -42,6 +42,13 @@ class TestTimeout:
         except Exception as ex:
             print(f"as expected: {ex}")
         sock.close()
+        #
+        time.sleep(1) # let the log flush
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10373"   # SSL handshake was not completed
+            ]
+        )
 
     # Check that mod_reqtimeout handshake setting takes effect
     def test_h2_105_02(self, env):
@@ -77,6 +84,13 @@ class TestTimeout:
         except Exception as ex:
             print(f"as expected: {ex}")
         sock.close()
+        #
+        time.sleep(1) # let the log flush
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10373"   # SSL handshake was not completed
+            ]
+        )
 
     # Check that mod_reqtimeout handshake setting do no longer apply to handshaked 
     # connections. See <https://github.com/icing/mod_h2/issues/196>.

Modified: httpd/httpd/trunk/test/modules/http2/test_106_shutdown.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_106_shutdown.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_106_shutdown.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_106_shutdown.py Fri Jul  7 08:21:21 2023
@@ -72,4 +72,10 @@ class TestShutdown:
             else:
                 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
+                assert "HTTP/2" == r.response["protocol"]
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH03490"   # scoreboard is full, not at MaxRequestWorkers
+            ]
+        )
\ No newline at end of file

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=1910844&r1=1910843&r2=1910844&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 Fri Jul  7 08:21:21 2023
@@ -28,6 +28,15 @@ class TestInvalidHeaders:
                 assert 500 == r.response["status"], f'unexpected status for char 0x{x:02}'
             else:
                 assert 0 != r.exit_code, f'unexpected exit code for char 0x{x:02}'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH02429"   # Response header name contains invalid characters
+            ],
+            matches = [
+                r'.*malformed header from script \'hecho.py\': Bad header: x.*'
+            ]
+        )
 
     # let the hecho.py CGI echo chars < 0x20 in field value
     # for almost all such characters, the stream returns a 500
@@ -46,6 +55,12 @@ class TestInvalidHeaders:
                     assert 500 == r.response["status"], f'unexpected status for char 0x{x:02}'
                 else:
                     assert 0 != r.exit_code, "unexpected exit code for char 0x%02x" % x
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH02430"   # Response header value contains invalid characters
+            ]
+        )
 
     # let the hecho.py CGI echo 0x10 and 0x7f in field name and value
     def test_h2_200_03(self, env):
@@ -63,6 +78,13 @@ class TestInvalidHeaders:
                 assert 500 == r.response["status"], f"unexpected exit code for char 0x{h:02}"
             else:
                 assert 0 != r.exit_code
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH02429",  # Response header name contains invalid characters
+                "AH02430"   # Response header value contains invalid characters
+            ]
+        )
 
     # test header field lengths check, LimitRequestLine (default 8190)
     def test_h2_200_10(self, env):

Modified: httpd/httpd/trunk/test/modules/http2/test_203_rfc9113.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_203_rfc9113.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_203_rfc9113.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_203_rfc9113.py Fri Jul  7 08:21:21 2023
@@ -1,4 +1,5 @@
 import pytest
+from typing import List, Optional
 
 from pyhttpd.env import HttpdTestEnv
 from .env import H2Conf
@@ -22,17 +23,17 @@ class TestRfc9113:
         assert r.response["status"] == 200, f'curl output: {r.stdout}'
 
     # response header are also handled, but we strip ws before sending
-    @pytest.mark.parametrize(["hvalue", "expvalue", "status"], [
-        ['"123"', '123', 200],
-        ['"123 "', '123', 200],       # trailing space stripped
-        ['"123\t"', '123', 200],     # trailing tab stripped
-        ['" 123"', '123', 200],        # leading space is stripped
-        ['"          123"', '123', 200],  # leading spaces are stripped
-        ['"\t123"', '123', 200],       # leading tab is stripped
-        ['"expr=%{unescape:123%0A 123}"', '', 500],  # illegal char
-        ['" \t "', '', 200],          # just ws
+    @pytest.mark.parametrize(["hvalue", "expvalue", "status", "lognos"], [
+        ['"123"', '123', 200, None],
+        ['"123 "', '123', 200, None],       # trailing space stripped
+        ['"123\t"', '123', 200, None],     # trailing tab stripped
+        ['" 123"', '123', 200, None],        # leading space is stripped
+        ['"          123"', '123', 200, None],  # leading spaces are stripped
+        ['"\t123"', '123', 200, None],       # leading tab is stripped
+        ['"expr=%{unescape:123%0A 123}"', '', 500, ["AH02430"]],  # illegal char
+        ['" \t "', '', 200, None],          # just ws
     ])
-    def test_h2_203_02(self, env, hvalue, expvalue, status):
+    def test_h2_203_02(self, env, hvalue, expvalue, status, lognos: Optional[List[str]]):
         hname = 'ap-test-007'
         conf = H2Conf(env, extras={
             f'test1.{env.http_tld}': [
@@ -53,4 +54,7 @@ class TestRfc9113:
         assert r.response["status"] == status
         if int(status) < 400:
             assert r.response["header"][hname] == expvalue
+        #
+        if lognos is not None:
+            env.httpd_error_log.ignore_recent(lognos = lognos)
 

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=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_500_proxy.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_500_proxy.py Fri Jul  7 08:21:21 2023
@@ -149,9 +149,21 @@ class TestProxy:
         url = env.mkurl("https", "cgi", "/proxy/h2test/error?body_error=timeout")
         r = env.curl_get(url)
         assert r.exit_code != 0, r
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH01110"   # Network error reading response
+            ]
+        )
 
     # produce an error, fail to generate an error bucket
     def test_h2_500_32(self, env, repeat):
         url = env.mkurl("https", "cgi", "/proxy/h2test/error?body_error=timeout&error_bucket=0")
         r = env.curl_get(url)
         assert r.exit_code != 0, r
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH01110"   # Network error reading response
+            ]
+        )

Modified: httpd/httpd/trunk/test/modules/http2/test_800_websockets.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/http2/test_800_websockets.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/http2/test_800_websockets.py (original)
+++ httpd/httpd/trunk/test/modules/http2/test_800_websockets.py Fri Jul  7 08:21:21 2023
@@ -154,7 +154,6 @@ class TestWebSockets:
         r, infos, frames = ws_run(env, path='/ws/echo/', scenario='fail-proto')
         assert r.exit_code == 0, f'{r}'
         assert infos == ['[1] :status: 501', '[1] EOF'], f'{r}'
-        env.httpd_error_log.ignore_recent()
 
     # a correct CONNECT, send CLOSE, expect CLOSE, basic success
     def test_h2_800_02_ws_empty(self, env: H2TestEnv, ws_server):

Modified: httpd/httpd/trunk/test/modules/md/conftest.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/conftest.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/conftest.py (original)
+++ httpd/httpd/trunk/test/modules/md/conftest.py Fri Jul  7 08:21:21 2023
@@ -1,6 +1,5 @@
 import logging
 import os
-import re
 import sys
 import pytest
 
@@ -37,44 +36,11 @@ def env(pytestconfig) -> MDTestEnv:
 
 
 @pytest.fixture(autouse=True, scope="package")
-def _session_scope(env):
-    # we'd like to check the httpd error logs after the test suite has
-    # run to catch anything unusual. For this, we setup the ignore list
-    # of errors and warnings that we do expect.
-    env.httpd_error_log.set_ignored_lognos([
-        'AH10040',  # mod_md, setup complain
-        'AH10045',  # mod_md complains that there is no vhost for an MDomain
-        'AH10056',  # mod_md, invalid params
-        'AH10105',  # mod_md does not find a vhost with SSL enabled for an MDomain
-        'AH10085',  # mod_ssl complains about fallback certificates
-        'AH01909',  # mod_ssl, cert alt name complains
-        'AH10170',  # mod_md, wrong config, tested
-        'AH10171',  # mod_md, wrong config, tested
-        'AH10373',  # SSL errors on uncompleted handshakes
-        'AH10398',  # test on global store lock
+def _md_package_scope(env):
+    env.httpd_error_log.add_ignored_lognos([
+        "AH10085"   # There are no SSL certificates configured and no other module contributed any
     ])
 
-    env.httpd_error_log.add_ignored_patterns([
-        re.compile(r'.*urn:ietf:params:acme:error:.*'),
-        re.compile(r'.*None of the ACME challenge methods configured for this domain are suitable.*'),
-        re.compile(r'.*problem\[(challenge-mismatch|challenge-setup-failure|apache:eab-hmac-invalid)].*'),
-        re.compile(r'.*CA considers answer to challenge invalid.].*'),
-        re.compile(r'.*problem\[urn:org:apache:httpd:log:AH\d+:].*'),
-        re.compile(r'.*Unsuccessful in contacting ACME server at :*'),
-        re.compile(r'.*test-md-720-002-\S+.org: dns-01 setup command failed .*'),
-        re.compile(r'.*AH\d*: unable to obtain global registry lock, .*'),
-    ])
-    if env.lacks_ocsp():
-        env.httpd_error_log.add_ignored_patterns([
-            re.compile(r'.*certificate with serial \S+ has no OCSP responder URL.*'),
-        ])
-    yield
-    assert env.apache_stop() == 0
-    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))
-
 
 @pytest.fixture(scope="package")
 def acme(env):

Modified: httpd/httpd/trunk/test/modules/md/test_300_conf_validate.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/test_300_conf_validate.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/test_300_conf_validate.py (original)
+++ httpd/httpd/trunk/test/modules/md/test_300_conf_validate.py Fri Jul  7 08:21:21 2023
@@ -24,6 +24,12 @@ class TestConf:
             MDomain not-forbidden.org www.not-forbidden.org mail.not-forbidden.org
             """).install()
         assert env.apache_restart() == 0
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10045"   # No VirtualHost matches Managed Domain
+            ]
+        )
 
     # test case: two MDomain definitions, non-overlapping
     def test_md_300_002(self, env):
@@ -32,6 +38,12 @@ class TestConf:
             MDomain example2.org www.example2.org mail.example2.org
             """).install()
         assert env.apache_restart() == 0
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10045"   # No VirtualHost matches Managed Domain
+            ]
+        )
 
     # test case: two MDomain definitions, exactly the same
     def test_md_300_003(self, env):
@@ -41,6 +53,12 @@ class TestConf:
             MDomain not-forbidden.org www.not-forbidden.org mail.not-forbidden.org test3.not-forbidden.org
             """).install()
         assert env.apache_fail() == 0
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10038"   # two Managed Domains have an overlap in domain
+            ]
+        )
 
     # test case: two MDomain definitions, overlapping
     def test_md_300_004(self, env):
@@ -50,6 +68,12 @@ class TestConf:
             MDomain example2.org test3.not-forbidden.org www.example2.org mail.example2.org
             """).install()
         assert env.apache_fail() == 0
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10038"   # two Managed Domains have an overlap in domain
+            ]
+        )
 
     # test case: two MDomains, one inside a virtual host
     def test_md_300_005(self, env):
@@ -60,6 +84,12 @@ class TestConf:
             </VirtualHost>
             """).install()
         assert env.apache_restart() == 0
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10045"   # No VirtualHost matches Managed Domain
+            ]
+        )
 
     # test case: two MDomains, one correct vhost name
     def test_md_300_006(self, env):
@@ -71,6 +101,12 @@ class TestConf:
             </VirtualHost>
             """).install()
         assert env.apache_restart() == 0
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10045"   # No VirtualHost matches Managed Domain
+            ]
+        )
 
     # test case: two MDomains, two correct vhost names
     def test_md_300_007(self, env):
@@ -85,6 +121,12 @@ class TestConf:
             </VirtualHost>
             """).install()
         assert env.apache_restart() == 0
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10045"   # No VirtualHost matches Managed Domain
+            ]
+        )
 
     # test case: two MDomains, overlapping vhosts
     def test_md_300_008(self, env):
@@ -102,6 +144,12 @@ class TestConf:
             </VirtualHost>
             """).install()
         assert env.apache_restart() == 0
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10045"   # No VirtualHost matches Managed Domain
+            ]
+        )
 
     # test case: vhosts with overlapping MDs
     def test_md_300_009(self, env):
@@ -118,7 +166,12 @@ class TestConf:
         conf.install()
         assert env.apache_fail() == 0
         env.apache_stop()
-        env.httpd_error_log.ignore_recent()
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10238"   # 2 MDs match Virtualhost
+            ]
+        )
 
     # test case: MDomain, vhost with matching ServerAlias
     def test_md_300_010(self, env):
@@ -146,6 +199,9 @@ class TestConf:
         conf.install()
         assert env.apache_fail() == 0
         env.apache_stop()
+        env.httpd_error_log.ignore_recent([
+            "AH10040"   # A requested MD certificate will not match ServerName
+        ])
 
     # test case: MDomain, misses one ServerAlias, but auto add enabled
     def test_md_300_011b(self, env):
@@ -171,6 +227,12 @@ class TestConf:
             </VirtualHost>
             """).install()
         assert env.apache_restart() == 0
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10045"   # No VirtualHost matches Managed Domain
+            ]
+        )
 
     # test case: one md covers two vhosts
     def test_md_300_013(self, env):
@@ -261,7 +323,6 @@ class TestConf:
         MDConf(env, text=line).install()
         assert env.apache_fail() == 0, "Server accepted test config {}".format(line)
         assert exp_err_msg in env.apachectl_stderr
-        env.httpd_error_log.ignore_recent()
 
     # test case: alt-names incomplete detection, github isse #68
     def test_md_300_021(self, env):
@@ -294,6 +355,12 @@ class TestConf:
             </VirtualHost>
             """).install()
         assert env.apache_restart() == 0
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10105"   # MD secret.com does not match any VirtualHost with 'SSLEngine on'
+            ]
+        )
 
     # test case: use MDRequireHttps not in <Directory
     def test_md_300_023(self, env):

Modified: httpd/httpd/trunk/test/modules/md/test_702_auto.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/test_702_auto.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/test_702_auto.py (original)
+++ httpd/httpd/trunk/test/modules/md/test_702_auto.py Fri Jul  7 08:21:21 2023
@@ -64,6 +64,12 @@ class TestAutov2:
         # file system needs to have correct permissions
         env.check_dir_empty(env.store_challenges())
         env.check_file_permissions(domain)
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10045"   # No VirtualHost matches Managed Domain test-md-702-001-1688648129.org
+            ]
+        )
 
     # test case: same as test_702_001, but with two parallel managed domains
     def test_md_702_002(self, env):
@@ -234,6 +240,15 @@ class TestAutov2:
         cert = env.get_cert(name_a)
         assert name_a in cert.get_san_list()
         assert env.get_http_status(name_a, "/name.txt") == 503
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # None of offered challenge types
+            ],
+            matches = [
+                r'.*problem\[challenge-mismatch\].*'
+            ]
+        )
 
     # Specify a non-working http proxy
     def test_md_702_008(self, env):
@@ -254,6 +269,15 @@ class TestAutov2:
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['status-description'] == 'Connection refused'
         assert 'account' not in md['ca']
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # Unsuccessful in contacting ACME server
+            ],
+            matches = [
+                r'.*Unsuccessful in contacting ACME server at .*'
+            ]
+        )
 
     # Specify a valid http proxy
     def test_md_702_008a(self, env):
@@ -335,6 +359,16 @@ class TestAutov2:
         assert env.apache_restart() == 0
         env.check_md(domains)
         assert env.await_completion([domain])
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10173",  # None of the ACME challenge methods configured for this domain are suitable
+                "AH10056"   # None of the ACME challenge methods configured for this domain are suitable
+            ],
+            matches = [
+                r'.*None of the ACME challenge methods configured for this domain are suitable.*'
+            ]
+        )
 
     def test_md_702_011(self, env):
         domain = self.test_domain
@@ -364,6 +398,16 @@ class TestAutov2:
         assert env.apache_restart() == 0
         env.check_md(domains)
         assert env.await_completion([domain])
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10173",  # None of the ACME challenge methods configured for this domain are suitable
+                "AH10056"   # None of the ACME challenge methods configured for this domain are suitable
+            ],
+            matches = [
+                r'.*None of the ACME challenge methods configured for this domain are suitable.*'
+            ]
+        )
 
     # test case: one MD with several dns names. sign up. remove the *first* name
     # in the MD. restart. should find and keep the existing MD.
@@ -648,6 +692,16 @@ class TestAutov2:
         conf.install()
         assert env.apache_restart() == 0
         assert env.await_error(domain)
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10173",  # None of the ACME challenge methods configured for this domain are suitable
+                "AH10056"   # None of the ACME challenge methods configured for this domain are suitable
+            ],
+            matches = [
+                r'.*None of the ACME challenge methods configured for this domain are suitable.*'
+            ]
+        )
 
     # Make a setup using the base server without http:, but with acme-tls/1, should work.
     def test_md_702_052(self, env):

Modified: httpd/httpd/trunk/test/modules/md/test_720_wildcard.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/test_720_wildcard.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/test_720_wildcard.py (original)
+++ httpd/httpd/trunk/test/modules/md/test_720_wildcard.py Fri Jul  7 08:21:21 2023
@@ -44,6 +44,15 @@ class TestWildcard:
         assert md
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['problem'] == 'challenge-mismatch'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # None of offered challenge types
+            ],
+            matches = [
+                r'.*problem\[challenge-mismatch\].*'
+            ]
+        )
 
     # test case: a wildcard certificate with ACMEv2, only dns-01 configured, invalid command path
     def test_md_720_002(self, env):
@@ -67,6 +76,16 @@ class TestWildcard:
         assert md
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['problem'] == 'challenge-setup-failure'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # None of offered challenge types
+            ],
+            matches = [
+                r'.*problem\[challenge-setup-failure\].*',
+                r'.*setup command failed to execute.*'
+            ]
+        )
 
     # variation, invalid cmd path, other challenges still get certificate for non-wildcard
     def test_md_720_002b(self, env):
@@ -113,6 +132,15 @@ class TestWildcard:
         assert md
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['problem'] == 'challenge-setup-failure'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # None of offered challenge types
+            ],
+            matches = [
+                r'.*problem\[challenge-setup-failure\].*'
+            ]
+        )
 
     # test case: a wildcard name certificate with ACMEv2, only dns-01 configured
     def test_md_720_004(self, env):

Modified: httpd/httpd/trunk/test/modules/md/test_730_static.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/test_730_static.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/test_730_static.py (original)
+++ httpd/httpd/trunk/test/modules/md/test_730_static.py Fri Jul  7 08:21:21 2023
@@ -115,3 +115,10 @@ class TestStatic:
         conf.add_vhost(domain)
         conf.install()
         assert env.apache_fail() == 0
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10170",  # Managed Domain needs one MDCertificateKeyFile for each MDCertificateFile
+                "AH10171"   # Managed Domain has MDCertificateKeyFile(s) but no MDCertificateFile
+            ]
+        )

Modified: httpd/httpd/trunk/test/modules/md/test_740_acme_errors.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/test_740_acme_errors.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/test_740_acme_errors.py (original)
+++ httpd/httpd/trunk/test/modules/md/test_740_acme_errors.py Fri Jul  7 08:21:21 2023
@@ -46,6 +46,15 @@ class TestAcmeErrors:
             assert md['renewal']['last']['detail'] == (
                     "Error creating new order :: Cannot issue for "
                     "\"%s\": Domain name contains an invalid character" % domains[1])
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # Order included DNS identifier with a value containing an illegal character
+            ],
+            matches = [
+                r'.*urn:ietf:params:acme:error:malformed.*'
+            ]
+        )
 
     # test case: MD with 3 names, 2 invalid
     #
@@ -70,3 +79,12 @@ class TestAcmeErrors:
                 "Error creating new order :: Cannot issue for")
             assert md['renewal']['last']['subproblems']
             assert len(md['renewal']['last']['subproblems']) == 2
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # Order included DNS identifier with a value containing an illegal character
+            ],
+            matches = [
+                r'.*urn:ietf:params:acme:error:malformed.*'
+            ]
+        )

Modified: httpd/httpd/trunk/test/modules/md/test_741_setup_errors.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/test_741_setup_errors.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/test_741_setup_errors.py (original)
+++ httpd/httpd/trunk/test/modules/md/test_741_setup_errors.py Fri Jul  7 08:21:21 2023
@@ -46,3 +46,13 @@ class TestSetupErrors:
         md = env.await_error(domain, errors=2, timeout=10)
         assert md
         assert md['renewal']['errors'] > 0
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # CA considers answer to challenge invalid
+            ],
+            matches = [
+                r'.*The key authorization file from the server did not match this challenge.*',
+                r'.*CA considers answer to challenge invalid.*'
+            ]
+        )

Modified: httpd/httpd/trunk/test/modules/md/test_750_eab.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/test_750_eab.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/test_750_eab.py (original)
+++ httpd/httpd/trunk/test/modules/md/test_750_eab.py Fri Jul  7 08:21:21 2023
@@ -37,6 +37,15 @@ class TestEab:
         md = env.await_error(domain)
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['problem'] == 'urn:ietf:params:acme:error:externalAccountRequired'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # ACME server policy requires newAccount requests must include a value for the 'externalAccountBinding' field
+            ],
+            matches = [
+                r'.*urn:ietf:params:acme:error:externalAccountRequired.*'
+            ]
+        )
 
     def test_md_750_002(self, env):
         # md with known EAB KID and non base64 hmac key configured
@@ -51,6 +60,15 @@ class TestEab:
         md = env.await_error(domain)
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['problem'] == 'apache:eab-hmac-invalid'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # external account binding HMAC value is not valid base64
+            ],
+            matches = [
+                r'.*problem\[apache:eab-hmac-invalid\].*'
+            ]
+        )
 
     def test_md_750_003(self, env):
         # md with empty EAB KID configured
@@ -65,6 +83,15 @@ class TestEab:
         md = env.await_error(domain)
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['problem'] == 'urn:ietf:params:acme:error:unauthorized'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # the field 'kid' references a key that is not known to the ACME server
+            ],
+            matches = [
+                r'.*urn:ietf:params:acme:error:unauthorized.*'
+            ]
+        )
 
     def test_md_750_004(self, env):
         # md with unknown EAB KID configured
@@ -79,6 +106,15 @@ class TestEab:
         md = env.await_error(domain)
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['problem'] == 'urn:ietf:params:acme:error:unauthorized'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # the field 'kid' references a key that is not known to the ACME server
+            ],
+            matches = [
+                r'.*urn:ietf:params:acme:error:unauthorized.*'
+            ]
+        )
 
     def test_md_750_005(self, env):
         # md with known EAB KID but wrong HMAC configured
@@ -93,6 +129,15 @@ class TestEab:
         md = env.await_error(domain)
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['problem'] == 'urn:ietf:params:acme:error:unauthorized'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # external account binding JWS verification error: square/go-jose: error in cryptographic primitive
+            ],
+            matches = [
+                r'.*urn:ietf:params:acme:error:unauthorized.*'
+            ]
+        )
 
     def test_md_750_010(self, env):
         # md with correct EAB configured
@@ -125,6 +170,15 @@ class TestEab:
         md = env.await_error(domain_b)
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['problem'] == 'urn:ietf:params:acme:error:externalAccountRequired'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # ACME server policy requires newAccount requests must include a value for the 'externalAccountBinding' field
+            ],
+            matches = [
+                r'.*urn:ietf:params:acme:error:externalAccountRequired.*'
+            ]
+        )
 
     def test_md_750_012(self, env):
         # first one md without EAB, then one with
@@ -144,6 +198,15 @@ class TestEab:
         md = env.await_error(domain_a)
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['problem'] == 'urn:ietf:params:acme:error:externalAccountRequired'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # ACME server policy requires newAccount requests must include a value for the 'externalAccountBinding' field
+            ],
+            matches = [
+                r'.*urn:ietf:params:acme:error:externalAccountRequired.*'
+            ]
+        )
 
     def test_md_750_013(self, env):
         # 2 mds with the same EAB, should one create a single account
@@ -215,6 +278,15 @@ class TestEab:
         md = env.await_error(domain)
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['problem'] == 'urn:ietf:params:acme:error:externalAccountRequired'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # ACME server policy requires newAccount requests must include a value for the 'externalAccountBinding' field
+            ],
+            matches = [
+                r'.*urn:ietf:params:acme:error:externalAccountRequired.*'
+            ]
+        )
 
     def test_md_750_016(self, env):
         # md with correct EAB, get cert, change to invalid EAB
@@ -241,6 +313,15 @@ class TestEab:
         md = env.await_error(domain)
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['problem'] == 'urn:ietf:params:acme:error:unauthorized'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # the field 'kid' references a key that is not known to the ACME server
+            ],
+            matches = [
+                r'.*urn:ietf:params:acme:error:unauthorized.*'
+            ]
+        )
 
     def test_md_750_017(self, env):
         # md without EAB explicitly set to none
@@ -257,6 +338,15 @@ class TestEab:
         md = env.await_error(domain)
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['problem'] == 'urn:ietf:params:acme:error:externalAccountRequired'
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # ACME server policy requires newAccount requests must include a value for the 'externalAccountBinding' field
+            ],
+            matches = [
+                r'.*urn:ietf:params:acme:error:externalAccountRequired.*'
+            ]
+        )
 
     def test_md_750_018(self, env):
         # md with EAB file that does not exist

Modified: httpd/httpd/trunk/test/modules/md/test_780_tailscale.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/test_780_tailscale.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/test_780_tailscale.py (original)
+++ httpd/httpd/trunk/test/modules/md/test_780_tailscale.py Fri Jul  7 08:21:21 2023
@@ -140,6 +140,12 @@ class TestTailscale:
         assert md['renewal']['last']['status-description'] == 'No such file or directory'
         assert md['renewal']['last']['detail'] == \
                f"tailscale socket not available, may not be up: {socket_path}"
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # retrieving certificate from tailscale
+            ]
+        )
 
     # create a MD using `tailscale` as protocol, path to faker, should succeed
     def test_md_780_002(self, env):
@@ -184,3 +190,9 @@ class TestTailscale:
         assert md['renewal']['errors'] > 0
         assert md['renewal']['last']['status-description'] == 'No such file or directory'
         assert md['renewal']['last']['detail'] == "retrieving certificate from tailscale"
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # retrieving certificate from tailscale
+            ]
+        )

Modified: httpd/httpd/trunk/test/modules/md/test_790_failover.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/test_790_failover.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/test_790_failover.py (original)
+++ httpd/httpd/trunk/test/modules/md/test_790_failover.py Fri Jul  7 08:21:21 2023
@@ -63,6 +63,15 @@ class TestFailover:
         assert env.apache_restart() == 0
         assert env.await_completion([domain])
         env.check_md_complete(domain)
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # Unsuccessful in contacting ACME server
+            ],
+            matches = [
+                r'.*Unsuccessful in contacting ACME server at .*'
+            ]
+        )
 
     # set 3 ACME certificata authority, invalid + invalid + valid
     def test_md_790_003(self, env):
@@ -85,3 +94,12 @@ class TestFailover:
         assert env.apache_restart() == 0
         assert env.await_completion([domain])
         env.check_md_complete(domain)
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # Unsuccessful in contacting ACME server
+            ],
+            matches = [
+                r'.*Unsuccessful in contacting ACME server at .*'
+            ]
+        )

Modified: httpd/httpd/trunk/test/modules/md/test_900_notify.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/test_900_notify.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/test_900_notify.py (original)
+++ httpd/httpd/trunk/test/modules/md/test_900_notify.py Fri Jul  7 08:21:21 2023
@@ -49,6 +49,12 @@ class TestNotify:
         assert env.await_error(self.domain)
         stat = env.get_md_status(self.domain)
         assert stat["renewal"]["last"]["problem"] == "urn:org:apache:httpd:log:AH10108:"
+        #
+        env.httpd_error_log.ignore_recent(
+            matches = [
+                r'.*urn:org:apache:httpd:log:AH10108:.*'
+            ]
+        )
 
     # test: valid notify cmd that fails, check error
     def test_md_900_002(self, env):
@@ -61,6 +67,14 @@ class TestNotify:
         assert env.await_error(self.domain)
         stat = env.get_md_status(self.domain)
         assert stat["renewal"]["last"]["problem"] == "urn:org:apache:httpd:log:AH10108:"
+        #
+        env.httpd_error_log.ignore_recent(
+            matches = [
+                r'.*urn:org:apache:httpd:log:AH10108:.*',
+                r'.*urn:org:apache:httpd:log:AH10109:.*'
+                r'.*problem\[challenge-setup-failure\].*',
+            ]
+        )
 
     # test: valid notify that logs to file
     def test_md_900_010(self, env):

Modified: httpd/httpd/trunk/test/modules/md/test_901_message.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/test_901_message.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/test_901_message.py (original)
+++ httpd/httpd/trunk/test/modules/md/test_901_message.py Fri Jul  7 08:21:21 2023
@@ -46,6 +46,16 @@ class TestMessage:
         stat = env.get_md_status(domain)
         # this command should have failed and logged an error
         assert stat["renewal"]["last"]["problem"] == "urn:org:apache:httpd:log:AH10109:"
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # None of the offered challenge types
+            ],
+            matches = [
+                r'.*urn:org:apache:httpd:log:AH10109:.*',
+                r'.*problem\[challenge-setup-failure\].*'
+            ]
+        )
 
     # test: signup with configured message cmd that is valid but returns != 0
     def test_md_901_002(self, env):
@@ -63,6 +73,16 @@ class TestMessage:
         stat = env.get_md_status(domain)
         # this command should have failed and logged an error
         assert stat["renewal"]["last"]["problem"] == "urn:org:apache:httpd:log:AH10109:"
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # None of the offered challenge types
+            ],
+            matches = [
+                r'.*urn:org:apache:httpd:log:AH10109:.*',
+                r'.*problem\[challenge-setup-failure\].*'
+            ]
+        )
 
     # test: signup with working message cmd and see that it logs the right things
     def test_md_901_003(self, env):
@@ -247,7 +267,6 @@ class TestMessage:
                     assert job["last"]["problem"] == "urn:org:apache:httpd:log:AH10109:"
                     break
             time.sleep(0.1)
-        env.httpd_error_log.ignore_recent()
 
         # reconfigure to a working notification command and restart
         conf = MDConf(env)
@@ -294,4 +313,13 @@ class TestMessage:
         stat = env.get_md_status(domain)
         # this command should have failed and logged an error
         assert stat["renewal"]["last"]["problem"] == "challenge-setup-failure"
-
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10056"   # None of the offered challenge types
+            ],
+            matches = [
+                r'.*urn:org:apache:httpd:log:AH10109:.*',
+                r'.*problem\[challenge-setup-failure\].*'
+            ]
+        )

Modified: httpd/httpd/trunk/test/modules/md/test_920_status.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/md/test_920_status.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/md/test_920_status.py (original)
+++ httpd/httpd/trunk/test/modules/md/test_920_status.py Fri Jul  7 08:21:21 2023
@@ -243,3 +243,9 @@ Protocols h2 http/1.1 acme-tls/1
             assert ktype in stat['cert']
             if env.acme_server == 'boulder':
                 assert 'ocsp' in stat['cert'][ktype]
+        #
+        env.httpd_error_log.ignore_recent(
+            matches = [
+                r'.*certificate with serial \w+ has no OCSP responder URL.*'
+            ]
+        )

Modified: httpd/httpd/trunk/test/modules/proxy/conftest.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/proxy/conftest.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/proxy/conftest.py (original)
+++ httpd/httpd/trunk/test/modules/proxy/conftest.py Fri Jul  7 08:21:21 2023
@@ -29,23 +29,3 @@ def env(pytestconfig) -> ProxyTestEnv:
     env.apache_access_log_clear()
     env.httpd_error_log.clear_log()
     return env
-
-
-@pytest.fixture(autouse=True, scope="package")
-def _session_scope(env):
-    # we'd like to check the httpd error logs after the test suite has
-    # run to catch anything unusual. For this, we setup the ignore list
-    # of errors and warnings that we do expect.
-    env.httpd_error_log.set_ignored_lognos([
-        'AH01144',  # No protocol handler was valid for the URL
-    ])
-
-    env.httpd_error_log.add_ignored_patterns([
-        #re.compile(r'.*urn:ietf:params:acme:error:.*'),
-    ])
-    yield
-    assert env.apache_stop() == 0
-    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))

Modified: httpd/httpd/trunk/test/modules/proxy/env.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/proxy/env.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/proxy/env.py (original)
+++ httpd/httpd/trunk/test/modules/proxy/env.py Fri Jul  7 08:21:21 2023
@@ -1,7 +1,6 @@
 import inspect
 import logging
 import os
-import re
 import subprocess
 from typing import Dict, Any
 

Modified: httpd/httpd/trunk/test/modules/proxy/test_02_unix.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/proxy/test_02_unix.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/proxy/test_02_unix.py (original)
+++ httpd/httpd/trunk/test/modules/proxy/test_02_unix.py Fri Jul  7 08:21:21 2023
@@ -153,6 +153,12 @@ Host: {domain}
         r2 = self.parse_response(rlines)
         assert r2.response
         assert r2.response['status'] == exp_status
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH01144"   #  No protocol handler was valid for the URL
+            ]
+        )
 
     def parse_response(self, lines) -> ExecResult:
         exp_body = False

Modified: httpd/httpd/trunk/test/modules/tls/conftest.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/tls/conftest.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/tls/conftest.py (original)
+++ httpd/httpd/trunk/test/modules/tls/conftest.py Fri Jul  7 08:21:21 2023
@@ -31,9 +31,3 @@ def env(pytestconfig) -> TlsTestEnv:
     env.apache_access_log_clear()
     env.httpd_error_log.clear_log()
     return env
-
-
-@pytest.fixture(autouse=True, scope="package")
-def _session_scope(env):
-    yield
-    assert env.apache_stop() == 0

Modified: httpd/httpd/trunk/test/modules/tls/test_03_sni.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/tls/test_03_sni.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/tls/test_03_sni.py (original)
+++ httpd/httpd/trunk/test/modules/tls/test_03_sni.py Fri Jul  7 08:21:21 2023
@@ -34,6 +34,12 @@ class TestSni:
         domain_unknown = "unknown.test"
         r = env.tls_get(domain_unknown, "/index.json")
         assert r.exit_code != 0
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10353"   # cannot decrypt peer's message
+            ]
+        )
 
     def test_tls_03_sni_request_other_same_config(self, env):
         # do we see the first vhost response for another domain with different certs?
@@ -44,6 +50,12 @@ class TestSni:
         assert r.exit_code == 0
         assert r.json is None
         assert r.response['status'] == 421
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10345"   # Connection host selected via SNI and request have incompatible TLS configurations
+            ]
+        )
 
     def test_tls_03_sni_request_other_other_honor(self, env):
         # do we see the first vhost response for an unknown domain?
@@ -60,6 +72,12 @@ class TestSni:
         # request denied
         assert r.exit_code == 0
         assert r.json is None
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10345"   # Connection host selected via SNI and request have incompatible TLS configurations
+            ]
+        )
 
     @pytest.mark.skip('openssl behaviour changed on ventura, unreliable')
     def test_tls_03_sni_bad_hostname(self, env):

Modified: httpd/httpd/trunk/test/modules/tls/test_06_ciphers.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/tls/test_06_ciphers.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/tls/test_06_ciphers.py (original)
+++ httpd/httpd/trunk/test/modules/tls/test_06_ciphers.py Fri Jul  7 08:21:21 2023
@@ -176,16 +176,18 @@ class TestCiphers:
 
     def test_tls_06_ciphers_pref_unsupported(self, env):
         # a warning on preferring a known, but not supported cipher
-        env.httpd_error_log.ignore_recent()
         conf = TlsTestConf(env=env, extras={
             env.domain_b: "TLSCiphersPrefer TLS_NULL_WITH_NULL_NULL"
         })
         conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b])
         conf.install()
         assert env.apache_restart() == 0
-        (errors, warnings) = env.httpd_error_log.get_recent_count()
-        assert errors == 0
-        assert warnings == 2  # once on dry run, once on start
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH10319"   # Server has TLSCiphersPrefer configured that are not supported by rustls
+            ]
+        )
 
     def test_tls_06_ciphers_supp_unknown(self, env):
         conf = TlsTestConf(env=env, extras={
@@ -197,13 +199,9 @@ class TestCiphers:
 
     def test_tls_06_ciphers_supp_unsupported(self, env):
         # no warnings on suppressing known, but not supported ciphers
-        env.httpd_error_log.ignore_recent()
         conf = TlsTestConf(env=env, extras={
             env.domain_b: "TLSCiphersSuppress TLS_NULL_WITH_NULL_NULL"
         })
         conf.add_tls_vhosts(domains=[env.domain_a, env.domain_b])
         conf.install()
         assert env.apache_restart() == 0
-        (errors, warnings) = env.httpd_error_log.get_recent_count()
-        assert errors == 0
-        assert warnings == 0

Modified: httpd/httpd/trunk/test/modules/tls/test_14_proxy_ssl.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/tls/test_14_proxy_ssl.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/tls/test_14_proxy_ssl.py (original)
+++ httpd/httpd/trunk/test/modules/tls/test_14_proxy_ssl.py Fri Jul  7 08:21:21 2023
@@ -48,6 +48,13 @@ class TestProxySSL:
         # does not work, since SSLProxy* not configured
         data = env.tls_get_json(env.domain_b, "/proxy-local/index.json")
         assert data is None
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH01961",  # failed to enable ssl support [Hint: if using mod_ssl, see SSLProxyEngine]
+                "AH00961"   # failed to enable ssl support (mod_proxy)
+            ]
+        )
 
     def test_tls_14_proxy_ssl_h2_get(self, env):
         r = env.tls_get(env.domain_b, "/proxy-h2-ssl/index.json")

Modified: httpd/httpd/trunk/test/modules/tls/test_15_proxy_tls.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/modules/tls/test_15_proxy_tls.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/modules/tls/test_15_proxy_tls.py (original)
+++ httpd/httpd/trunk/test/modules/tls/test_15_proxy_tls.py Fri Jul  7 08:21:21 2023
@@ -1,4 +1,3 @@
-import re
 from datetime import timedelta
 
 import pytest
@@ -53,6 +52,13 @@ class TestProxyTLS:
         # does not work, since SSLProxy* not configured
         data = env.tls_get_json(env.domain_b, "/proxy-local/index.json")
         assert data is None
+        #
+        env.httpd_error_log.ignore_recent(
+            lognos = [
+                "AH01961",  # failed to enable ssl support [Hint: if using mod_ssl, see SSLProxyEngine]
+                "AH00961"   # failed to enable ssl support (mod_proxy)
+            ]
+        )
 
     def test_tls_15_proxy_tls_h2_get(self, env):
         r = env.tls_get(env.domain_b, "/proxy-h2-tls/index.json")

Modified: httpd/httpd/trunk/test/pyhttpd/env.py
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/test/pyhttpd/env.py?rev=1910844&r1=1910843&r2=1910844&view=diff
==============================================================================
--- httpd/httpd/trunk/test/pyhttpd/env.py (original)
+++ httpd/httpd/trunk/test/pyhttpd/env.py Fri Jul  7 08:21:21 2023
@@ -324,6 +324,12 @@ class HttpdTestEnv:
             for name in self._httpd_log_modules:
                 self._log_interesting += f" {name}:{log_level}"
 
+    def check_error_log(self):
+        errors, warnings = self._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))
+
     @property
     def curl(self) -> str:
         return self._curl
@@ -558,6 +564,7 @@ class HttpdTestEnv:
         return f"{scheme}://{hostname}.{self.http_tld}:{port}{path}"
 
     def install_test_conf(self, lines: List[str]):
+        self.apache_stop()
         with open(self._test_conf, 'w') as fd:
             fd.write('\n'.join(self._httpd_base_conf))
             fd.write('\n')