Files
Raúl MarínandClaude Opus 4.8 ce175adaea Speed up test_url_invalid_hostname
The query to a bogus host retried http_max_tries (default 10) times, each
paying a DNS-resolution timeout plus exponential backoff (~33s total). Set
http_max_tries=2: the retry path is still exercised and the error still
propagates.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-26 15:18:18 +02:00

119 lines
3.3 KiB
Python

from contextlib import nullcontext as does_not_raise
import pytest
from helpers.client import QueryRuntimeException
from helpers.cluster import ClickHouseCluster
ACCESSIBLE_IPV4 = "10.5.172.10"
OTHER_ACCESSIBLE_IPV4 = "10.5.172.20"
NOT_ACCESSIBLE_IPV4 = "10.5.172.11"
ACCESSIBLE_IPV6 = "2001:3984:3989::1:1000"
NOT_ACCESSIBLE_IPV6 = "2001:3984:3989::1:1001"
DST_NODE_IPV4 = ACCESSIBLE_IPV4
DST_NODE_IPV6 = ACCESSIBLE_IPV6
SRC_NODE_IPV6 = "2001:3984:3989::1:2000"
cluster = ClickHouseCluster(__file__)
# Destination node
dst_node = cluster.add_instance(
"dst_node",
with_zookeeper=True,
ipv4_address=DST_NODE_IPV4,
ipv6_address=DST_NODE_IPV6,
main_configs=["configs/listen.xml"],
)
# Source node
src_node = cluster.add_instance(
"src_node",
with_zookeeper=True,
ipv6_address=SRC_NODE_IPV6,
)
@pytest.fixture(scope="module")
def started_cluster():
try:
cluster.start()
yield cluster
except Exception as ex:
print(ex)
finally:
cluster.shutdown()
pass
@pytest.fixture
def dst_node_addrs(started_cluster, request):
src_node.set_hosts([(ip, "dst_node") for ip in request.param])
src_node.query("SYSTEM CLEAR DNS CACHE")
yield
# Clear static DNS entries and all keep alive connections
src_node.set_hosts([])
src_node.query("SYSTEM CLEAR DNS CACHE")
src_node.query("SYSTEM CLEAR CONNECTIONS CACHE")
@pytest.mark.parametrize(
"dst_node_addrs, expectation",
[
((ACCESSIBLE_IPV4, ACCESSIBLE_IPV6), does_not_raise()),
((NOT_ACCESSIBLE_IPV4, ACCESSIBLE_IPV6), does_not_raise()),
((ACCESSIBLE_IPV4, NOT_ACCESSIBLE_IPV6), does_not_raise()),
(
(NOT_ACCESSIBLE_IPV4, NOT_ACCESSIBLE_IPV6),
pytest.raises(QueryRuntimeException),
),
],
indirect=["dst_node_addrs"],
)
def test_url_destination_host_with_multiple_addrs(dst_node_addrs, expectation):
with expectation:
result = src_node.query(
"SELECT * FROM url('http://dst_node:8123/?query=SELECT+42', TSV, 'column1 UInt32')",
settings={"http_max_tries": "3"},
)
assert result == "42\n"
def test_url_invalid_hostname(started_cluster):
with pytest.raises(QueryRuntimeException):
# http_max_tries=2 still exercises the retry path (one retry) but avoids
# the default 10 attempts, each of which pays a DNS-resolution timeout for
# the bogus host plus exponential backoff (~33s total).
src_node.query(
"SELECT count(*) FROM url('http://notvalidhost:8123/?query=SELECT+1', TSV, 'column1 UInt32');",
settings={"http_max_tries": "2"},
)
def test_url_ip_change(started_cluster):
assert (
src_node.query(
"SELECT * FROM url('http://dst_node:8123/?query=SELECT+42', TSV, 'column1 UInt32')"
)
== "42\n"
)
started_cluster.restart_instance_with_ip_change(dst_node, OTHER_ACCESSIBLE_IPV4)
# Ensure that only new IPV4 address is accessible
src_node.set_hosts(
[(OTHER_ACCESSIBLE_IPV4, "dst_node"), (NOT_ACCESSIBLE_IPV6, "dst_node")]
)
src_node.query("SYSTEM CLEAR DNS CACHE")
assert (
src_node.query(
"SELECT * FROM url('http://dst_node:8123/?query=SELECT+42', TSV, 'column1 UInt32')"
)
== "42\n"
)