From d371288de73465efb1b26958150d04f8adfe6fd2 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 9 Dec 2025 17:00:52 +0100 Subject: [PATCH] test: increase altsvc test reliability Move new tests from test_12 to test_06 (eyeballing) where they better fit. Increase reliability by check Alt-Svc redirects from h3 to a lower version for a port where no h3 is available. Closes #19903 --- tests/http/test_06_eyeballs.py | 66 +++++++++++++++++++++ tests/http/test_12_reuse.py | 104 --------------------------------- 2 files changed, 66 insertions(+), 104 deletions(-) diff --git a/tests/http/test_06_eyeballs.py b/tests/http/test_06_eyeballs.py index 3b374e8158..6129ab5f17 100644 --- a/tests/http/test_06_eyeballs.py +++ b/tests/http/test_06_eyeballs.py @@ -149,3 +149,69 @@ class TestEyeballs: r.check_exit_code(0) r.check_response(count=1, http_status=200) assert r.stats[0]['http_version'] == '2' + + @pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported") + def test_06_21_as_follow_h3h1(self, env: Env, httpd, configures_httpd, nghttpx): + # With '--http3` an Alt-Svc redirection from h3 to h1 is allowed + # write an alt-svc file the advises h1 instead of h3 + curl = CurlClient(env=env) + asfile = curl.mk_altsvc_file('test_12', + 'h3', env.domain1, env.https_only_tcp_port, + 'http/1.1', env.domain1, env.https_only_tcp_port) + urln = f'https://{env.domain1}:{env.https_only_tcp_port}/data.json' + r = curl.http_download(urls=[urln], with_stats=True, extra_args=[ + '--alt-svc', f'{asfile}', '--http3' + ]) + r.check_response(count=1, http_status=200) + # We expect the connection to be preferring HTTP/1.1 in the ALPN + assert r.total_connects == 1, f'{r.dump_logs()}' + re_m = re.compile(r'.* ALPN: curl offers http/1.1,h2') + lines = [line for line in r.trace_lines if re_m.match(line)] + assert len(lines), f'{r.dump_logs()}' + + @pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported") + def test_06_22_as_ignore_h3h1(self, env: Env, httpd, configures_httpd, nghttpx): + # With '--http3-only` an Alt-Svc redirection from h3 to h1 is ignored + # write an alt-svc file the advises h1 instead of h3 + curl = CurlClient(env=env) + asfile = curl.mk_altsvc_file('test_12', + 'h3', env.domain1, env.https_port, + 'http/1.1', env.domain1, env.https_port) + urln = f'https://{env.authority_for(env.domain1, "h3")}/data.json' + r = curl.http_download(urls=[urln], with_stats=True, extra_args=[ + '--alt-svc', f'{asfile}', '--http3-only' + ]) + r.check_response(count=1, http_status=200) + # We expect the connection to be stay on h3, since we used --http3-only + assert r.total_connects == 1 + assert r.stats[0]['http_version'] == '3', f'{r.stats}' + + @pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported") + def test_06_23_as_ignore_h2h3(self, env: Env, httpd, configures_httpd, nghttpx): + # With '--http2` an Alt-Svc redirection from h2 to h3 is ignored + # write an alt-svc file that advises h3 instead of h2 + curl = CurlClient(env=env) + asfile = curl.mk_altsvc_file('test_12', + 'h2', env.domain1, env.https_port, + 'h3', env.domain1, env.h3_port) + urln = f'https://{env.authority_for(env.domain1, "h2")}/data.json' + r = curl.http_download(urls=[urln], with_stats=True, extra_args=[ + '--alt-svc', f'{asfile}', '--http2' + ]) + r.check_response(count=1, http_status=200) + assert r.stats[0]['http_version'] == '2', f'{r.stats}' + + # download using HTTP/3 on available server with alt-svc to h2, use h2 + @pytest.mark.skipif(condition=not Env.have_h3(), reason="missing HTTP/3 support") + def test_06_24_h3_altsvc_h2_used(self, env: Env, httpd, nghttpx): + curl = CurlClient(env=env) + urln = f'https://{env.domain1}:{env.https_only_tcp_port}/data.json' + altsvc_file = curl.mk_altsvc_file('test_12', + 'h3', env.domain1, env.https_only_tcp_port, + 'h2', env.domain1, env.https_only_tcp_port) + r = curl.http_download(urls=[urln], extra_args=[ + '--http3', '--alt-svc', altsvc_file + ]) + r.check_exit_code(0) + r.check_response(count=1, http_status=200) + assert r.stats[0]['http_version'] == '2' diff --git a/tests/http/test_12_reuse.py b/tests/http/test_12_reuse.py index 522df92708..6f267d9862 100644 --- a/tests/http/test_12_reuse.py +++ b/tests/http/test_12_reuse.py @@ -25,9 +25,6 @@ ########################################################################### # import logging -import os -import re -from datetime import datetime, timedelta import pytest from testenv import Env, CurlClient @@ -75,104 +72,3 @@ class TestReuse: r.check_response(count=count, http_status=200) # Connections time out on server before we send another request, assert r.total_connects == count - - @pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported") - def test_12_03_as_follow_h2h3(self, env: Env, httpd, configures_httpd, nghttpx): - curl = CurlClient(env=env) - # write an alt-svc file that advises h3 instead of h2 - asfile = curl.mk_altsvc_file('test_12', - 'h2', env.domain1, env.https_port, - 'h3', env.domain1, env.h3_port) - urln = f'https://{env.authority_for(env.domain1, "h2")}/data.json' - r = curl.http_download(urls=[urln], with_stats=True, extra_args=[ - '--alt-svc', f'{asfile}', - ]) - r.check_response(count=1, http_status=200) - assert r.stats[0]['http_version'] == '3', f'{r.stats}' - - @pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported") - def test_12_04_as_follow_h3h2(self, env: Env, httpd, configures_httpd, nghttpx): - count = 2 - # write an alt-svc file the advises h2 instead of h3 - asfile = os.path.join(env.gen_dir, 'alt-svc-12_04.txt') - ts = datetime.now() + timedelta(hours=24) - expires = f'{ts.year:04}{ts.month:02}{ts.day:02} {ts.hour:02}:{ts.minute:02}:{ts.second:02}' - with open(asfile, 'w') as fd: - fd.write(f'h3 {env.domain1} {env.https_port} h2 {env.domain1} {env.https_port} "{expires}" 0 0') - log.info(f'altscv: {open(asfile).readlines()}') - curl = CurlClient(env=env) - urln = f'https://{env.authority_for(env.domain1, "h3")}/data.json?[0-{count-1}]' - r = curl.http_download(urls=[urln], with_stats=True, extra_args=[ - '--alt-svc', f'{asfile}', '--http3' - ]) - r.check_response(count=count, http_status=200) - # We expect the connection to be reused and use HTTP/2 - assert r.total_connects == 1 - for s in r.stats: - assert s['http_version'] == '2', f'{s}' - - @pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported") - def test_12_05_as_follow_h3h1(self, env: Env, httpd, configures_httpd, nghttpx): - # With '--http3` an Alt-Svc redirection from h3 to h1 is allowed - # write an alt-svc file the advises h1 instead of h3 - curl = CurlClient(env=env) - asfile = curl.mk_altsvc_file('test_12', - 'h3', env.domain1, env.https_port, - 'http/1.1', env.domain1, env.https_port) - urln = f'https://{env.authority_for(env.domain1, "h3")}/data.json' - r = curl.http_download(urls=[urln], with_stats=True, extra_args=[ - '--alt-svc', f'{asfile}', '--http3' - ]) - r.check_response(count=1, http_status=200) - # We expect the connection to be preferring HTTP/1.1 in the ALPN - assert r.total_connects == 1 - re_m = re.compile(r'.* ALPN: curl offers http/1.1,h2') - lines = [line for line in r.trace_lines if re_m.match(line)] - assert len(lines), f'{r.dump_logs()}' - - @pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported") - def test_12_06_as_ignore_h3h1(self, env: Env, httpd, configures_httpd, nghttpx): - # With '--http3-only` an Alt-Svc redirection from h3 to h1 is ignored - # write an alt-svc file the advises h1 instead of h3 - curl = CurlClient(env=env) - asfile = curl.mk_altsvc_file('test_12', - 'h3', env.domain1, env.https_port, - 'http/1.1', env.domain1, env.https_port) - urln = f'https://{env.authority_for(env.domain1, "h3")}/data.json' - r = curl.http_download(urls=[urln], with_stats=True, extra_args=[ - '--alt-svc', f'{asfile}', '--http3-only' - ]) - r.check_response(count=1, http_status=200) - # We expect the connection to be stay on h3, since we used --http3-only - assert r.total_connects == 1 - assert r.stats[0]['http_version'] == '3', f'{r.stats}' - - @pytest.mark.skipif(condition=not Env.have_h3(), reason="h3 not supported") - def test_12_07_as_ignore_h2h3(self, env: Env, httpd, configures_httpd, nghttpx): - # With '--http2` an Alt-Svc redirection from h2 to h3 is ignored - # write an alt-svc file that advises h3 instead of h2 - curl = CurlClient(env=env) - asfile = curl.mk_altsvc_file('test_12', - 'h2', env.domain1, env.https_port, - 'h3', env.domain1, env.h3_port) - urln = f'https://{env.authority_for(env.domain1, "h2")}/data.json' - r = curl.http_download(urls=[urln], with_stats=True, extra_args=[ - '--alt-svc', f'{asfile}', '--http2' - ]) - r.check_response(count=1, http_status=200) - assert r.stats[0]['http_version'] == '2', f'{r.stats}' - - # download using HTTP/3 on available server with alt-svc to h2, use h2 - @pytest.mark.skipif(condition=not Env.have_h3(), reason="missing HTTP/3 support") - def test_12_08_h3_altsvc_h2_used(self, env: Env, httpd, nghttpx): - curl = CurlClient(env=env) - urln = f'https://{env.domain1}:{env.https_port}/data.json' - altsvc_file = curl.mk_altsvc_file('test_12', - 'h3', env.domain1, env.https_port, - 'h2', env.domain1, env.https_port) - r = curl.http_download(urls=[urln], extra_args=[ - '--http3', '--alt-svc', altsvc_file - ]) - r.check_exit_code(0) - r.check_response(count=1, http_status=200) - assert r.stats[0]['http_version'] == '2' -- 2.47.3