From 91facd7bb3bb366525b7cb41221f6359c5e936db Mon Sep 17 00:00:00 2001 From: Aritra Basu Date: Wed, 27 May 2026 20:35:44 -0400 Subject: [PATCH] tests/http: fix HTTP/3 proxy pytest failures with h2o Fix pytest failures in HTTP/3 proxy tests when h2o is not installed, misconfigured, or fails to start at runtime. This prevents: - FileNotFoundError when h2o document root does not exist - Fixture setup errors when h2o is configured but cannot start - Unused test data file creation when h2o is absent or broken - CI aborts on systems where h2o exists but is not runnable Bug: https://github.com/curl/curl/pull/21789#issuecomment-4559098879 Bug: https://github.com/curl/curl/pull/21789#issuecomment-4559161907 Follow-up to e78b1b3eccfa6a2e367a1225ea1b66dafcdac3c4 #21153 Closes #21791 --- tests/http/conftest.py | 8 ++++++-- tests/http/test_60_h3_proxy.py | 27 +++++++++++++++------------ tests/http/testenv/env.py | 1 + tests/http/testenv/h2o.py | 12 ++++++++---- 4 files changed, 30 insertions(+), 18 deletions(-) diff --git a/tests/http/conftest.py b/tests/http/conftest.py index 0de5c1a8b9..5275b91bf9 100644 --- a/tests/http/conftest.py +++ b/tests/http/conftest.py @@ -172,7 +172,9 @@ def h2o_server(env) -> Generator[Union[H2oServer, bool], None, None]: h2o = H2oServer(env=env) if env.have_h2o(): h2o.clear_logs() - assert h2o.initial_start() + if not h2o.initial_start(): + h2o_logs = "\n".join(h2o.dump_logs()) + pytest.skip(f"h2o server failed to start\n{h2o_logs}") yield h2o h2o.stop() else: @@ -184,7 +186,9 @@ def h2o_proxy(env) -> Generator[Union[H2oProxy, bool], None, None]: h2o = H2oProxy(env=env) if env.have_h2o(): h2o.clear_logs() - assert h2o.initial_start() + if not h2o.initial_start(): + h2o_logs = "\n".join(h2o.dump_logs()) + pytest.skip(f"h2o proxy failed to start\n{h2o_logs}") yield h2o h2o.stop() else: diff --git a/tests/http/test_60_h3_proxy.py b/tests/http/test_60_h3_proxy.py index def32a6fe7..786c6e7bf2 100644 --- a/tests/http/test_60_h3_proxy.py +++ b/tests/http/test_60_h3_proxy.py @@ -359,10 +359,11 @@ class TestH3ProxyRobustness: pytestmark = H3_PROXY_COMMON_MARKS + [MARK_NEEDS_H2O] @pytest.fixture(autouse=True, scope="class") - def _class_scope(self, env): - doc_root = os.path.join(env.gen_dir, "docs") + def _class_scope(self, env, h2o_server): + if not env.have_h2o(): + pytest.skip("h2o not available") env.make_data_file( - indir=doc_root, fname="proxy-drop-20m", fsize=20 * 1024 * 1024 + indir=h2o_server.docs_dir, fname="proxy-drop-20m", fsize=20 * 1024 * 1024 ) def test_60_05_graceful_shutdown( @@ -451,10 +452,11 @@ class TestH3ProxyDataTransfer: pytestmark = H3_PROXY_COMMON_MARKS + [MARK_NEEDS_H2O] @pytest.fixture(autouse=True, scope="class") - def _class_scope(self, env): - doc_root = os.path.join(env.gen_dir, "docs") - env.make_data_file(indir=doc_root, fname="download-1m", fsize=1 * 1024 * 1024) - env.make_data_file(indir=doc_root, fname="download-10m", fsize=10 * 1024 * 1024) + def _class_scope(self, env, h2o_server): + if not env.have_h2o(): + pytest.skip("h2o not available") + env.make_data_file(indir=h2o_server.docs_dir, fname="download-1m", fsize=1 * 1024 * 1024) + env.make_data_file(indir=h2o_server.docs_dir, fname="download-10m", fsize=10 * 1024 * 1024) env.make_data_file(indir=env.gen_dir, fname="upload-2m", fsize=2 * 1024 * 1024) def test_60_07_large_download(self, env: Env, h2o_server, h2o_proxy): @@ -558,11 +560,12 @@ class TestH3ProxyUdpTunnel: pytestmark = H3_PROXY_COMMON_MARKS @pytest.fixture(autouse=True, scope="class") - def _class_scope(self, env): - doc_root = os.path.join(env.gen_dir, "docs") - env.make_data_file(indir=doc_root, fname="download-1400", fsize=1400) - env.make_data_file(indir=doc_root, fname="download-1m", fsize=1 * 1024 * 1024) - env.make_data_file(indir=doc_root, fname="download-10m", fsize=10 * 1024 * 1024) + def _class_scope(self, env, h2o_server): + if not env.have_h2o(): + return + env.make_data_file(indir=h2o_server.docs_dir, fname="download-1400", fsize=1400) + env.make_data_file(indir=h2o_server.docs_dir, fname="download-1m", fsize=1 * 1024 * 1024) + env.make_data_file(indir=h2o_server.docs_dir, fname="download-10m", fsize=10 * 1024 * 1024) @MARK_NEEDS_H2O @pytest.mark.parametrize( diff --git a/tests/http/testenv/env.py b/tests/http/testenv/env.py index 3b43cfce0d..093092b4c5 100644 --- a/tests/http/testenv/env.py +++ b/tests/http/testenv/env.py @@ -909,6 +909,7 @@ class Env: ) -> str: if line_length < 11: raise RuntimeError("line_length less than 11 not supported") + os.makedirs(indir, exist_ok=True) fpath = os.path.join(indir, fname) s10 = "0123456789" s = round((line_length / 10) + 1) * s10 diff --git a/tests/http/testenv/h2o.py b/tests/http/testenv/h2o.py index 6a55f4882b..c67aaf1888 100644 --- a/tests/http/testenv/h2o.py +++ b/tests/http/testenv/h2o.py @@ -241,6 +241,11 @@ class H2oServer(H2o): super().__init__( env=env, name="h2o-server", domain=env.domain1, cred_name=env.domain1 ) + self._docs_dir = os.path.join(self.env.gen_dir, "docs") + + @property + def docs_dir(self): + return self._docs_dir def initial_start(self): super().initial_start() @@ -261,11 +266,10 @@ class H2oServer(H2o): def write_config(self): creds = self.env.get_credentials(self._cred_name) assert creds # convince pytype this is not None - doc_root = os.path.join(self.env.gen_dir, "docs") - self._mkpath(doc_root) + self._mkpath(self._docs_dir) self._mkpath(self._run_dir) # Create a simple test file - with open(os.path.join(doc_root, "data.json"), "w") as f: + with open(os.path.join(self._docs_dir, "data.json"), "w") as f: f.write('{"message": "Hello from h2o HTTP/3 server"}\n') with open(self._conf_file, "w") as fd: fd.write(f"""# h2o HTTP/3 server configuration @@ -289,7 +293,7 @@ hosts: "{self._domain}": paths: "/": - file.dir: {doc_root} + file.dir: {self._docs_dir} http2-reprioritize-blocking-assets: ON