This commit is contained in:
Arthur 2026-07-23 15:09:52 -07:00
parent 6539ee10b2
commit eeb44cd0c8
1 changed files with 25 additions and 0 deletions

View File

@ -90,6 +90,31 @@ class CountersTestCase(TestCase):
device_type.refresh_from_db() device_type.refresh_from_db()
self.assertEqual(device_type.device_count, 1) self.assertEqual(device_type.device_count, 1)
# Exactly one update should fire (DeviceType.device_count). Without the optimization the two
# cascaded Interfaces on Device 1 would each have triggered an interface_count update.
self.assertEqual(mock_update.call_count, 1)
def test_counter_skipped_when_parent_deleted_via_queryset(self):
"""
A bulk QuerySet delete (e.g. Device.objects.filter(...).delete(), as used by scripts,
plugins, and programmatic callers) sets `origin` to the QuerySet rather than a single
object. Counter updates for children whose parent belongs to that QuerySet must be
suppressed, while counters on surviving related objects are still updated.
"""
device_type = Device.objects.get(name='Device 1').device_type
self.assertEqual(device_type.device_count, 2)
# Wrap update_counter so the real counter logic still runs while we record each call
with patch('utilities.counters.update_counter', wraps=update_counter) as mock_update:
Device.objects.filter(name='Device 1').delete()
# The deleted Device's interface_count must not be decremented per cascaded Interface, and
# the only update should be the surviving DeviceType's device_count
counter_names = [call.args[2] for call in mock_update.call_args_list]
self.assertEqual(counter_names, ['device_count'])
device_type.refresh_from_db()
self.assertEqual(device_type.device_count, 1)
def test_interface_count_move(self): def test_interface_count_move(self):
""" """
When a tracked object (Interface) is moved, the tracking counter should be updated. When a tracked object (Interface) is moved, the tracking counter should be updated.