Skip to content

Commit fafd420

Browse files
committed
test: add quick_timing fixture and apply to register-heavy tests
Recent bump of _CHECK_TIME from 175ms to 500ms (made for RFC 6762 interop on slow WiFi / IoT networks) inflated every test that does real probe/announce/unregister by ~1-2s. The production constants are not needed for loopback tests — services register and answer themselves over 127.0.0.1 with no contention. Add an opt-in `quick_timing` fixture in tests/conftest.py that patches `_core._CHECK_TIME`, `_core._REGISTER_TIME`, and `_core._UNREGISTER_TIME` to 10ms each. Patching at the `_core` module is required because these constants are pulled in via `from .const import ...` at module load time, so patching `const.*` does not affect the binding `_core` already holds. Apply to seven of the worst-offending register-heavy tests, also passing explicit `timeout=200` to the post-unregister `async_get_service_info` calls and the patched-_is_complete `async_request` call so they don't pay the default 3000ms. Combined wall time across the seven tests drops from ~46s to ~7.5s: test_shutdown_while_register_in_process 10.69s -> 0.40s test_service_info_async_request 9.82s -> 0.7s test_async_zeroconf_service_types 6.16s -> 4.3s test_async_unregister_all_services 5.99s -> 0.52s test_async_service_registration_same_server_same_ports 3.23s -> ~0.2s test_async_service_registration_same_server_different_ports 3.18s -> ~0.2s test_async_service_registration_name_strict_check 2.99s -> ~0.2s The fixture is opt-in (not autouse) because a handful of tests under tests/test_handlers.py (`test_response_aggregation_timings`, `test_response_aggregation_timings_multiple`) assert against the production timing constants and must not be patched.
1 parent 72a0152 commit fafd420

3 files changed

Lines changed: 30 additions & 11 deletions

File tree

tests/conftest.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import annotations
44

55
import threading
6+
from collections.abc import Generator
67
from unittest.mock import patch
78

