Skip to content

Commit a8595be

Browse files
authored
fix: stop OON policies churning as ghost deletions on UniFi 10.x (#154) (#155)
1 parent ade8cbf commit a8595be

5 files changed

Lines changed: 35 additions & 18 deletions

File tree

custom_components/unifi_network_rules/coordination/entity_manager.py

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -352,23 +352,12 @@ def check_for_deleted_rules(self, new_data: dict[str, list[Any]]) -> None:
352352

353353
current_known_ids = set(self.coordinator.known_unique_ids) # Take a snapshot
354354

355-
# Gather ALL unique IDs present in the new data
355+
# Gather ALL unique IDs present in the new data. Mirrors the discovery
356+
# map so any rule type the discovery side creates entities for is also
357+
# checked here — otherwise entries in known_unique_ids for missing
358+
# types get flagged as ghost deletions every cycle (issue #154).
356359
all_current_unique_ids = set()
357-
all_rule_sources_types = [
358-
"port_forwards",
359-
"traffic_routes",
360-
"static_routes",
361-
"nat_rules",
362-
"firewall_policies",
363-
"traffic_rules",
364-
"legacy_firewall_rules",
365-
"qos_rules",
366-
"wlans",
367-
"vpn_clients",
368-
"vpn_servers",
369-
"port_profiles",
370-
"networks",
371-
]
360+
all_rule_sources_types = [rule_type for rule_type, _ in self._rule_type_entity_map]
372361

373362
for rule_type in all_rule_sources_types:
374363
rules = new_data.get(rule_type, [])

custom_components/unifi_network_rules/coordination/state_manager.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def data_has_changes(self, previous_data: dict[str, list[Any]], new_data: dict[s
6868
"port_profiles",
6969
"networks",
7070
"nat_rules",
71+
"oon_policies",
7172
]:
7273
prev_count = len(previous_data.get(rule_type, []))
7374
new_count = len(new_data.get(rule_type, []))
@@ -87,6 +88,7 @@ def data_has_changes(self, previous_data: dict[str, list[Any]], new_data: dict[s
8788
"wlans",
8889
"qos_rules",
8990
"nat_rules",
91+
"oon_policies",
9092
]:
9193
prev_rules = previous_data.get(rule_type, [])
9294
new_rules = new_data.get(rule_type, [])
@@ -286,6 +288,7 @@ def validate_data_and_handle_errors(self, data: dict[str, list[Any]], previous_d
286288
"networks",
287289
"devices",
288290
"nat_rules",
291+
"oon_policies",
289292
]
290293
)
291294

custom_components/unifi_network_rules/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"quality_scale": "custom",
1313
"requirements": [
1414
"aiohttp",
15-
"aiounifi>=87.0.0",
15+
"aiounifi>=91",
1616
"orjson>=3.8.0"
1717
],
1818
"version": "4.4.5"

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ asyncio
33
aiofiles
44
aiohttp
55
argparse
6-
aiounifi>=87.0.0
6+
aiounifi>=91
77
pytest
88
pytest-asyncio
99
pytest-aiohttp

tests/test_oon_policy.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,3 +273,28 @@ def test_change_detector_mapping(self):
273273
detector = UnifiedChangeDetector(Mock(), Mock())
274274
assert "oon_policies" in detector._rule_type_mapping
275275
assert detector._rule_type_mapping["oon_policies"] == "oon_policy"
276+
277+
def test_deletion_check_does_not_orphan_oon_policies(self, oon_policy_payload):
278+
"""Regression for #154: OON policies present in current data must not
279+
be flagged as deletions every cycle. The deletion-check iteration list
280+
previously omitted "oon_policies", causing every OON ID in
281+
known_unique_ids to be treated as a ghost deletion on every poll."""
282+
from custom_components.unifi_network_rules.coordination.entity_manager import (
283+
CoordinatorEntityManager,
284+
)
285+
from custom_components.unifi_network_rules.helpers.rule import get_rule_id
286+
287+
policy = OONPolicy(oon_policy_payload)
288+
oon_unique_id = get_rule_id(policy)
289+
assert oon_unique_id and oon_unique_id.startswith("unr_oon_")
290+
291+
coordinator = Mock()
292+
coordinator._initial_update_done = True
293+
coordinator.known_unique_ids = {oon_unique_id}
294+
295+
manager = CoordinatorEntityManager(Mock(), coordinator)
296+
manager._process_deleted_rules = Mock()
297+
298+
manager.check_for_deleted_rules({"oon_policies": [policy]})
299+
300+
manager._process_deleted_rules.assert_not_called()

0 commit comments

Comments
 (0)