@@ -174,6 +174,99 @@ class TestNetworkingCheckpoints(netlib.NetworkCase):
174174
175175 testlib .wait (checkpoint_was_destroyed )
176176
177+ def testCheckpointSessionStorageEventSuccess (self ):
178+ b = self .browser
179+
180+ self .login_and_go ("/network" )
181+ self .nm_checkpoints_enable ()
182+ b .wait_visible ("#networking" )
183+
184+ iface = 'cockpit1'
185+ self .add_veth (iface , dhcp_cidr = "10.111.114.2/20" )
186+ self .nm_activate_eth (iface )
187+ self .wait_for_iface (iface )
188+
189+ self .select_iface (iface )
190+ b .wait_visible ("#network-interface" )
191+
192+ # Verify sessionStorage is initially false or not set
193+ initial_value = b .call_js_func ("window.sessionStorage.getItem" , "cockpit_has_checkpoint" )
194+ self .assertIn (initial_value , [None , "false" ])
195+
196+ # Change IP settings which will trigger a checkpoint
197+ self .configure_iface_setting ('IPv4' )
198+ b .wait_visible ("#network-ip-settings-dialog" )
199+ b .select_from_dropdown ("#network-ip-settings-select-method" , "manual" )
200+ b .set_input_text ('#network-ip-settings-address-0' , "10.111.114.100" )
201+ b .set_input_text ('#network-ip-settings-netmask-0' , "20" )
202+
203+ # Click save, which triggers checkpoint creation
204+ b .click ("#network-ip-settings-save" )
205+
206+ # Verify sessionStorage becomes true during checkpoint operation
207+ def checkpoint_active ():
208+ value = b .call_js_func ("window.sessionStorage.getItem" , "cockpit_has_checkpoint" )
209+ return value == "true"
210+
211+ testlib .wait (checkpoint_active )
212+
213+ # Wait for operation to complete and sessionStorage to be cleared
214+ def checkpoint_cleared ():
215+ value = b .call_js_func ("window.sessionStorage.getItem" , "cockpit_has_checkpoint" )
216+ return value == "false"
217+
218+ testlib .wait (checkpoint_cleared )
219+
220+ def testCheckpointSessionStorageEventRollback (self ):
221+ b = self .browser
222+ m = self .machine
223+
224+ self .login_and_go ("/network" )
225+ self .nm_checkpoints_enable ()
226+ b .wait_visible ("#networking" )
227+
228+ iface = self .get_iface ("52:54:00:12:34:56" )
229+
230+ if "debian" in m .image :
231+ self .sed_file ("s/managed=false/managed=true/" , "/etc/NetworkManager/NetworkManager.conf" ,
232+ "systemctl restart NetworkManager" )
233+
234+ if m .image == "arch" :
235+ self .sed_file ("s/unmanaged-devices=interface-name:eth0//" , "/etc/NetworkManager/conf.d/noauto.conf" ,
236+ "systemctl restart NetworkManager" )
237+
238+ self .wait_for_iface (iface , prefix = "172." )
239+ self .select_iface (iface )
240+ b .wait_visible ("#network-interface" )
241+
242+ # Verify sessionStorage is initially false or not set
243+ initial_value = b .call_js_func ("window.sessionStorage.getItem" , "cockpit_has_checkpoint" )
244+ self .assertIn (initial_value , [None , "false" ])
245+
246+ # Disconnect interface which will trigger checkpoint and should cause rollback dialog
247+ self .wait_onoff ("label[for='interface-switch']" , val = True )
248+ self .toggle_onoff ("label[for='interface-switch']" )
249+
250+ # Verify sessionStorage becomes true during checkpoint operation
251+ def checkpoint_active ():
252+ value = b .call_js_func ("window.sessionStorage.getItem" , "cockpit_has_checkpoint" )
253+ return value == "true"
254+
255+ testlib .wait (checkpoint_active )
256+
257+ # Wait for dialog to appear (this happens when checkpoint_destroy fails)
258+ with b .wait_timeout (60 ):
259+ b .wait_visible ("#confirm-breaking-change-popup" )
260+
261+ # By the time dialog is visible, sessionStorage should already be cleared
262+ checkpoint_cleared_value = b .call_js_func ("window.sessionStorage.getItem" , "cockpit_has_checkpoint" )
263+ self .assertEqual (checkpoint_cleared_value , "false" )
264+
265+ # Keep the connection (rollback)
266+ b .click ("#confirm-breaking-change-popup button:contains('Keep connection')" )
267+
268+ b .wait_not_present ("#confirm-breaking-change-popup" )
269+
177270
178271if __name__ == '__main__' :
179272 testlib .test_main ()
0 commit comments