11"""
22Tests for Branch merge functionality with ObjectChange collapsing.
33"""
4+ import uuid
5+
46from django .contrib .auth import get_user_model
57from django .db import connections
6- from django .test import TransactionTestCase
8+ from django .test import RequestFactory , TransactionTestCase
9+ from django .urls import reverse
710
811from dcim .models import Device , DeviceRole , DeviceType , Interface , Manufacturer , Site
12+ from netbox .context_managers import event_tracking
913from netbox_branching .choices import BranchStatusChoices
1014from netbox_branching .models import Branch
1115from netbox_branching .utilities import activate_branch
@@ -43,6 +47,7 @@ def _create_and_provision_branch(self, name='Test Branch'):
4347 branch = Branch (name = name )
4448 branch .save (provision = False )
4549 branch .provision (user = self .user )
50+ branch .refresh_from_db () # Refresh to get updated status
4651 return branch
4752
4853 def test_merge_delete_then_create_same_slug (self ):
@@ -57,8 +62,13 @@ def test_merge_delete_then_create_same_slug(self):
5762 # Create branch
5863 branch = self ._create_and_provision_branch ()
5964
65+ # Create a request context for event tracking
66+ request = RequestFactory ().get (reverse ('home' ))
67+ request .id = uuid .uuid4 () # Set request id for ObjectChange tracking
68+ request .user = self .user
69+
6070 # In branch: delete old site, create new site with same slug
61- with activate_branch (branch ):
71+ with activate_branch (branch ), event_tracking ( request ) :
6272 Site .objects .get (id = site1_id ).delete ()
6373 site2 = Site .objects .create (name = 'Site 1 New' , slug = 'site-1' )
6474 site2_id = site2 .id
@@ -82,58 +92,65 @@ def test_merge_delete_then_create_same_slug(self):
8292 branch .refresh_from_db ()
8393 self .assertEqual (branch .status , BranchStatusChoices .MERGED )
8494
85- def test_merge_update_interface_then_delete_device (self ):
95+ def test_merge_create_device_and_delete_old (self ):
8696 """
87- Test merging when an interface is moved to a new device, then the old device is deleted.
88- The update must happen before the delete to avoid cascade deletion .
97+ Test merging when a new device is created and an old device is deleted.
98+ Tests ordering with dependencies .
8999 """
90- # Create devices and interface in main
100+ # Create device with interface in main
91101 site = Site .objects .create (name = 'Site 1' , slug = 'site-1' )
92102 device_a = Device .objects .create (
93103 name = 'Device A' ,
94104 site = site ,
95105 device_type = self .device_type ,
96- device_role = self .device_role
106+ role = self .device_role
97107 )
98108 device_a_id = device_a .id
99109
100- interface = Interface .objects .create (
110+ interface_a = Interface .objects .create (
101111 device = device_a ,
102112 name = 'eth0' ,
103113 type = '1000base-t'
104114 )
105- interface_id = interface .id
115+ interface_a_id = interface_a .id
106116
107117 # Create branch
108118 branch = self ._create_and_provision_branch ()
109119
110- # In branch: create new device, move interface, delete old device
111- with activate_branch (branch ):
120+ # Create a request context for event tracking
121+ request = RequestFactory ().get (reverse ('home' ))
122+ request .id = uuid .uuid4 () # Set request id for ObjectChange tracking
123+ request .user = self .user
124+
125+ # In branch: create new device with interface, delete old device with interface
126+ with activate_branch (branch ), event_tracking (request ):
112127 device_b = Device .objects .create (
113128 name = 'Device B' ,
114129 site = Site .objects .first (),
115130 device_type = DeviceType .objects .first (),
116- device_role = DeviceRole .objects .first ()
131+ role = DeviceRole .objects .first ()
117132 )
118133 device_b_id = device_b .id
119134
120- # Move interface to new device
121- interface = Interface .objects .get (id = interface_id )
122- interface .device = device_b
123- interface .save ()
135+ # Create interface on new device
136+ interface_b = Interface .objects .create (
137+ device = device_b ,
138+ name = 'eth0' ,
139+ type = '1000base-t'
140+ )
141+ interface_b_id = interface_b .id
124142
125- # Delete old device
143+ # Delete old device (cascade deletes interface_a)
126144 Device .objects .get (id = device_a_id ).delete ()
127145
128146 # Merge branch
129147 branch .merge (user = self .user , commit = True )
130148
131149 # Verify main schema
132150 self .assertFalse (Device .objects .filter (id = device_a_id ).exists ())
151+ self .assertFalse (Interface .objects .filter (id = interface_a_id ).exists ())
133152 self .assertTrue (Device .objects .filter (id = device_b_id ).exists ())
134-
135- interface = Interface .objects .get (id = interface_id )
136- self .assertEqual (interface .device_id , device_b_id )
153+ self .assertTrue (Interface .objects .filter (id = interface_b_id ).exists ())
137154
138155 def test_merge_create_and_delete_same_object (self ):
139156 """
@@ -142,8 +159,13 @@ def test_merge_create_and_delete_same_object(self):
142159 # Create branch
143160 branch = self ._create_and_provision_branch ()
144161
162+ # Create a request context for event tracking
163+ request = RequestFactory ().get (reverse ('home' ))
164+ request .id = uuid .uuid4 () # Set request id for ObjectChange tracking
165+ request .user = self .user
166+
145167 # In branch: create and delete a site
146- with activate_branch (branch ):
168+ with activate_branch (branch ), event_tracking ( request ) :
147169 site = Site .objects .create (name = 'Temp Site' , slug = 'temp-site' )
148170 site_id = site .id
149171 site .delete ()
@@ -170,8 +192,13 @@ def test_merge_slug_rename_then_create(self):
170192 # Create branch
171193 branch = self ._create_and_provision_branch ()
172194
195+ # Create a request context for event tracking
196+ request = RequestFactory ().get (reverse ('home' ))
197+ request .id = uuid .uuid4 () # Set request id for ObjectChange tracking
198+ request .user = self .user
199+
173200 # In branch: rename site1 slug, create new site with old slug
174- with activate_branch (branch ):
201+ with activate_branch (branch ), event_tracking ( request ) :
175202 site1 = Site .objects .get (id = site1_id )
176203 site1 .slug = 'site-1-renamed'
177204 site1 .save ()
@@ -202,8 +229,13 @@ def test_merge_multiple_updates_collapsed(self):
202229 # Create branch
203230 branch = self ._create_and_provision_branch ()
204231
232+ # Create a request context for event tracking
233+ request = RequestFactory ().get (reverse ('home' ))
234+ request .id = uuid .uuid4 () # Set request id for ObjectChange tracking
235+ request .user = self .user
236+
205237 # In branch: update site multiple times
206- with activate_branch (branch ):
238+ with activate_branch (branch ), event_tracking ( request ) :
207239 site = Site .objects .get (id = site_id )
208240
209241 site .description = 'Update 1'
@@ -231,8 +263,13 @@ def test_merge_create_with_multiple_updates(self):
231263 # Create branch
232264 branch = self ._create_and_provision_branch ()
233265
266+ # Create a request context for event tracking
267+ request = RequestFactory ().get (reverse ('home' ))
268+ request .id = uuid .uuid4 () # Set request id for ObjectChange tracking
269+ request .user = self .user
270+
234271 # In branch: create site and update it multiple times
235- with activate_branch (branch ):
272+ with activate_branch (branch ), event_tracking ( request ) :
236273 site = Site .objects .create (name = 'New Site' , slug = 'new-site' , description = 'Initial' )
237274 site_id = site .id
238275
@@ -262,49 +299,51 @@ def test_merge_complex_dependency_chain(self):
262299 name = 'Device A' ,
263300 site = site ,
264301 device_type = self .device_type ,
265- device_role = self .device_role
302+ role = self .device_role
266303 )
267304 device_a_id = device_a .id
268305
269306 # Create branch
270307 branch = self ._create_and_provision_branch ()
271308
309+ # Create a request context for event tracking
310+ request = RequestFactory ().get (reverse ('home' ))
311+ request .id = uuid .uuid4 () # Set request id for ObjectChange tracking
312+ request .user = self .user
313+
272314 # In branch: complex operations
273- with activate_branch (branch ):
315+ with activate_branch (branch ), event_tracking ( request ) :
274316 # Create new devices
275317 device_b = Device .objects .create (
276318 name = 'Device B' ,
277319 site = Site .objects .first (),
278320 device_type = DeviceType .objects .first (),
279- device_role = DeviceRole .objects .first ()
321+ role = DeviceRole .objects .first ()
280322 )
281323 device_b_id = device_b .id
282324
283325 device_c = Device .objects .create (
284326 name = 'Device C' ,
285327 site = Site .objects .first (),
286328 device_type = DeviceType .objects .first (),
287- device_role = DeviceRole .objects .first ()
329+ role = DeviceRole .objects .first ()
288330 )
289331 device_c_id = device_c .id
290332
291- # Create interfaces
292- interface_a = Interface .objects .create (
293- device = device_a ,
294- name = 'eth0' ,
295- type = '1000base-t'
296- )
297-
333+ # Create interface on device_b
298334 interface_b = Interface .objects .create (
299335 device = device_b ,
300336 name = 'eth0' ,
301337 type = '1000base-t'
302338 )
303339 interface_b_id = interface_b .id
304340
305- # Move interface_a to device_b
306- interface_a .device = device_b
307- interface_a .save ()
341+ # Create another interface on device_b
342+ interface_c = Interface .objects .create (
343+ device = device_b ,
344+ name = 'eth1' ,
345+ type = '1000base-t'
346+ )
308347
309348 # Update device_b
310349 device_b .name = 'Device B Updated'
@@ -323,7 +362,7 @@ def test_merge_complex_dependency_chain(self):
323362
324363 device_b = Device .objects .get (id = device_b_id )
325364 self .assertEqual (device_b .name , 'Device B Updated' )
326- self .assertEqual (device_b .interface_set .count (), 2 )
365+ self .assertEqual (device_b .interfaces .count (), 2 )
327366
328367 def test_merge_delete_ordering_by_time (self ):
329368 """
@@ -341,8 +380,13 @@ def test_merge_delete_ordering_by_time(self):
341380 # Create branch
342381 branch = self ._create_and_provision_branch ()
343382
383+ # Create a request context for event tracking
384+ request = RequestFactory ().get (reverse ('home' ))
385+ request .id = uuid .uuid4 () # Set request id for ObjectChange tracking
386+ request .user = self .user
387+
344388 # In branch: delete sites in specific order
345- with activate_branch (branch ):
389+ with activate_branch (branch ), event_tracking ( request ) :
346390 Site .objects .get (id = site1_id ).delete ()
347391 Site .objects .get (id = site3_id ).delete ()
348392 Site .objects .get (id = site2_id ).delete ()
0 commit comments