| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -105,12 +105,15 @@ def verify_threads_ended(): | |||
| 105 | 105 | ||
| 106 | 106 | ||
| 107 | 107 | @pytest.fixture | |
| 108 | - def zc() -> Generator[Zeroconf]: | ||
| 108 | + def zc(verify_threads_ended: None) -> Generator[Zeroconf]: | ||
| 109 | 109 | """Yield a loopback `Zeroconf` and close it on teardown. | |
| 110 | 110 | ||
| 111 | 111 | Replaces the inline `zc = Zeroconf(interfaces=["127.0.0.1"])` + | |
| 112 | 112 | explicit `zc.close()` pattern duplicated across the suite. Calling | |
| 113 | 113 | `zc.close()` inside a test is still safe — `close()` is idempotent. | |
| 114 | + | ||
| 115 | + Depends on `verify_threads_ended` so the instance is torn down before | ||
| 116 | + the thread check runs. | ||
| 114 | 117 | """ | |
| 115 | 118 | zc = Zeroconf(interfaces=["127.0.0.1"]) | |
| 116 | 119 | try: | |
@@ -120,7 +123,7 @@ def zc() -> Generator[Zeroconf]: | |||
| 120 | 123 | ||
| 121 | 124 | ||
| 122 | 125 | @pytest_asyncio.fixture | |
| 123 | - async def aiozc() -> AsyncGenerator[AsyncZeroconf]: | ||
| 126 | + async def aiozc(verify_threads_ended: None) -> AsyncGenerator[AsyncZeroconf]: | ||
| 124 | 127 | """Yield a loopback `AsyncZeroconf` and close it on teardown. | |
| 125 | 128 | ||
| 126 | 129 | Replaces the inline `aiozc = AsyncZeroconf(interfaces=["127.0.0.1"])` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -54,11 +54,10 @@ def teardown_module(): | |||
| 54 | 54 | log.setLevel(original_logging_level) | |
| 55 | 55 | ||
| 56 | 56 | ||
| 57 | - def test_service_browser_cancel_multiple_times(): | ||
| 57 | + def test_service_browser_cancel_multiple_times(zc: Zeroconf) -> None: | ||
| 58 | 58 | """Test we can cancel a ServiceBrowser multiple times before close.""" | |
| 59 | 59 | ||
| 60 | 60 | # instantiate a zeroconf instance | |
| 61 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 62 | 61 | # start a browser | |
| 63 | 62 | type_ = "_hap._tcp.local." | |
| 64 | 63 | ||
@@ -73,14 +72,11 @@ class MyServiceListener(r.ServiceListener): | |||
| 73 | 72 | browser.cancel() | |
| 74 | 73 | browser.cancel() | |
| 75 | 74 | ||
| 76 | - zc.close() | ||
| 77 | - | ||
| 78 | 75 | ||
| 79 | - def test_service_browser_cancel_context_manager(): | ||
| 76 | + def test_service_browser_cancel_context_manager(zc: Zeroconf) -> None: | ||
| 80 | 77 | """Test we can cancel a ServiceBrowser with it being used as a context manager.""" | |
| 81 | 78 | ||
| 82 | 79 | # instantiate a zeroconf instance | |
| 83 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 84 | 80 | # start a browser | |
| 85 | 81 | type_ = "_hap._tcp.local." | |
| 86 | 82 | ||
@@ -102,8 +98,6 @@ class MyServiceListener(r.ServiceListener): | |||
| 102 | 98 | ||
| 103 | 99 | assert cast(bool, browser.done) is True | |
| 104 | 100 | ||
| 105 | - zc.close() | ||
| 106 | - | ||
| 107 | 101 | ||
| 108 | 102 | def test_service_browser_cancel_multiple_times_after_close(): | |
| 109 | 103 | """Test we can cancel a ServiceBrowser multiple times after close.""" | |
@@ -834,12 +828,10 @@ def on_service_state_change(zeroconf, service_type, state_change, name): | |||
| 834 | 828 | await aiozc.async_close() | |
| 835 | 829 | ||
| 836 | 830 | ||
| 837 | - def test_legacy_record_update_listener(quick_timing: None) -> None: | ||
| 831 | + def test_legacy_record_update_listener(zc: Zeroconf, quick_timing: None) -> None: | ||
| 838 | 832 | """Test a RecordUpdateListener that does not implement update_records.""" | |
| 839 | 833 | ||
| 840 | 834 | # instantiate a zeroconf instance | |
| 841 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 842 | - | ||
| 843 | 835 | with pytest.raises(RuntimeError): | |
| 844 | 836 | r.RecordUpdateListener().update_record( | |
| 845 | 837 | zc, | |
@@ -892,14 +884,11 @@ def on_service_state_change(zeroconf, service_type, state_change, name): | |||
| 892 | 884 | # Removing a second time should not throw | |
| 893 | 885 | zc.remove_listener(listener) | |
| 894 | 886 | ||
| 895 | - zc.close() | ||
| 896 | - | ||
| 897 | 887 | ||
| 898 | - def test_service_browser_is_aware_of_port_changes(): | ||
| 888 | + def test_service_browser_is_aware_of_port_changes(zc: Zeroconf) -> None: | ||
| 899 | 889 | """Test that the ServiceBrowser is aware of port changes.""" | |
| 900 | 890 | ||
| 901 | 891 | # instantiate a zeroconf instance | |
| 902 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 903 | 892 | # start a browser | |
| 904 | 893 | type_ = "_hap._tcp.local." | |
| 905 | 894 | registration_name = f"xxxyyy.{type_}" | |
@@ -955,14 +944,11 @@ def on_service_state_change(zeroconf, service_type, state_change, name): | |||
| 955 | 944 | assert service_info.port == 400 | |
| 956 | 945 | browser.cancel() | |
| 957 | 946 | ||
| 958 | - zc.close() | ||
| 959 | - | ||
| 960 | 947 | ||
| 961 | - def test_service_browser_listeners_update_service(): | ||
| 948 | + def test_service_browser_listeners_update_service(zc: Zeroconf) -> None: | ||
| 962 | 949 | """Test that the ServiceBrowser ServiceListener that implements update_service.""" | |
| 963 | 950 | ||
| 964 | 951 | # instantiate a zeroconf instance | |
| 965 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 966 | 952 | # start a browser | |
| 967 | 953 | type_ = "_hap._tcp.local." | |
| 968 | 954 | registration_name = f"xxxyyy.{type_}" | |
@@ -1017,14 +1003,11 @@ def update_service(self, zc, type_, name) -> None: # type: ignore[no-untyped-de | |||
| 1017 | 1003 | ] | |
| 1018 | 1004 | browser.cancel() | |
| 1019 | 1005 | ||
| 1020 | - zc.close() | ||
| 1021 | - | ||
| 1022 | 1006 | ||
| 1023 | - def test_service_browser_listeners_no_update_service(): | ||
| 1007 | + def test_service_browser_listeners_no_update_service(zc: Zeroconf) -> None: | ||
| 1024 | 1008 | """A listener that ignores update events records only add/remove callbacks.""" | |
| 1025 | 1009 | ||
| 1026 | 1010 | # instantiate a zeroconf instance | |
| 1027 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 1028 | 1011 | # start a browser | |
| 1029 | 1012 | type_ = "_hap._tcp.local." | |
| 1030 | 1013 | registration_name = f"xxxyyy.{type_}" | |
@@ -1077,12 +1060,9 @@ def update_service(self, zc, type_, name) -> None: # type: ignore[no-untyped-de | |||
| 1077 | 1060 | ] | |
| 1078 | 1061 | browser.cancel() | |
| 1079 | 1062 | ||
| 1080 | - zc.close() | ||
| 1081 | - | ||
| 1082 | 1063 | ||
| 1083 | - def test_service_browser_nsec_record_does_not_trigger_update(): | ||
| 1064 | + def test_service_browser_nsec_record_does_not_trigger_update(zc: Zeroconf) -> None: | ||
| 1084 | 1065 | """NSEC records assert non-existence and must not fire ServiceStateChange.Updated.""" | |
| 1085 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 1086 | 1066 | type_ = "_hap._tcp.local." | |
| 1087 | 1067 | registration_name = f"xxxyyy.{type_}" | |
| 1088 | 1068 | callbacks: list[tuple[str, str, str]] = [] | |
@@ -1144,24 +1124,21 @@ def update_service(self, zc, type_, name) -> None: # type: ignore[no-untyped-de | |||
| 1144 | 1124 | assert callbacks == [("add", type_, registration_name)] | |
| 1145 | 1125 | finally: | |
| 1146 | 1126 | browser.cancel() | |
| 1147 | - zc.close() | ||
| 1148 | 1127 | ||
| 1149 | 1128 | ||
| 1150 | - def test_service_browser_uses_non_strict_names(): | ||
| 1129 | + def test_service_browser_uses_non_strict_names(zc: Zeroconf) -> None: | ||
| 1151 | 1130 | """Verify we can look for technically invalid names as we cannot change what others do.""" | |
| 1152 | 1131 | ||
| 1153 | 1132 | # dummy service callback | |
| 1154 | 1133 | def on_service_state_change(zeroconf, service_type, state_change, name): | |
| 1155 | 1134 | pass | |
| 1156 | 1135 | ||
| 1157 | - zc = r.Zeroconf(interfaces=["127.0.0.1"]) | ||
| 1158 | 1136 | browser = ServiceBrowser(zc, ["_tivo-videostream._tcp.local."], [on_service_state_change]) | |
| 1159 | 1137 | browser.cancel() | |
| 1160 | 1138 | ||
| 1161 | 1139 | # Still fail on completely invalid | |
| 1162 | 1140 | with pytest.raises(r.BadTypeInNameException): | |
| 1163 | 1141 | browser = ServiceBrowser(zc, ["tivo-videostream._tcp.local."], [on_service_state_change]) | |
| 1164 | - zc.close() | ||
| 1165 | 1142 | ||
| 1166 | 1143 | ||
| 1167 | 1144 | def test_group_ptr_queries_with_known_answers(): | |
@@ -1408,11 +1385,10 @@ def send(out, addr=const._MDNS_ADDR, port=const._MDNS_PORT, v6_flow_scope=()): | |||
| 1408 | 1385 | await aiozc.async_close() | |
| 1409 | 1386 | ||
| 1410 | 1387 | ||
| 1411 | - def test_service_browser_matching(): | ||
| 1388 | + def test_service_browser_matching(zc: Zeroconf) -> None: | ||
| 1412 | 1389 | """Test that the ServiceBrowser matching does not match partial names.""" | |
| 1413 | 1390 | ||
| 1414 | 1391 | # instantiate a zeroconf instance | |
| 1415 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 1416 | 1392 | # start a browser | |
| 1417 | 1393 | type_ = "_http._tcp.local." | |
| 1418 | 1394 | registration_name = f"xxxyyy.{type_}" | |
@@ -1495,8 +1471,6 @@ def update_service(self, zc, type_, name) -> None: # type: ignore[no-untyped-de | |||
| 1495 | 1471 | ] | |
| 1496 | 1472 | browser.cancel() | |
| 1497 | 1473 | ||
| 1498 | - zc.close() | ||
| 1499 | - | ||
| 1500 | 1474 | ||
| 1501 | 1475 | @patch.object(_engine, "_CACHE_CLEANUP_INTERVAL", 0.01) | |
| 1502 | 1476 | def test_service_browser_expire_callbacks(): | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -181,13 +181,9 @@ def test_use_asyncio_true_requires_running_loop(): | |||
| 181 | 181 | r.Zeroconf(interfaces=["127.0.0.1"], use_asyncio=True) | |
| 182 | 182 | ||
| 183 | 183 | ||
| 184 | - def test_use_asyncio_default_starts_thread_without_loop(): | ||
| 184 | + def test_use_asyncio_default_starts_thread_without_loop(zc: Zeroconf) -> None: | ||
| 185 | 185 | """use_asyncio=None (default) keeps the historic auto-detect behavior.""" | |
| 186 | - zc = r.Zeroconf(interfaces=["127.0.0.1"]) | ||
| 187 | - try: | ||
| 188 | - assert zc._loop_thread is not None | ||
| 189 | - finally: | ||
| 190 | - zc.close() | ||
| 186 | + assert zc._loop_thread is not None | ||
| 191 | 187 | ||
| 192 | 188 | ||
| 193 | 189 | def test_async_updates_from_response(): | |
@@ -396,9 +392,8 @@ def test_invalid_packets_ignored_and_does_not_cause_loop_exception(): | |||
| 396 | 392 | assert zc.cache.get(entry) is not None | |
| 397 | 393 | ||
| 398 | 394 | ||
| 399 | - def test_goodbye_all_services(): | ||
| 395 | + def test_goodbye_all_services(zc: Zeroconf) -> None: | ||
| 400 | 396 | """Verify generating the goodbye query does not change with time.""" | |
| 401 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 402 | 397 | out = zc.generate_unregister_all_services() | |
| 403 | 398 | assert out is None | |
| 404 | 399 | type_ = "_http._tcp.local." | |
@@ -429,15 +424,11 @@ def test_goodbye_all_services(): | |||
| 429 | 424 | assert out3 is None | |
| 430 | 425 | assert zc.registry.async_get_service_infos() == [] | |
| 431 | 426 | ||
| 432 | - zc.close() | ||
| 433 | 427 | ||
| 434 | - | ||
| 435 | - def test_register_service_with_custom_ttl(quick_timing: None) -> None: | ||
| 428 | + def test_register_service_with_custom_ttl(zc: Zeroconf, quick_timing: None) -> None: | ||
| 436 | 429 | """Test a registering a service with a custom ttl.""" | |
| 437 | 430 | ||
| 438 | 431 | # instantiate a zeroconf instance | |
| 439 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 440 | - | ||
| 441 | 432 | # start a browser | |
| 442 | 433 | type_ = "_homeassistant._tcp.local." | |
| 443 | 434 | name = "MyTestHome" | |
@@ -456,15 +447,12 @@ def test_register_service_with_custom_ttl(quick_timing: None) -> None: | |||
| 456 | 447 | record = zc.cache.get(info_service.dns_pointer()) | |
| 457 | 448 | assert record is not None | |
| 458 | 449 | assert record.ttl == 3000 | |
| 459 | - zc.close() | ||
| 460 | 450 | ||
| 461 | 451 | ||
| 462 | - def test_logging_packets(caplog: pytest.LogCaptureFixture, quick_timing: None) -> None: | ||
| 452 | + def test_logging_packets(zc: Zeroconf, caplog: pytest.LogCaptureFixture, quick_timing: None) -> None: | ||
| 463 | 453 | """Test packets are only logged with debug logging.""" | |
| 464 | 454 | ||
| 465 | 455 | # instantiate a zeroconf instance | |
| 466 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 467 | - | ||
| 468 | 456 | # start a browser | |
| 469 | 457 | type_ = "_logging._tcp.local." | |
| 470 | 458 | name = "TLD" | |
@@ -492,23 +480,18 @@ def test_logging_packets(caplog: pytest.LogCaptureFixture, quick_timing: None) - | |||
| 492 | 480 | assert "Sending to" not in caplog.text | |
| 493 | 481 | logging.getLogger("zeroconf").setLevel(logging.DEBUG) | |
| 494 | 482 | ||
| 495 | - zc.close() | ||
| 496 | - | ||
| 497 | 483 | ||
| 498 | - def test_get_service_info_failure_path(): | ||
| 484 | + def test_get_service_info_failure_path(zc: Zeroconf) -> None: | ||
| 499 | 485 | """Verify get_service_info return None when the underlying call returns False.""" | |
| 500 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 501 | 486 | assert zc.get_service_info("_neverused._tcp.local.", "xneverused._neverused._tcp.local.", 10) is None | |
| 502 | - zc.close() | ||
| 503 | 487 | ||
| 504 | 488 | ||
| 505 | 489 | @pytest.mark.skipif( | |
| 506 | 490 | sys.platform == "win32", | |
| 507 | 491 | reason="multicast loopback on the 127.0.0.1-only socket is unreliable on GH Actions Windows runners", | |
| 508 | 492 | ) | |
| 509 | - def test_sending_unicast(): | ||
| 493 | + def test_sending_unicast(zc: Zeroconf) -> None: | ||
| 510 | 494 | """Test sending unicast response.""" | |
| 511 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 512 | 495 | generated = r.DNSOutgoing(const._FLAGS_QR_RESPONSE) | |
| 513 | 496 | entry = r.DNSText( | |
| 514 | 497 | "didnotcrashincoming._crash._tcp.local.", | |
@@ -534,11 +517,8 @@ def test_sending_unicast(): | |||
| 534 | 517 | ||
| 535 | 518 | assert zc.cache.get(entry) is not None | |
| 536 | 519 | ||
| 537 | - zc.close() | ||
| 538 | 520 | ||
| 539 | - | ||
| 540 | - def test_tc_bit_defers(): | ||
| 541 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 521 | + def test_tc_bit_defers(zc: Zeroconf) -> None: | ||
| 542 | 522 | _wait_for_start(zc) | |
| 543 | 523 | type_ = "_tcbitdefer._tcp.local." | |
| 544 | 524 | name = "knownname" | |
@@ -634,11 +614,9 @@ def test_tc_bit_defers(): | |||
| 634 | 614 | ||
| 635 | 615 | # unregister | |
| 636 | 616 | zc.unregister_service(info) | |
| 637 | - zc.close() | ||
| 638 | 617 | ||
| 639 | 618 | ||
| 640 | - def test_tc_bit_defers_last_response_missing(): | ||
| 641 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 619 | + def test_tc_bit_defers_last_response_missing(zc: Zeroconf) -> None: | ||
| 642 | 620 | _wait_for_start(zc) | |
| 643 | 621 | type_ = "_knowndefer._tcp.local." | |
| 644 | 622 | name = "knownname" | |
@@ -751,12 +729,10 @@ def test_tc_bit_defers_last_response_missing(): | |||
| 751 | 729 | ||
| 752 | 730 | # unregister | |
| 753 | 731 | zc.registry.async_remove(info) | |
| 754 | - zc.close() | ||
| 755 | 732 | ||
| 756 | 733 | ||
| 757 | - def test_tc_bit_defer_window_is_bounded(): | ||
| 734 | + def test_tc_bit_defer_window_is_bounded(zc: Zeroconf) -> None: | ||
| 758 | 735 | """TC-deferral assembly window must not slide past first_arrival + max delay.""" | |
| 759 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 760 | 736 | _wait_for_start(zc) | |
| 761 | 737 | type_ = "_boundeddefer._tcp.local." | |
| 762 | 738 | registration_name = f"knownname.{type_}" | |
@@ -797,7 +773,6 @@ def test_tc_bit_defer_window_is_bounded(): | |||
| 797 | 773 | assert protocol._timers[source_ip].when() <= first_when | |
| 798 | 774 | ||
| 799 | 775 | zc.registry.async_remove(info) | |
| 800 | - zc.close() | ||
| 801 | 776 | ||
| 802 | 777 | ||
| 803 | 778 | def _make_distinct_tc_packets(count: int, name_prefix: str = "q") -> list[bytes]: | |
@@ -819,9 +794,8 @@ def _synthetic_source_ip(i: int) -> str: | |||
| 819 | 794 | return f"192.0.2.{i - 512}" | |
| 820 | 795 | ||
| 821 | 796 | ||
| 822 | - def test_tc_bit_per_addr_queue_is_bounded(quick_timing: None) -> None: | ||
| 797 | + def test_tc_bit_per_addr_queue_is_bounded(zc: Zeroconf, quick_timing: None) -> None: | ||
| 823 | 798 | """Per-addr deferred queue must not grow past ``_MAX_DEFERRED_PER_ADDR``.""" | |
| 824 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 825 | 799 | _wait_for_start(zc) | |
| 826 | 800 | protocol = zc.engine.protocols[0] | |
| 827 | 801 | source_ip = "203.0.113.21" | |
@@ -841,12 +815,9 @@ def test_tc_bit_per_addr_queue_is_bounded(quick_timing: None) -> None: | |||
| 841 | 815 | retained = [incoming.data for incoming in protocol._deferred[source_ip]] | |
| 842 | 816 | assert retained == packets[: const._MAX_DEFERRED_PER_ADDR] | |
| 843 | 817 | ||
| 844 | - zc.close() | ||
| 845 | - | ||
| 846 | 818 | ||
| 847 | - def test_tc_bit_total_addrs_is_bounded(quick_timing: None) -> None: | ||
| 819 | + def test_tc_bit_total_addrs_is_bounded(zc: Zeroconf, quick_timing: None) -> None: | ||
| 848 | 820 | """Distinct addrs with deferred state must not exceed ``_MAX_DEFERRED_ADDRS``.""" | |
| 849 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 850 | 821 | _wait_for_start(zc) | |
| 851 | 822 | protocol = zc.engine.protocols[0] | |
| 852 | 823 | ||
@@ -865,12 +836,9 @@ def test_tc_bit_total_addrs_is_bounded(quick_timing: None) -> None: | |||
| 865 | 836 | assert len(protocol._deferred) == const._MAX_DEFERRED_ADDRS | |
| 866 | 837 | assert len(protocol._timers) == const._MAX_DEFERRED_ADDRS | |
| 867 | 838 | ||
| 868 | - zc.close() | ||
| 869 | - | ||
| 870 | 839 | ||
| 871 | - def test_tc_bit_eviction_drops_oldest_addr(quick_timing: None) -> None: | ||
| 840 | + def test_tc_bit_eviction_drops_oldest_addr(zc: Zeroconf, quick_timing: None) -> None: | ||
| 872 | 841 | """Adding a new addr at capacity drops the oldest insertion (FIFO).""" | |
| 873 | - zc = Zeroconf(interfaces=["127.0.0.1"]) | ||
| 874 | 842 | _wait_for_start(zc) | |
| 875 | 843 | protocol = zc.engine.protocols[0] | |
| 876 | 844 | ||
@@ -892,8 +860,6 @@ def test_tc_bit_eviction_drops_oldest_addr(quick_timing: None) -> None: | |||
| 892 | 860 | assert new_addr in protocol._deferred | |
| 893 | 861 | assert len(protocol._deferred) == const._MAX_DEFERRED_ADDRS | |
| 894 | 862 | ||
| 895 | - zc.close() | ||
| 896 | - | ||
| 897 | 863 | ||
| 898 | 864 | @pytest.mark.asyncio | |
| 899 | 865 | async def test_open_close_twice_from_async() -> None: | |
| Back | FazBrowse Home | New Git URL |
0 commit comments