@@ -996,6 +996,9 @@ def send(out, addr=const._MDNS_ADDR, port=const._MDNS_PORT, v6_flow_scope=()):
996996 # Increase simulated time shift by 1/4 of the TTL in seconds
997997 time_offset += expected_ttl / 4
998998 now = _new_current_time_millis ()
999+ # Force the next query to be sent since we are testing
1000+ # to see if the query contains answers and not the scheduler
1001+ browser .query_scheduler ._next_time [type_ ] = now + (1000 * expected_ttl )
9991002 browser .reschedule_type (type_ , now , now )
10001003 sleep_count += 1
10011004 await asyncio .wait_for (got_query .wait (), 1 )
@@ -1244,3 +1247,67 @@ def update_service(self, zc, type_, name) -> None: # type: ignore[no-untyped-de
12441247 ('add' , '_http._tcp.local.' , 'ShellyPro4PM-94B97EC07650._http._tcp.local.' ),
12451248 ('update' , '_http._tcp.local.' , 'ShellyPro4PM-94B97EC07650._http._tcp.local.' ),
12461249 ]
1250+
1251+
1252+ @pytest .mark .asyncio
1253+ async def test_service_browser_does_not_try_to_send_if_not_ready ():
1254+ """Test that the service browser does not try to send if not ready when rescheduling a type."""
1255+ service_added = asyncio .Event ()
1256+ type_ = "_http._tcp.local."
1257+ registration_name = "nosend.%s" % type_
1258+
1259+ def on_service_state_change (zeroconf , service_type , state_change , name ):
1260+ if name == registration_name :
1261+ if state_change is ServiceStateChange .Added :
1262+ service_added .set ()
1263+
1264+ aiozc = AsyncZeroconf (interfaces = ['127.0.0.1' ])
1265+ zeroconf_browser = aiozc .zeroconf
1266+ await zeroconf_browser .async_wait_for_start ()
1267+
1268+ expected_ttl = const ._DNS_HOST_TTL
1269+ time_offset = 0.0
1270+
1271+ def _new_current_time_millis ():
1272+ """Current system time in milliseconds"""
1273+ return (time .monotonic () * 1000 ) + (time_offset * 1000 )
1274+
1275+ assert len (zeroconf_browser .engine .protocols ) == 2
1276+
1277+ aio_zeroconf_registrar = AsyncZeroconf (interfaces = ['127.0.0.1' ])
1278+ zeroconf_registrar = aio_zeroconf_registrar .zeroconf
1279+ await aio_zeroconf_registrar .zeroconf .async_wait_for_start ()
1280+ assert len (zeroconf_registrar .engine .protocols ) == 2
1281+ with patch ("zeroconf._services.browser.current_time_millis" , _new_current_time_millis ):
1282+ service_added = asyncio .Event ()
1283+ browser = AsyncServiceBrowser (zeroconf_browser , type_ , [on_service_state_change ])
1284+ desc = {'path' : '/~paulsm/' }
1285+ info = ServiceInfo (
1286+ type_ , registration_name , 80 , 0 , 0 , desc , "ash-2.local." , addresses = [socket .inet_aton ("10.0.1.2" )]
1287+ )
1288+ task = await aio_zeroconf_registrar .async_register_service (info )
1289+ await task
1290+
1291+ try :
1292+ await asyncio .wait_for (service_added .wait (), 1 )
1293+ time_offset = 1000 * expected_ttl # set the time to the end of the ttl
1294+ now = _new_current_time_millis ()
1295+ browser .query_scheduler ._next_time [type_ ] = now + (1000 * expected_ttl )
1296+ # Make sure the query schedule is to a time in the future
1297+ # so we will reschedule
1298+ with patch .object (
1299+ browser , "_async_send_ready_queries"
1300+ ) as _async_send_ready_queries , patch .object (
1301+ browser , "_async_send_ready_queries_schedule_next"
1302+ ) as _async_send_ready_queries_schedule_next :
1303+ # Reschedule the type to be sent in 1ms in the future
1304+ # to make sure the query is not sent
1305+ browser .reschedule_type (type_ , now , now + 1 )
1306+ assert not _async_send_ready_queries .called
1307+ await asyncio .sleep (0.01 )
1308+ # Make sure it does happen after the sleep
1309+ assert _async_send_ready_queries_schedule_next .called
1310+ finally :
1311+ await aio_zeroconf_registrar .async_close ()
1312+ await browser .async_cancel ()
1313+ await aiozc .async_close ()
0 commit comments