@@ -515,6 +515,11 @@ def _mock_get_expiration_time(self, percent):
515515 assert service_added_count == 3
516516 assert service_removed_count == 0
517517
518+ _inject_response (
519+ zeroconf ,
520+ mock_incoming_msg (r .ServiceStateChange .Updated , service_types [0 ], service_names [0 ], 0 ),
521+ )
522+
518523 # all three services removed
519524 _inject_response (
520525 zeroconf ,
@@ -1265,6 +1270,124 @@ def mock_incoming_msg(records) -> r.DNSIncoming:
12651270 zc .close ()
12661271
12671272
1273+ def test_service_browser_listeners_update_service ():
1274+ """Test that the ServiceBrowser ServiceListener that implements update_service."""
1275+
1276+ # instantiate a zeroconf instance
1277+ zc = Zeroconf (interfaces = ['127.0.0.1' ])
1278+ # start a browser
1279+ type_ = "_hap._tcp.local."
1280+ registration_name = "xxxyyy.%s" % type_
1281+ callbacks = []
1282+
1283+ class MyServiceListener (r .ServiceListener ):
1284+ def add_service (self , zc , type_ , name ) -> None :
1285+ nonlocal callbacks
1286+ if name == registration_name :
1287+ callbacks .append (("add" , type_ , name ))
1288+
1289+ def remove_service (self , zc , type_ , name ) -> None :
1290+ nonlocal callbacks
1291+ if name == registration_name :
1292+ callbacks .append (("remove" , type_ , name ))
1293+
1294+ def update_service (self , zc , type_ , name ) -> None :
1295+ nonlocal callbacks
1296+ if name == registration_name :
1297+ callbacks .append (("update" , type_ , name ))
1298+
1299+ listener = MyServiceListener ()
1300+
1301+ browser = r .ServiceBrowser (zc , type_ , None , listener )
1302+
1303+ desc = {'path' : '/~paulsm/' }
1304+ address_parsed = "10.0.1.2"
1305+ address = socket .inet_aton (address_parsed )
1306+ info = ServiceInfo (type_ , registration_name , 80 , 0 , 0 , desc , "ash-2.local." , addresses = [address ])
1307+
1308+ def mock_incoming_msg (records ) -> r .DNSIncoming :
1309+ generated = r .DNSOutgoing (const ._FLAGS_QR_RESPONSE )
1310+ for record in records :
1311+ generated .add_answer_at_time (record , 0 )
1312+ return r .DNSIncoming (generated .packets ()[0 ])
1313+
1314+ _inject_response (
1315+ zc ,
1316+ mock_incoming_msg ([info .dns_pointer (), info .dns_service (), info .dns_text (), * info .dns_addresses ()]),
1317+ )
1318+ time .sleep (0.2 )
1319+ info .port = 400
1320+ _inject_response (
1321+ zc ,
1322+ mock_incoming_msg ([info .dns_service ()]),
1323+ )
1324+ time .sleep (0.2 )
1325+
1326+ assert callbacks == [
1327+ ('add' , type_ , registration_name ),
1328+ ('update' , type_ , registration_name ),
1329+ ]
1330+ browser .cancel ()
1331+
1332+ zc .close ()
1333+
1334+
1335+ def test_service_browser_listeners_no_update_service ():
1336+ """Test that the ServiceBrowser ServiceListener that does not implement update_service."""
1337+
1338+ # instantiate a zeroconf instance
1339+ zc = Zeroconf (interfaces = ['127.0.0.1' ])
1340+ # start a browser
1341+ type_ = "_hap._tcp.local."
1342+ registration_name = "xxxyyy.%s" % type_
1343+ callbacks = []
1344+
1345+ class MyServiceListener :
1346+ def add_service (self , zc , type_ , name ) -> None :
1347+ nonlocal callbacks
1348+ if name == registration_name :
1349+ callbacks .append (("add" , type_ , name ))
1350+
1351+ def remove_service (self , zc , type_ , name ) -> None :
1352+ nonlocal callbacks
1353+ if name == registration_name :
1354+ callbacks .append (("remove" , type_ , name ))
1355+
1356+ listener = MyServiceListener ()
1357+
1358+ browser = r .ServiceBrowser (zc , type_ , None , listener )
1359+
1360+ desc = {'path' : '/~paulsm/' }
1361+ address_parsed = "10.0.1.2"
1362+ address = socket .inet_aton (address_parsed )
1363+ info = ServiceInfo (type_ , registration_name , 80 , 0 , 0 , desc , "ash-2.local." , addresses = [address ])
1364+
1365+ def mock_incoming_msg (records ) -> r .DNSIncoming :
1366+ generated = r .DNSOutgoing (const ._FLAGS_QR_RESPONSE )
1367+ for record in records :
1368+ generated .add_answer_at_time (record , 0 )
1369+ return r .DNSIncoming (generated .packets ()[0 ])
1370+
1371+ _inject_response (
1372+ zc ,
1373+ mock_incoming_msg ([info .dns_pointer (), info .dns_service (), info .dns_text (), * info .dns_addresses ()]),
1374+ )
1375+ time .sleep (0.2 )
1376+ info .port = 400
1377+ _inject_response (
1378+ zc ,
1379+ mock_incoming_msg ([info .dns_service ()]),
1380+ )
1381+ time .sleep (0.2 )
1382+
1383+ assert callbacks == [
1384+ ('add' , type_ , registration_name ),
1385+ ]
1386+ browser .cancel ()
1387+
1388+ zc .close ()
1389+
1390+
12681391def test_changing_name_updates_serviceinfo_key ():
12691392 """Verify a name change will adjust the underlying key value."""
12701393 type_ = "_homeassistant._tcp.local."
0 commit comments