diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a38eaca6..5d03fcde 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -40,7 +40,7 @@ repos: - id: pyupgrade args: [--py39-plus] - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.1.0 + rev: v0.11.0 hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] diff --git a/build_ext.py b/build_ext.py index 7faa607f..ff088f83 100644 --- a/build_ext.py +++ b/build_ext.py @@ -53,7 +53,7 @@ def build_extensions(self) -> None: def build(setup_kwargs: Any) -> None: - if os.environ.get("SKIP_CYTHON", False): + if os.environ.get("SKIP_CYTHON"): return try: from Cython.Build import cythonize diff --git a/src/zeroconf/_services/browser.py b/src/zeroconf/_services/browser.py index 6bf3f0f4..ab8c050d 100644 --- a/src/zeroconf/_services/browser.py +++ b/src/zeroconf/_services/browser.py @@ -278,7 +278,7 @@ def generate_service_query( if not qu_question and question_history.suppresses(question, now_millis, known_answers): log.debug("Asking %s was suppressed by the question history", question) continue - if TYPE_CHECKING: # noqa: SIM108 + if TYPE_CHECKING: pointer_known_answers = cast(set[DNSPointer], known_answers) else: pointer_known_answers = known_answers diff --git a/tests/__init__.py b/tests/__init__.py index 3df09819..a70cca60 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -29,6 +29,7 @@ from unittest import mock import ifaddr + from zeroconf import DNSIncoming, DNSQuestion, DNSRecord, Zeroconf from zeroconf._history import QuestionHistory diff --git a/tests/benchmarks/test_cache.py b/tests/benchmarks/test_cache.py index e32abda0..7813f679 100644 --- a/tests/benchmarks/test_cache.py +++ b/tests/benchmarks/test_cache.py @@ -1,6 +1,7 @@ from __future__ import annotations from pytest_codspeed import BenchmarkFixture + from zeroconf import DNSCache, DNSPointer, current_time_millis from zeroconf.const import _CLASS_IN, _TYPE_PTR diff --git a/tests/benchmarks/test_incoming.py b/tests/benchmarks/test_incoming.py index 672e5c78..6d31e51e 100644 --- a/tests/benchmarks/test_incoming.py +++ b/tests/benchmarks/test_incoming.py @@ -5,6 +5,7 @@ import socket from pytest_codspeed import BenchmarkFixture + from zeroconf import ( DNSAddress, DNSIncoming, diff --git a/tests/benchmarks/test_outgoing.py b/tests/benchmarks/test_outgoing.py index cc2f3f42..a8db4d6f 100644 --- a/tests/benchmarks/test_outgoing.py +++ b/tests/benchmarks/test_outgoing.py @@ -3,6 +3,7 @@ from __future__ import annotations from pytest_codspeed import BenchmarkFixture + from zeroconf._protocol.outgoing import State from .helpers import generate_packets diff --git a/tests/benchmarks/test_send.py b/tests/benchmarks/test_send.py index d931b48b..596662a2 100644 --- a/tests/benchmarks/test_send.py +++ b/tests/benchmarks/test_send.py @@ -4,12 +4,13 @@ import pytest from pytest_codspeed import BenchmarkFixture + from zeroconf.asyncio import AsyncZeroconf from .helpers import generate_packets -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_sending_packets(benchmark: BenchmarkFixture) -> None: """Benchmark sending packets.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) diff --git a/tests/benchmarks/test_txt_properties.py b/tests/benchmarks/test_txt_properties.py index b7b0e767..72afa0b6 100644 --- a/tests/benchmarks/test_txt_properties.py +++ b/tests/benchmarks/test_txt_properties.py @@ -1,6 +1,7 @@ from __future__ import annotations from pytest_codspeed import BenchmarkFixture + from zeroconf import ServiceInfo info = ServiceInfo( diff --git a/tests/conftest.py b/tests/conftest.py index 3d891ec4..531c810b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -6,6 +6,7 @@ from unittest.mock import patch import pytest + from zeroconf import _core, const from zeroconf._handlers import query_handler @@ -19,7 +20,7 @@ def verify_threads_ended(): assert not threads -@pytest.fixture() +@pytest.fixture def run_isolated(): """Change the mDNS port to run the test in isolation.""" with ( @@ -30,7 +31,7 @@ def run_isolated(): yield -@pytest.fixture() +@pytest.fixture def disable_duplicate_packet_suppression(): """Disable duplicate packet suppress. diff --git a/tests/services/test_browser.py b/tests/services/test_browser.py index f5237365..d57568f4 100644 --- a/tests/services/test_browser.py +++ b/tests/services/test_browser.py @@ -14,6 +14,7 @@ from unittest.mock import patch import pytest + import zeroconf as r import zeroconf._services.browser as _services_browser from zeroconf import ( @@ -555,7 +556,7 @@ def on_service_state_change(zeroconf, service_type, state_change, name): zeroconf_browser.close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_asking_default_is_asking_qm_questions_after_the_first_qu(): """Verify the service browser's first questions are QU and refresh queries are QM.""" service_added = asyncio.Event() @@ -657,7 +658,7 @@ def send(out, addr=const._MDNS_ADDR, port=const._MDNS_PORT, v6_flow_scope=()): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_ttl_refresh_cancelled_rescue_query(): """Verify seeing a name again cancels the rescue query.""" service_added = asyncio.Event() @@ -767,7 +768,7 @@ def send(out, addr=const._MDNS_ADDR, port=const._MDNS_PORT, v6_flow_scope=()): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_asking_qm_questions(): """Verify explicitly asking QM questions.""" type_ = "_quservice._tcp.local." @@ -806,7 +807,7 @@ def on_service_state_change(zeroconf, service_type, state_change, name): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_asking_qu_questions(): """Verify the service browser can ask QU questions.""" type_ = "_quservice._tcp.local." @@ -898,7 +899,7 @@ def on_service_state_change(zeroconf, service_type, state_change, name): browser.cancel() - assert len(updates) + assert updates assert len([isinstance(update, r.DNSPointer) and update.name == type_ for update in updates]) >= 1 zc.remove_listener(listener) @@ -1138,7 +1139,7 @@ def test_group_ptr_queries_with_known_answers(): # This test uses asyncio because it needs to access the cache directly # which is not threadsafe -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_generate_service_query_suppress_duplicate_questions(): """Generate a service query for sending with zeroconf.send.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -1191,7 +1192,7 @@ async def test_generate_service_query_suppress_duplicate_questions(): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_query_scheduler(): delay = const._BROWSER_TIME types_ = {"_hap._tcp.local.", "_http._tcp.local."} @@ -1284,7 +1285,7 @@ def send(out, addr=const._MDNS_ADDR, port=const._MDNS_PORT, v6_flow_scope=()): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_query_scheduler_rescue_records(): delay = const._BROWSER_TIME types_ = {"_hap._tcp.local.", "_http._tcp.local."} @@ -1579,7 +1580,7 @@ def test_scheduled_ptr_query_dunder_methods(): assert query75 >= other # type: ignore[operator] -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_close_zeroconf_without_browser_before_start_up_queries(): """Test that we stop sending startup queries if zeroconf is closed out from under the browser.""" service_added = asyncio.Event() @@ -1647,7 +1648,7 @@ def send(out, addr=const._MDNS_ADDR, port=const._MDNS_PORT, v6_flow_scope=()): await browser.async_cancel() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_close_zeroconf_without_browser_after_start_up_queries(): """Test that we stop sending rescue queries if zeroconf is closed out from under the browser.""" service_added = asyncio.Event() diff --git a/tests/services/test_info.py b/tests/services/test_info.py index 8b912bea..3d4c5302 100644 --- a/tests/services/test_info.py +++ b/tests/services/test_info.py @@ -14,6 +14,7 @@ from unittest.mock import patch import pytest + import zeroconf as r from zeroconf import DNSAddress, RecordUpdate, const from zeroconf._services import info @@ -827,7 +828,7 @@ def test_scoped_addresses_from_cache(): # This test uses asyncio because it needs to access the cache directly # which is not threadsafe -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_multiple_a_addresses_newest_address_first(): """Test that info.addresses returns the newest seen address first.""" type_ = "_http._tcp.local." @@ -847,7 +848,7 @@ async def test_multiple_a_addresses_newest_address_first(): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_invalid_a_addresses(caplog): type_ = "_http._tcp.local." registration_name = f"multiarec.{type_}" @@ -1056,7 +1057,7 @@ def test_request_timeout(): assert (end_time - start_time) < 3000 + 1000 -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_we_try_four_times_with_random_delay(): """Verify we try four times even with the random delay.""" type_ = "_typethatisnothere._tcp.local." @@ -1079,7 +1080,7 @@ def async_send(out, addr=const._MDNS_ADDR, port=const._MDNS_PORT): assert request_count == 4 -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_release_wait_when_new_recorded_added(): """Test that async_request returns as soon as new matching records are added to the cache.""" type_ = "_http._tcp.local." @@ -1144,7 +1145,7 @@ async def test_release_wait_when_new_recorded_added(): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_port_changes_are_seen(): """Test that port changes are seen by async_request.""" type_ = "_http._tcp.local." @@ -1227,7 +1228,7 @@ async def test_port_changes_are_seen(): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_port_changes_are_seen_with_directed_request(): """Test that port changes are seen by async_request with a directed request.""" type_ = "_http._tcp.local." @@ -1310,7 +1311,7 @@ async def test_port_changes_are_seen_with_directed_request(): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_ipv4_changes_are_seen(): """Test that ipv4 changes are seen by async_request.""" type_ = "_http._tcp.local." @@ -1398,7 +1399,7 @@ async def test_ipv4_changes_are_seen(): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_ipv6_changes_are_seen(): """Test that ipv6 changes are seen by async_request.""" type_ = "_http._tcp.local." @@ -1493,7 +1494,7 @@ async def test_ipv6_changes_are_seen(): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_bad_ip_addresses_ignored_in_cache(): """Test that bad ip address in the cache are ignored async_request.""" type_ = "_http._tcp.local." @@ -1547,7 +1548,7 @@ async def test_bad_ip_addresses_ignored_in_cache(): assert info.addresses_by_version(IPVersion.V4Only) == [b"\x7f\x00\x00\x01"] -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_service_name_change_as_seen_has_ip_in_cache(): """Test that service name changes are seen by async_request when the ip is in the cache.""" type_ = "_http._tcp.local." @@ -1629,7 +1630,7 @@ async def test_service_name_change_as_seen_has_ip_in_cache(): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_service_name_change_as_seen_ip_not_in_cache(): """Test that service name changes are seen by async_request when the ip is not in the cache.""" type_ = "_http._tcp.local." @@ -1711,7 +1712,7 @@ async def test_service_name_change_as_seen_ip_not_in_cache(): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio @patch.object(info, "_LISTENER_TIME", 10000000) async def test_release_wait_when_new_recorded_added_concurrency(): """Test that concurrent async_request returns as soon as new matching records are added to the cache.""" @@ -1783,7 +1784,7 @@ async def test_release_wait_when_new_recorded_added_concurrency(): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_service_info_nsec_records(): """Test we can generate nsec records from ServiceInfo.""" type_ = "_http._tcp.local." @@ -1798,7 +1799,7 @@ async def test_service_info_nsec_records(): assert nsec_record.rdtypes == [const._TYPE_A, const._TYPE_AAAA] -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_address_resolver(): """Test that the address resolver works.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -1822,7 +1823,7 @@ async def test_address_resolver(): assert resolver.addresses == [b"\x7f\x00\x00\x01"] -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_address_resolver_ipv4(): """Test that the IPv4 address resolver works.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -1846,7 +1847,7 @@ async def test_address_resolver_ipv4(): assert resolver.addresses == [b"\x7f\x00\x00\x01"] -@pytest.mark.asyncio() +@pytest.mark.asyncio @unittest.skipIf(not has_working_ipv6(), "Requires IPv6") @unittest.skipIf(os.environ.get("SKIP_IPV6"), "IPv6 tests disabled") async def test_address_resolver_ipv6(): diff --git a/tests/test_asyncio.py b/tests/test_asyncio.py index e3102507..40ecf816 100644 --- a/tests/test_asyncio.py +++ b/tests/test_asyncio.py @@ -11,6 +11,7 @@ from unittest.mock import ANY, call, patch import pytest + import zeroconf._services.browser as _services_browser from zeroconf import ( DNSAddress, @@ -78,14 +79,14 @@ def verify_threads_ended(): assert not threads -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_basic_usage() -> None: """Test we can create and close the instance.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_close_twice() -> None: """Test we can close twice.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -93,7 +94,7 @@ async def test_async_close_twice() -> None: await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_with_sync_passed_in() -> None: """Test we can create and close the instance when passing in a sync Zeroconf.""" zc = Zeroconf(interfaces=["127.0.0.1"]) @@ -102,7 +103,7 @@ async def test_async_with_sync_passed_in() -> None: await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_with_sync_passed_in_closed_in_async() -> None: """Test caller closes the sync version in async.""" zc = Zeroconf(interfaces=["127.0.0.1"]) @@ -112,7 +113,7 @@ async def test_async_with_sync_passed_in_closed_in_async() -> None: await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_sync_within_event_loop_executor() -> None: """Test sync version still works from an executor within an event loop.""" @@ -124,7 +125,7 @@ def sync_code(): await asyncio.get_event_loop().run_in_executor(None, sync_code) -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_service_registration() -> None: """Test registering services broadcasts the registration by default.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -191,7 +192,7 @@ def update_service(self, zeroconf: Zeroconf, type: str, name: str) -> None: ] -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_service_registration_with_server_missing() -> None: """Test registering a service with the server not specified. @@ -258,7 +259,7 @@ def update_service(self, zeroconf: Zeroconf, type: str, name: str) -> None: ] -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_service_registration_same_server_different_ports() -> None: """Test registering services with the same server with different srv records.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -325,7 +326,7 @@ def update_service(self, zeroconf: Zeroconf, type: str, name: str) -> None: ] -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_service_registration_same_server_same_ports() -> None: """Test registering services with the same server with the exact same srv record.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -392,7 +393,7 @@ def update_service(self, zeroconf: Zeroconf, type: str, name: str) -> None: ] -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_service_registration_name_conflict() -> None: """Test registering services throws on name conflict.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -440,7 +441,7 @@ async def test_async_service_registration_name_conflict() -> None: await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_service_registration_name_does_not_match_type() -> None: """Test registering services throws when the name does not match the type.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -466,7 +467,7 @@ async def test_async_service_registration_name_does_not_match_type() -> None: await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_service_registration_name_strict_check() -> None: """Test registering services throws when the name does not comply.""" zc = Zeroconf(interfaces=["127.0.0.1"]) @@ -501,7 +502,7 @@ async def test_async_service_registration_name_strict_check() -> None: await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_tasks() -> None: """Test awaiting broadcast tasks""" @@ -567,7 +568,7 @@ def update_service(self, zeroconf: Zeroconf, type: str, name: str) -> None: ] -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_wait_unblocks_on_update() -> None: """Test async_wait will unblock on update.""" @@ -603,7 +604,7 @@ async def test_async_wait_unblocks_on_update() -> None: await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_service_info_async_request() -> None: """Test registering services broadcasts and query with AsyncServceInfo.async_request.""" if not has_working_ipv6() or os.environ.get("SKIP_IPV6"): @@ -712,7 +713,7 @@ async def test_service_info_async_request() -> None: await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_service_browser() -> None: """Test AsyncServiceBrowser.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -772,7 +773,7 @@ def update_service(self, aiozc: Zeroconf, type: str, name: str) -> None: ] -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_context_manager() -> None: """Test using an async context manager.""" type_ = "_test10-sr-type._tcp.local." @@ -796,7 +797,7 @@ async def test_async_context_manager() -> None: assert aiosinfo is not None -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_service_browser_cancel_async_context_manager(): """Test we can cancel an AsyncServiceBrowser with it being used as an async context manager.""" @@ -822,7 +823,7 @@ class MyServiceListener(ServiceListener): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_unregister_all_services() -> None: """Test unregistering all services.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -881,7 +882,7 @@ async def test_async_unregister_all_services() -> None: await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_zeroconf_service_types(): type_ = "_test-srvc-type._tcp.local." name = "xxxyyy" @@ -915,7 +916,7 @@ async def test_async_zeroconf_service_types(): await zeroconf_registrar.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_guard_against_running_serviceinfo_request_event_loop() -> None: """Test that running ServiceInfo.request from the event loop throws.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -926,7 +927,7 @@ async def test_guard_against_running_serviceinfo_request_event_loop() -> None: await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_service_browser_instantiation_generates_add_events_from_cache(): """Test that the ServiceBrowser will generate Add events with the existing cache when starting.""" @@ -975,7 +976,7 @@ def update_service(self, zc, type_, name) -> None: # type: ignore[no-untyped-de await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_integration(): service_added = asyncio.Event() service_removed = asyncio.Event() @@ -1123,7 +1124,7 @@ def send(out, addr=const._MDNS_ADDR, port=const._MDNS_PORT, v6_flow_scope=()): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_info_asking_default_is_asking_qm_questions_after_the_first_qu(): """Verify the service info first question is QU and subsequent ones are QM questions.""" type_ = "_quservice._tcp.local." @@ -1177,7 +1178,7 @@ def send(out, addr=const._MDNS_ADDR, port=const._MDNS_PORT): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_service_browser_ignores_unrelated_updates(): """Test that the ServiceBrowser ignores unrelated updates.""" @@ -1274,7 +1275,7 @@ def update_service(self, zc, type_, name) -> None: # type: ignore[no-untyped-de await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_request_timeout(): """Test that the timeout does not throw an exception and finishes close to the actual timeout.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -1288,7 +1289,7 @@ async def test_async_request_timeout(): assert (end_time - start_time) < 3000 + 1000 -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_request_non_running_instance(): """Test that the async_request throws when zeroconf is not running.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -1297,7 +1298,7 @@ async def test_async_request_non_running_instance(): await aiozc.async_get_service_info("_notfound.local.", "notthere._notfound.local.") -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_legacy_unicast_response(run_isolated): """Verify legacy unicast responses include questions and correct id.""" type_ = "_mservice._tcp.local." @@ -1338,7 +1339,7 @@ async def test_legacy_unicast_response(run_isolated): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_update_with_uppercase_names(run_isolated): """Test an ip update from a shelly which uses uppercase names.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) diff --git a/tests/test_cache.py b/tests/test_cache.py index 5bd6a869..9d55435d 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -7,6 +7,7 @@ from heapq import heapify, heappop import pytest + import zeroconf as r from zeroconf import const @@ -363,7 +364,7 @@ def test_async_get_unique_returns_newest_record(): assert record is record2 -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_cache_heap_cleanup() -> None: """Test that the heap gets cleaned up when there are many old expirations.""" cache = r.DNSCache() @@ -415,7 +416,7 @@ async def test_cache_heap_cleanup() -> None: assert not cache.async_entries_with_name(name), cache._expire_heap -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_cache_heap_multi_name_cleanup() -> None: """Test cleanup with multiple names.""" cache = r.DNSCache() @@ -451,7 +452,7 @@ async def test_cache_heap_multi_name_cleanup() -> None: assert not cache.async_entries_with_name(name), cache._expire_heap -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_cache_heap_pops_order() -> None: """Test cache heap is popped in order.""" cache = r.DNSCache() diff --git a/tests/test_circular_imports.py b/tests/test_circular_imports.py index 79d58ae1..74ed1f12 100644 --- a/tests/test_circular_imports.py +++ b/tests/test_circular_imports.py @@ -8,7 +8,7 @@ import pytest -@pytest.mark.asyncio() +@pytest.mark.asyncio @pytest.mark.timeout(30) # cloud can take > 9s @pytest.mark.parametrize( "module", diff --git a/tests/test_core.py b/tests/test_core.py index 1dfb9806..fcfdf424 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -15,6 +15,7 @@ from unittest.mock import AsyncMock, Mock, patch import pytest + import zeroconf as r from zeroconf import NotRunningException, Zeroconf, const, current_time_millis from zeroconf._listener import AsyncListener, _WrappedTransport @@ -664,7 +665,7 @@ def test_tc_bit_defers_last_response_missing(): zc.close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_open_close_twice_from_async() -> None: """Test we can close twice from a coroutine when using Zeroconf. @@ -684,7 +685,7 @@ async def test_open_close_twice_from_async() -> None: await asyncio.sleep(0) -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_multiple_sync_instances_stared_from_async_close(): """Test we can shutdown multiple sync instances from async.""" @@ -740,7 +741,7 @@ def _background_register(): bgthread.join() -@pytest.mark.asyncio() +@pytest.mark.asyncio @patch("zeroconf._core._STARTUP_TIMEOUT", 0) @patch("zeroconf._core.AsyncEngine._async_setup", new_callable=AsyncMock) async def test_event_loop_blocked(mock_start): diff --git a/tests/test_dns.py b/tests/test_dns.py index 5928338c..246c8dcf 100644 --- a/tests/test_dns.py +++ b/tests/test_dns.py @@ -8,6 +8,7 @@ import unittest.mock import pytest + import zeroconf as r from zeroconf import DNSHinfo, DNSText, ServiceInfo, const, current_time_millis from zeroconf._dns import DNSRRSet diff --git a/tests/test_engine.py b/tests/test_engine.py index 5f244804..b7a94c86 100644 --- a/tests/test_engine.py +++ b/tests/test_engine.py @@ -8,6 +8,7 @@ from unittest.mock import patch import pytest + import zeroconf as r from zeroconf import _engine, const from zeroconf.asyncio import AsyncZeroconf @@ -29,7 +30,7 @@ def teardown_module(): # This test uses asyncio because it needs to access the cache directly # which is not threadsafe -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_reaper(): with patch.object(_engine, "_CACHE_CLEANUP_INTERVAL", 0.01): aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -64,7 +65,7 @@ async def test_reaper(): assert record_with_1s_ttl not in entries -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_reaper_aborts_when_done(): """Ensure cache cleanup stops when zeroconf is done.""" with patch.object(_engine, "_CACHE_CLEANUP_INTERVAL", 0.01): diff --git a/tests/test_handlers.py b/tests/test_handlers.py index 58f8ecb1..ffa4ff88 100644 --- a/tests/test_handlers.py +++ b/tests/test_handlers.py @@ -13,6 +13,7 @@ from unittest.mock import patch import pytest + import zeroconf as r from zeroconf import ServiceInfo, Zeroconf, const, current_time_millis from zeroconf._handlers.multicast_outgoing_queue import ( @@ -492,7 +493,7 @@ def test_unicast_response(): zc.close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_probe_answered_immediately(): """Verify probes are responded to immediately.""" # instantiate a zeroconf instance @@ -543,7 +544,7 @@ async def test_probe_answered_immediately(): zc.close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_probe_answered_immediately_with_uppercase_name(): """Verify probes are responded to immediately with an uppercase name.""" # instantiate a zeroconf instance @@ -1091,7 +1092,7 @@ def test_enumeration_query_with_no_registered_services(): # This test uses asyncio because it needs to access the cache directly # which is not threadsafe -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_qu_response_only_sends_additionals_if_sends_answer(): """Test that a QU response does not send additionals unless it sends the answer as well.""" # instantiate a zeroconf instance @@ -1257,7 +1258,7 @@ async def test_qu_response_only_sends_additionals_if_sends_answer(): # This test uses asyncio because it needs to access the cache directly # which is not threadsafe -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_cache_flush_bit(): """Test that the cache flush bit sets the TTL to one for matching records.""" # instantiate a zeroconf instance @@ -1360,7 +1361,7 @@ async def test_cache_flush_bit(): # This test uses asyncio because it needs to access the cache directly # which is not threadsafe -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_record_update_manager_add_listener_callsback_existing_records(): """Test that the RecordUpdateManager will callback existing records.""" @@ -1414,7 +1415,7 @@ def async_update_records(self, zc: Zeroconf, now: float, records: list[r.RecordU await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_questions_query_handler_populates_the_question_history_from_qm_questions(): aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) zc = aiozc.zeroconf @@ -1460,7 +1461,7 @@ async def test_questions_query_handler_populates_the_question_history_from_qm_qu await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_questions_query_handler_does_not_put_qu_questions_in_history(): aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) zc = aiozc.zeroconf @@ -1503,7 +1504,7 @@ async def test_questions_query_handler_does_not_put_qu_questions_in_history(): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_guard_against_low_ptr_ttl(): """Ensure we enforce a min for PTR record ttls to avoid excessive refresh queries from ServiceBrowsers. @@ -1554,7 +1555,7 @@ async def test_guard_against_low_ptr_ttl(): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_duplicate_goodbye_answers_in_packet(): """Ensure we do not throw an exception when there are duplicate goodbye records in a packet.""" aiozc = AsyncZeroconf(interfaces=["127.0.0.1"]) @@ -1586,7 +1587,7 @@ async def test_duplicate_goodbye_answers_in_packet(): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_response_aggregation_timings(run_isolated): """Verify multicast responses are aggregated.""" type_ = "_mservice._tcp.local." @@ -1708,7 +1709,7 @@ async def test_response_aggregation_timings(run_isolated): await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_response_aggregation_timings_multiple(run_isolated, disable_duplicate_packet_suppression): """Verify multicast responses that are aggregated do not take longer than 620ms to send. @@ -1790,7 +1791,7 @@ async def test_response_aggregation_timings_multiple(run_isolated, disable_dupli assert info2.dns_pointer() in incoming.answers() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_response_aggregation_random_delay(): """Verify the random delay for outgoing multicast will coalesce into a single group @@ -1898,7 +1899,7 @@ async def test_response_aggregation_random_delay(): assert info5.dns_pointer() in outgoing_queue.queue[1].answers -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_future_answers_are_removed_on_send(): """Verify any future answers scheduled to be sent are removed when we send.""" type_ = "_mservice._tcp.local." @@ -1962,7 +1963,7 @@ async def test_future_answers_are_removed_on_send(): assert info2.dns_pointer() in outgoing_queue.queue[0].answers -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_add_listener_warns_when_not_using_record_update_listener(caplog): """Log when a listener is added that is not using RecordUpdateListener as a base class.""" @@ -1987,7 +1988,7 @@ def async_update_records(self, zc: Zeroconf, now: float, records: list[r.RecordU await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_updates_iteration_safe(): """Ensure we can safely iterate over the async_updates.""" @@ -2031,7 +2032,7 @@ def async_update_records(self, zc: Zeroconf, now: float, records: list[r.RecordU await aiozc.async_close() -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_updates_complete_iteration_safe(): """Ensure we can safely iterate over the async_updates_complete.""" diff --git a/tests/test_protocol.py b/tests/test_protocol.py index 78fed0e0..08d7e600 100644 --- a/tests/test_protocol.py +++ b/tests/test_protocol.py @@ -11,6 +11,7 @@ from typing import cast import pytest + import zeroconf as r from zeroconf import DNSHinfo, DNSIncoming, DNSText, const, current_time_millis diff --git a/tests/test_services.py b/tests/test_services.py index d192c652..7d7c3fc7 100644 --- a/tests/test_services.py +++ b/tests/test_services.py @@ -11,6 +11,7 @@ from typing import Any import pytest + import zeroconf as r from zeroconf import Zeroconf from zeroconf._services.info import ServiceInfo diff --git a/tests/test_updates.py b/tests/test_updates.py index 376082e7..ec1296f7 100644 --- a/tests/test_updates.py +++ b/tests/test_updates.py @@ -7,6 +7,7 @@ import time import pytest + import zeroconf as r from zeroconf import Zeroconf, const from zeroconf._record_update import RecordUpdate @@ -80,7 +81,7 @@ def on_service_state_change(zeroconf, service_type, state_change, name): browser.cancel() - assert len(updates) + assert updates assert len([isinstance(update, r.DNSPointer) and update.name == type_ for update in updates]) >= 1 zc.remove_listener(listener) diff --git a/tests/utils/test_asyncio.py b/tests/utils/test_asyncio.py index 4d2ee0ec..7989a82c 100644 --- a/tests/utils/test_asyncio.py +++ b/tests/utils/test_asyncio.py @@ -10,13 +10,14 @@ from unittest.mock import patch import pytest + from zeroconf import EventLoopBlocked from zeroconf._engine import _CLOSE_TIMEOUT from zeroconf._utils import asyncio as aioutils from zeroconf.const import _LOADED_SYSTEM_TIMEOUT -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_async_get_all_tasks() -> None: """Test we can get all tasks in the event loop. @@ -32,7 +33,7 @@ async def test_async_get_all_tasks() -> None: await aioutils._async_get_all_tasks(loop) -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_get_running_loop_from_async() -> None: """Test we can get the event loop.""" assert isinstance(aioutils.get_running_loop(), asyncio.AbstractEventLoop) @@ -43,7 +44,7 @@ def test_get_running_loop_no_loop() -> None: assert aioutils.get_running_loop() is None -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_wait_future_or_timeout_times_out() -> None: """Test wait_future_or_timeout will timeout.""" loop = asyncio.get_running_loop() @@ -117,7 +118,7 @@ def test_cumulative_timeouts_less_than_close_plus_buffer(): ) < 1 + _CLOSE_TIMEOUT + _LOADED_SYSTEM_TIMEOUT -@pytest.mark.asyncio() +@pytest.mark.asyncio async def test_run_coro_with_timeout() -> None: """Test running a coroutine with a timeout raises EventLoopBlocked.""" loop = asyncio.get_event_loop() diff --git a/tests/utils/test_name.py b/tests/utils/test_name.py index 3b70c7d4..1feb7713 100644 --- a/tests/utils/test_name.py +++ b/tests/utils/test_name.py @@ -5,6 +5,7 @@ import socket import pytest + from zeroconf import BadTypeInNameException from zeroconf._services.info import ServiceInfo, instance_name_from_service_info from zeroconf._utils import name as nameutils diff --git a/tests/utils/test_net.py b/tests/utils/test_net.py index 17ff6196..f763b655 100644 --- a/tests/utils/test_net.py +++ b/tests/utils/test_net.py @@ -10,6 +10,7 @@ import ifaddr import pytest + import zeroconf as r from zeroconf._utils import net as netutils