89
import pytest
@@ -40,3 +41,21 @@ def disable_duplicate_packet_suppression():
4041
"""
4142
with patch.object(const, "_DUPLICATE_PACKET_SUPPRESSION_INTERVAL", 0):
4243
yield
44+
45+
46+
@pytest.fixture
47+
def quick_timing() -> Generator[None]:
48+
"""Shorten the probe/announce/goodbye intervals for tests on loopback.
49+
50+
The production values (_CHECK_TIME=500ms, _REGISTER_TIME=225ms,
51+
_UNREGISTER_TIME=125ms) exist for RFC 6762 interop on real
52+
networks. Tests on 127.0.0.1 do not need them and pay 1-2s per
53+
register/unregister cycle without this fixture. Opt in by adding
54+
`quick_timing` to a test's argument list.
55+
"""
56+
with (
57+
patch.object(_core, "_CHECK_TIME", 10),
58+
patch.object(_core, "_REGISTER_TIME", 10),
59+
patch.object(_core, "_UNREGISTER_TIME", 10),
60+
):
61+
yield

tests/test_asyncio.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ def update_service(self, zeroconf: Zeroconf, type: str, name: str) -> None:
260260

261261

262262
@pytest.mark.asyncio
263-
async def test_async_service_registration_same_server_different_ports() -> None:
263+
async def test_async_service_registration_same_server_different_ports(quick_timing: None) -> None:
264264
"""Test registering services with the same server with different srv records."""
265265
aiozc = AsyncZeroconf(interfaces=["127.0.0.1"])
266266
type_ = "_test1-srvc-type._tcp.local."
@@ -327,7 +327,7 @@ def update_service(self, zeroconf: Zeroconf, type: str, name: str) -> None:
327327

328328

329329
@pytest.mark.asyncio
330-
async def test_async_service_registration_same_server_same_ports() -> None:
330+
async def test_async_service_registration_same_server_same_ports(quick_timing: None) -> None:
331331
"""Test registering services with the same server with the exact same srv record."""
332332
aiozc = AsyncZeroconf(interfaces=["127.0.0.1"])
333333
type_ = "_test1-srvc-type._tcp.local."
@@ -468,7 +468,7 @@ async def test_async_service_registration_name_does_not_match_type() -> None:
468468

469469

470470
@pytest.mark.asyncio
471-
async def test_async_service_registration_name_strict_check() -> None:
471+
async def test_async_service_registration_name_strict_check(quick_timing: None) -> None:
472472
"""Test registering services throws when the name does not comply."""
473473
zc = Zeroconf(interfaces=["127.0.0.1"])
474474
aiozc = AsyncZeroconf(interfaces=["127.0.0.1"])
@@ -605,7 +605,7 @@ async def test_async_wait_unblocks_on_update() -> None:
605605

606606

607607
@pytest.mark.asyncio
608-
async def test_service_info_async_request() -> None:
608+
async def test_service_info_async_request(quick_timing: None) -> None:
609609
"""Test registering services broadcasts and query with AsyncServceInfo.async_request."""
610610
if not has_working_ipv6() or os.environ.get("SKIP_IPV6"):
611611
pytest.skip("Requires IPv6")
@@ -700,14 +700,14 @@ async def test_service_info_async_request() -> None:
700700
# Generating the race condition is almost impossible
701701
# without patching since its a TOCTOU race
702702
with patch("zeroconf.asyncio.AsyncServiceInfo._is_complete", False):
703-
await aiosinfo.async_request(aiozc.zeroconf, 3000)
703+
await aiosinfo.async_request(aiozc.zeroconf, 200)
704704
assert aiosinfo is not None
705705
assert aiosinfo.addresses == [socket.inet_aton("10.0.1.3")]
706706

707707
task = await aiozc.async_unregister_service(new_info)
708708
await task
709709

710-
aiosinfo = await aiozc.async_get_service_info(type_, registration_name)
710+
aiosinfo = await aiozc.async_get_service_info(type_, registration_name, timeout=200)
711711
assert aiosinfo is None
712712

713713
await aiozc.async_close()
@@ -824,7 +824,7 @@ class MyServiceListener(ServiceListener):
824824

825825

826826
@pytest.mark.asyncio
827-
async def test_async_unregister_all_services() -> None:
827+
async def test_async_unregister_all_services(quick_timing: None) -> None:
828828
"""Test unregistering all services."""
829829
aiozc = AsyncZeroconf(interfaces=["127.0.0.1"])
830830
type_ = "_test1-srvc-type._tcp.local."
@@ -870,8 +870,8 @@ async def test_async_unregister_all_services() -> None:
870870
_clear_cache(aiozc.zeroconf)
871871

872872
tasks = []
873-
tasks.append(aiozc.async_get_service_info(type_, registration_name))
874-
tasks.append(aiozc.async_get_service_info(type_, registration_name2))
873+
tasks.append(aiozc.async_get_service_info(type_, registration_name, timeout=200))
874+
tasks.append(aiozc.async_get_service_info(type_, registration_name2, timeout=200))
875875
results = await asyncio.gather(*tasks)
876876
assert results[0] is None
877877
assert results[1] is None
@@ -883,7 +883,7 @@ async def test_async_unregister_all_services() -> None:
883883

884884

885885
@pytest.mark.asyncio
886-
async def test_async_zeroconf_service_types():
886+
async def test_async_zeroconf_service_types(quick_timing: None) -> None:
887887
type_ = "_test-srvc-type._tcp.local."
888888
name = "xxxyyy"
889889
registration_name = f"{name}.{type_}"

tests/test_core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,7 @@ async def test_multiple_sync_instances_stared_from_async_close():
721721
await asyncio.sleep(0)
722722

723723

724-
def test_shutdown_while_register_in_process():
724+
def test_shutdown_while_register_in_process(quick_timing: None) -> None:
725725
"""Test we can shutdown while registering a service in another thread."""
726726

727727
# instantiate a zeroconf instance

0 commit comments

Comments
 (0)