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']) aiozc = AsyncZeroconf(zc=zc) assert aiozc.zeroconf is zc zc.close() await aiozc.async_close()
async def test_async_zeroconf_service_types(): type_ = "_test-srvc-type._tcp.local." name = "xxxyyy" registration_name = "%s.%s" % (name, type_) zeroconf_registrar = AsyncZeroconf(interfaces=['127.0.0.1']) desc = {'path': '/~paulsm/'} info = ServiceInfo( type_, registration_name, 80, 0, 0, desc, "ash-2.local.", addresses=[socket.inet_aton("10.0.1.2")], ) task = await zeroconf_registrar.async_register_service(info) await task # Ensure we do not clear the cache until after the last broadcast is processed await asyncio.sleep(0.2) _clear_cache(zeroconf_registrar.zeroconf) try: service_types = await AsyncZeroconfServiceTypes.async_find( interfaces=['127.0.0.1'], timeout=0.5) assert type_ in service_types _clear_cache(zeroconf_registrar.zeroconf) service_types = await AsyncZeroconfServiceTypes.async_find( aiozc=zeroconf_registrar, timeout=0.5) assert type_ in service_types finally: await zeroconf_registrar.async_close()
async def test_async_wait_unblocks_on_update() -> None: """Test async_wait will unblock on update.""" aiozc = AsyncZeroconf(interfaces=['127.0.0.1']) type_ = "_test-srvc4-type._tcp.local." name = "xxxyyy" registration_name = "%s.%s" % (name, type_) desc = {'path': '/~paulsm/'} info = ServiceInfo( type_, registration_name, 80, 0, 0, desc, "ash-2.local.", addresses=[socket.inet_aton("10.0.1.2")], ) task = await aiozc.async_register_service(info) # Should unblock due to update from the # registration now = current_time_millis() await aiozc.async_wait(50000) assert current_time_millis() - now < 3000 await task now = current_time_millis() await aiozc.async_wait(50) assert current_time_millis() - now < 1000 await aiozc.async_close()
async def test_async_service_registration() -> None: """Test registering services broadcasts the registration by default.""" aiozc = AsyncZeroconf(interfaces=['127.0.0.1']) type_ = "_test1-srvc-type._tcp.local." name = "xxxyyy" registration_name = "%s.%s" % (name, type_) calls = [] class MyListener(ServiceListener): def add_service(self, zeroconf: Zeroconf, type: str, name: str) -> None: calls.append(("add", type, name)) def remove_service(self, zeroconf: Zeroconf, type: str, name: str) -> None: calls.append(("remove", type, name)) def update_service(self, zeroconf: Zeroconf, type: str, name: str) -> None: calls.append(("update", type, name)) listener = MyListener() aiozc.zeroconf.add_service_listener(type_, listener) desc = {'path': '/~paulsm/'} info = ServiceInfo( type_, registration_name, 80, 0, 0, desc, "ash-2.local.", addresses=[socket.inet_aton("10.0.1.2")], ) task = await aiozc.async_register_service(info) await task new_info = ServiceInfo( type_, registration_name, 80, 0, 0, desc, "ash-2.local.", addresses=[socket.inet_aton("10.0.1.3")], ) task = await aiozc.async_update_service(new_info) await task task = await aiozc.async_unregister_service(new_info) await task await aiozc.async_close() assert calls == [ ('add', type_, registration_name), ('update', type_, registration_name), ('remove', type_, registration_name), ]
async def async_run(self) -> None: self.aiozc = AsyncZeroconf(ip_version=ip_version) services = ["_http._tcp.local.", "_hap._tcp.local."] if self.args.find: services = list(await AsyncZeroconfServiceTypes.async_find( aiozc=self.aiozc, ip_version=ip_version)) print("\nBrowsing %s service(s), press Ctrl-C to exit...\n" % services) self.aiobrowser = AsyncServiceBrowser( self.aiozc, services, handlers=[async_on_service_state_change]) while True: await asyncio.sleep(1)
async def test_async_unregister_all_services() -> None: """Test unregistering all services.""" aiozc = AsyncZeroconf(interfaces=['127.0.0.1']) type_ = "_test1-srvc-type._tcp.local." name = "xxxyyy" name2 = "abc" registration_name = "%s.%s" % (name, type_) registration_name2 = "%s.%s" % (name2, type_) desc = {'path': '/~paulsm/'} info = ServiceInfo( type_, registration_name, 80, 0, 0, desc, "ash-1.local.", addresses=[socket.inet_aton("10.0.1.2")], ) info2 = ServiceInfo( type_, registration_name2, 80, 0, 0, desc, "ash-5.local.", addresses=[socket.inet_aton("10.0.1.5")], ) tasks = [] tasks.append(await aiozc.async_register_service(info)) tasks.append(await aiozc.async_register_service(info2)) await asyncio.gather(*tasks) tasks = [] tasks.append(aiozc.async_get_service_info(type_, registration_name)) tasks.append(aiozc.async_get_service_info(type_, registration_name2)) results = await asyncio.gather(*tasks) assert results[0] is not None assert results[1] is not None await aiozc.async_unregister_all_services() tasks = [] tasks.append(aiozc.async_get_service_info(type_, registration_name)) tasks.append(aiozc.async_get_service_info(type_, registration_name2)) results = await asyncio.gather(*tasks) assert results[0] is None assert results[1] is None # Verify we can call again await aiozc.async_unregister_all_services() await aiozc.async_close()
async def test_async_service_registration_name_conflict() -> None: """Test registering services throws on name conflict.""" aiozc = AsyncZeroconf(interfaces=['127.0.0.1']) type_ = "_test-srvc2-type._tcp.local." name = "xxxyyy" registration_name = "%s.%s" % (name, type_) desc = {'path': '/~paulsm/'} info = ServiceInfo( type_, registration_name, 80, 0, 0, desc, "ash-2.local.", addresses=[socket.inet_aton("10.0.1.2")], ) task = await aiozc.async_register_service(info) await task with pytest.raises(NonUniqueNameException): task = await aiozc.async_register_service(info) await task with pytest.raises(ServiceNameAlreadyRegistered): task = await aiozc.async_register_service(info, cooperating_responders=True) await task conflicting_info = ServiceInfo( type_, registration_name, 80, 0, 0, desc, "ash-3.local.", addresses=[socket.inet_aton("10.0.1.3")], ) with pytest.raises(NonUniqueNameException): task = await aiozc.async_register_service(conflicting_info) await task await aiozc.async_close()
async def test_async_context_manager() -> None: """Test using an async context manager.""" type_ = "_test10-sr-type._tcp.local." name = "xxxyyy" registration_name = "%s.%s" % (name, type_) async with AsyncZeroconf(interfaces=['127.0.0.1']) as aiozc: info = ServiceInfo( type_, registration_name, 80, 0, 0, {'path': '/~paulsm/'}, "ash-2.local.", addresses=[socket.inet_aton("10.0.1.2")], ) task = await aiozc.async_register_service(info) await task aiosinfo = await aiozc.async_get_service_info(type_, registration_name) assert aiosinfo is not None
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']) type_ = "_test-srvc3-type._tcp.local." name = "xxxyyy" registration_name = "%s.%s" % (name, type_) desc = {'path': '/~paulsm/'} info = ServiceInfo( type_, registration_name, 80, 0, 0, desc, "ash-2.local.", addresses=[socket.inet_aton("10.0.1.2")], ) info.type = "_wrong._tcp.local." with pytest.raises(BadTypeInNameException): task = await aiozc.async_register_service(info) await task await aiozc.async_close()
ip_version = IPVersion.V4Only infos = [] for i in range(250): infos.append( AsyncServiceInfo( "_http._tcp.local.", f"Paul's Test Web Site {i}._http._tcp.local.", addresses=[socket.inet_aton("127.0.0.1")], port=80, properties={'path': '/~paulsm/'}, server=f"zcdemohost-{i}.local.", ) ) print("Registration of 250 services, press Ctrl-C to exit...") aiozc = AsyncZeroconf(ip_version=ip_version) loop = asyncio.get_event_loop() loop.run_until_complete(register_services(infos)) print("Registration complete.") try: while True: time.sleep(0.1) except KeyboardInterrupt: pass finally: print("Unregistering...") loop.run_until_complete(unregister_services(infos)) print("Unregistration complete.") loop.run_until_complete(close_aiozc(aiozc))
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']) aiozc = AsyncZeroconf(zc=zc) assert aiozc.zeroconf is zc await aiozc.async_close()
async def test_async_close_twice() -> None: """Test we can close twice.""" aiozc = AsyncZeroconf(interfaces=['127.0.0.1']) await aiozc.async_close() await aiozc.async_close()
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()
async def test_async_service_browser() -> None: """Test AsyncServiceBrowser.""" aiozc = AsyncZeroconf(interfaces=['127.0.0.1']) type_ = "_test9-srvc-type._tcp.local." name = "xxxyyy" registration_name = "%s.%s" % (name, type_) calls = [] with pytest.raises(NotImplementedError): AsyncServiceListener().add_service(aiozc, "_type", "name._type") with pytest.raises(NotImplementedError): AsyncServiceListener().remove_service(aiozc, "_type", "name._type") with pytest.raises(NotImplementedError): AsyncServiceListener().update_service(aiozc, "_type", "name._type") class MyListener(AsyncServiceListener): def add_service(self, aiozc: AsyncZeroconf, type: str, name: str) -> None: calls.append(("add", type, name)) def remove_service(self, aiozc: AsyncZeroconf, type: str, name: str) -> None: calls.append(("remove", type, name)) def update_service(self, aiozc: AsyncZeroconf, type: str, name: str) -> None: calls.append(("update", type, name)) listener = MyListener() await aiozc.async_add_service_listener(type_, listener) desc = {'path': '/~paulsm/'} info = ServiceInfo( type_, registration_name, 80, 0, 0, desc, "ash-2.local.", addresses=[socket.inet_aton("10.0.1.2")], ) task = await aiozc.async_register_service(info) await task new_info = ServiceInfo( type_, registration_name, 80, 0, 0, desc, "ash-2.local.", addresses=[socket.inet_aton("10.0.1.3")], ) task = await aiozc.async_update_service(new_info) await task task = await aiozc.async_unregister_service(new_info) await task await aiozc.async_wait(1) await aiozc.async_close() assert calls == [ ('add', type_, registration_name), ('update', type_, registration_name), ('remove', type_, registration_name), ]
async def test_service_info_async_request() -> None: """Test registering services broadcasts and query with AsyncServceInfo.async_request.""" aiozc = AsyncZeroconf(interfaces=['127.0.0.1']) type_ = "_test1-srvc-type._tcp.local." name = "xxxyyy" name2 = "abc" registration_name = "%s.%s" % (name, type_) registration_name2 = "%s.%s" % (name2, type_) # Start a tasks BEFORE the registration that will keep trying # and see the registration a bit later get_service_info_task1 = asyncio.ensure_future( aiozc.async_get_service_info(type_, registration_name)) await asyncio.sleep(_LISTENER_TIME / 1000 / 2) get_service_info_task2 = asyncio.ensure_future( aiozc.async_get_service_info(type_, registration_name)) desc = {'path': '/~paulsm/'} info = ServiceInfo( type_, registration_name, 80, 0, 0, desc, "ash-1.local.", addresses=[socket.inet_aton("10.0.1.2")], ) info2 = ServiceInfo( type_, registration_name2, 80, 0, 0, desc, "ash-5.local.", addresses=[socket.inet_aton("10.0.1.5")], ) tasks = [] tasks.append(await aiozc.async_register_service(info)) tasks.append(await aiozc.async_register_service(info2)) await asyncio.gather(*tasks) aiosinfo = await get_service_info_task1 assert aiosinfo is not None assert aiosinfo.addresses == [socket.inet_aton("10.0.1.2")] aiosinfo = await get_service_info_task2 assert aiosinfo is not None assert aiosinfo.addresses == [socket.inet_aton("10.0.1.2")] aiosinfo = await aiozc.async_get_service_info(type_, registration_name) assert aiosinfo is not None assert aiosinfo.addresses == [socket.inet_aton("10.0.1.2")] new_info = ServiceInfo( type_, registration_name, 80, 0, 0, desc, "ash-2.local.", addresses=[ socket.inet_aton("10.0.1.3"), socket.inet_pton(socket.AF_INET6, "6001:db8::1") ], ) task = await aiozc.async_update_service(new_info) await task aiosinfo = await aiozc.async_get_service_info(type_, registration_name) assert aiosinfo is not None assert aiosinfo.addresses == [socket.inet_aton("10.0.1.3")] aiosinfos = await asyncio.gather( aiozc.async_get_service_info(type_, registration_name), aiozc.async_get_service_info(type_, registration_name2), ) assert aiosinfos[0] is not None assert aiosinfos[0].addresses == [socket.inet_aton("10.0.1.3")] assert aiosinfos[1] is not None assert aiosinfos[1].addresses == [socket.inet_aton("10.0.1.5")] aiosinfo = AsyncServiceInfo(type_, registration_name) _clear_cache(aiozc.zeroconf) # Generating the race condition is almost impossible # without patching since its a TOCTOU race with unittest.mock.patch("zeroconf.aio.AsyncServiceInfo._is_complete", False): await aiosinfo.async_request(aiozc, 3000) assert aiosinfo is not None assert aiosinfo.addresses == [socket.inet_aton("10.0.1.3")] task = await aiozc.async_unregister_service(new_info) await task aiosinfo = await aiozc.async_get_service_info(type_, registration_name) assert aiosinfo is None await aiozc.async_close()
parser = argparse.ArgumentParser() parser.add_argument('--debug', action='store_true') version_group = parser.add_mutually_exclusive_group() version_group.add_argument('--v6', action='store_true') version_group.add_argument('--v6-only', action='store_true') args = parser.parse_args() if args.debug: logging.getLogger('zeroconf').setLevel(logging.DEBUG) if args.v6: ip_version = IPVersion.All elif args.v6_only: ip_version = IPVersion.V6Only else: ip_version = IPVersion.V4Only aiozc = AsyncZeroconf(ip_version=ip_version) services = ["_http._tcp.local.", "_hap._tcp.local."] print("\nBrowsing %s service(s), press Ctrl-C to exit...\n" % services) aiobrowser = AsyncServiceBrowser(aiozc, services, handlers=[async_on_service_state_change]) loop = asyncio.get_event_loop() try: loop.run_forever() except KeyboardInterrupt: pass finally: loop.run_until_complete(aiobrowser.async_cancel()) loop.run_until_complete(aiozc.async_close())