diff --git a/aiounifi/interfaces/api_handlers.py b/aiounifi/interfaces/api_handlers.py index ad4d1c84a..7410b3d82 100644 --- a/aiounifi/interfaces/api_handlers.py +++ b/aiounifi/interfaces/api_handlers.py @@ -146,7 +146,6 @@ def subscribe( elif isinstance(id_filter, str): _id_filter = (id_filter,) - subscription = (callback, event_filter) for obj_id in _id_filter: if obj_id not in self._subscribers: self._subscribers[obj_id] = [] @@ -156,6 +155,8 @@ def unsubscribe() -> None: for obj_id in _id_filter: if obj_id not in self._subscribers: continue + if subscription not in self._subscribers[obj_id]: + continue self._subscribers[obj_id].remove(subscription) return unsubscribe diff --git a/tests/test_api.py b/tests/test_api.py index 658bde2fd..4b753f81a 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -2,39 +2,133 @@ from unittest.mock import Mock +import pytest + from aiounifi.interfaces.api_handlers import APIHandler, ItemEvent -async def test_api_handler_subscriptions(): +@pytest.mark.parametrize( + "event_filter", + [ + None, + {ItemEvent.ADDED, ItemEvent.CHANGED, ItemEvent.DELETED}, + ], +) +async def test_api_handler_subscriptions(event_filter): """Test process and remove item.""" handler = APIHandler(Mock()) handler.obj_id_key = "key" handler.item_cls = Mock() - handler.subscribe(mock_subscribe_cb := Mock()) + unsub = handler.subscribe(mock_subscribe_cb := Mock(), event_filter) assert handler.process_item({}) == "" mock_subscribe_cb.assert_not_called() - assert handler.process_item({"key": 1}) == 1 - mock_subscribe_cb.assert_called_with(ItemEvent.ADDED, 1) + assert handler.process_item({"key": "1"}) == "1" + mock_subscribe_cb.assert_called_with(ItemEvent.ADDED, "1") - assert handler.process_item({"key": 1}) == "" - mock_subscribe_cb.assert_called_with(ItemEvent.CHANGED, 1) + assert handler.process_item({"key": "1"}) == "" + mock_subscribe_cb.assert_called_with(ItemEvent.CHANGED, "1") - assert handler.remove_item({"key": 1}) == 1 - mock_subscribe_cb.assert_called_with(ItemEvent.DELETED, 1) + assert handler.remove_item({"key": "1"}) == "1" + mock_subscribe_cb.assert_called_with(ItemEvent.DELETED, "1") - assert handler.remove_item({"key": 2}) == "" + assert handler.remove_item({"key": "2"}) == "" # Process raw assert handler.process_raw([{}]) == set() - assert handler.process_raw([{"key": 2}]) == {2} - mock_subscribe_cb.assert_called_with(ItemEvent.ADDED, 2) + assert handler.process_raw([{"key": "2"}]) == {"2"} + mock_subscribe_cb.assert_called_with(ItemEvent.ADDED, "2") + + assert handler.process_raw([{"key": "2"}]) == set() + mock_subscribe_cb.assert_called_with(ItemEvent.CHANGED, "2") + + assert handler.remove_item({"key": "2"}) == "2" + mock_subscribe_cb.assert_called_with(ItemEvent.DELETED, "2") + + unsub() + + unsub() # Empty list of object ID + + handler._subscribers.clear() + + unsub() # Object ID does not exist in subscribers + + +async def test_api_handler_subscriptions_event_filter_added(): + """Test process and remove item.""" + handler = APIHandler(Mock()) + handler.obj_id_key = "key" + handler.item_cls = Mock() + + unsub = handler.subscribe(mock_subscribe_cb := Mock(), ItemEvent.ADDED) + + assert handler.process_item({}) == "" + mock_subscribe_cb.assert_not_called() + + assert handler.process_item({"key": "1"}) == "1" + mock_subscribe_cb.assert_called_with(ItemEvent.ADDED, "1") + + assert handler.process_item({"key": "1"}) == "" + assert mock_subscribe_cb.call_count == 1 + + assert handler.remove_item({"key": "1"}) == "1" + assert mock_subscribe_cb.call_count == 1 + + assert handler.remove_item({"key": "2"}) == "" + + # Process raw + + assert handler.process_raw([{}]) == set() + + assert handler.process_raw([{"key": "2"}]) == {"2"} + mock_subscribe_cb.assert_called_with(ItemEvent.ADDED, "2") + + assert handler.process_raw([{"key": "2"}]) == set() + assert mock_subscribe_cb.call_count == 2 + + assert handler.remove_item({"key": "2"}) == "2" + assert mock_subscribe_cb.call_count == 2 + + unsub() + + +async def test_api_handler_subscriptions_id_filter(): + """Test process and remove item.""" + handler = APIHandler(Mock()) + handler.obj_id_key = "key" + handler.item_cls = Mock() + + unsub = handler.subscribe(mock_subscribe_cb := Mock(), id_filter="1") + + assert handler.process_item({}) == "" + mock_subscribe_cb.assert_not_called() + + assert handler.process_item({"key": "1"}) == "1" + mock_subscribe_cb.assert_called_with(ItemEvent.ADDED, "1") + + assert handler.process_item({"key": "1"}) == "" + mock_subscribe_cb.assert_called_with(ItemEvent.CHANGED, "1") + + assert handler.remove_item({"key": "1"}) == "1" + mock_subscribe_cb.assert_called_with(ItemEvent.DELETED, "1") + + assert handler.remove_item({"key": "2"}) == "" + + # Process raw + + assert handler.process_raw([{}]) == set() + + assert handler.process_raw([{"key": "2"}]) == {"2"} + assert mock_subscribe_cb.call_count == 3 + + assert handler.process_raw([{"key": "2"}]) == set() + assert mock_subscribe_cb.call_count == 3 - assert handler.process_raw([{"key": 2}]) == set() - mock_subscribe_cb.assert_called_with(ItemEvent.CHANGED, 2) + assert handler.remove_item({"key": "2"}) == "2" + assert mock_subscribe_cb.call_count == 3 - assert handler.remove_item({"key": 2}) == 2 + unsub()