2929from unittest .mock import patch , mock_open
3030import asyncio
3131import sys
32+ import logging
3233
3334import qubes .config
3435import qubes .tests
3536import qubesadmin .exc
3637
38+ # nose will duplicate this logger.
39+ logger = logging .getLogger (__name__ )
40+ logger .setLevel (logging .DEBUG )
41+ handler = logging .StreamHandler ()
42+ formatter = logging .Formatter (
43+ "%(asctime)s: %(funcName)s: %(levelname)s: %(message)s"
44+ )
45+ handler .setFormatter (formatter )
46+ logger .addHandler (handler )
47+
3748
3849class TC_04_DispVM (qubes .tests .SystemTestCase ):
3950 def setUp (self ):
@@ -183,6 +194,7 @@ def test_011_failed_start_timeout(self):
183194
184195class TC_20_DispVMMixin (object ):
185196 def setUp (self ): # pylint: disable=invalid-name
197+ logger .info ("start" )
186198 super (TC_20_DispVMMixin , self ).setUp ()
187199 if "whonix-g" in self .template :
188200 self .skipTest (
@@ -205,8 +217,10 @@ def setUp(self): # pylint: disable=invalid-name
205217 "--" ,
206218 "qubesdb-read /name | tr -d '\n '" ,
207219 ]
220+ logger .info ("end" )
208221
209222 def tearDown (self ): # pylint: disable=invalid-name
223+ logger .info ("start" )
210224 if "gui" in self .disp_base .features :
211225 del self .disp_base .features ["gui" ]
212226 old_preload = self .disp_base .get_feat_preload ()
@@ -215,6 +229,7 @@ def tearDown(self): # pylint: disable=invalid-name
215229 self .loop .run_until_complete (asyncio .gather (* tasks ))
216230 self .disp_base .features ["preload-dispvm-max" ] = False
217231 super (TC_20_DispVMMixin , self ).tearDown ()
232+ logger .info ("end" )
218233
219234 def _test_event_handler (
220235 self , vm , event , * args , ** kwargs
@@ -233,7 +248,38 @@ async def no_preload(self):
233248 await asyncio .sleep (0 )
234249 self .disp_base .features ["preload-dispvm-max" ] = False
235250
251+ async def wait_preload (
252+ self , preload_max , wait_pause = True , fail_on_timeout = True
253+ ):
254+ """Waiting for pause avoids objects leaking."""
255+ logger .info ("start" )
256+ for _ in range (60 ):
257+ if len (self .disp_base .get_feat_preload ()) == preload_max :
258+ break
259+ await asyncio .sleep (1 )
260+ else :
261+ if fail_on_timeout :
262+ self .fail ("didn't preload in time" )
263+ if not wait_pause :
264+ logger .info ("end" )
265+ return
266+ preload_dispvm = self .disp_base .get_feat_preload ()
267+ preload_unfinished = preload_dispvm
268+ for _ in range (60 ):
269+ for qube in preload_unfinished .copy ():
270+ if self .app .domains [qube ].is_paused ():
271+ preload_unfinished .remove (qube )
272+ continue
273+ if not preload_unfinished :
274+ break
275+ await asyncio .sleep (1 )
276+ else :
277+ if fail_on_timeout :
278+ self .fail ("last preloaded didn't pause in time" )
279+ logger .info ("end" )
280+
236281 async def run_preload_proc (self ):
282+ logger .info ("start" )
237283 proc = await asyncio .create_subprocess_exec (
238284 * self .preload_cmd ,
239285 stdout = asyncio .subprocess .PIPE ,
@@ -245,8 +291,11 @@ async def run_preload_proc(self):
245291 proc .terminate ()
246292 await proc .wait ()
247293 raise
294+ finally :
295+ logger .info ("end" )
248296
249297 async def run_preload (self ):
298+ logger .info ("start" )
250299 appvm = self .disp_base
251300 dispvm = appvm .get_feat_preload ()[0 ]
252301 dispvm = self .app .domains [dispvm ]
@@ -324,6 +373,7 @@ async def run_preload(self):
324373 next_preload_list = appvm .get_feat_preload ()
325374 self .assertTrue (next_preload_list )
326375 self .assertNotIn (dispvm_name , next_preload_list )
376+ logger .info ("end" )
327377
328378 def test_010_dvm_run_simple (self ):
329379 dispvm = self .loop .run_until_complete (
@@ -353,6 +403,7 @@ def test_012_dvm_run_preload_low_mem(self):
353403
354404 async def _test_012_dvm_run_preload_low_mem (self ):
355405 # pylint: disable=unspecified-encoding
406+ logger .info ("start" )
356407 unpatched_open = open
357408
358409 def mock_open_mem (file , * args , ** kwargs ):
@@ -362,135 +413,107 @@ def mock_open_mem(file, *args, **kwargs):
362413 return unpatched_open (file , * args , ** kwargs )
363414
364415 with patch ("builtins.open" , side_effect = mock_open_mem ):
365- self .disp_base .features ["preload-dispvm-max" ] = "2"
366- for _ in range (15 ):
367- if len (self .disp_base .get_feat_preload ()) == 2 :
368- break
369- await asyncio .sleep (1 )
416+ preload_max = 2
417+ self .disp_base .features ["preload-dispvm-max" ] = str (preload_max )
418+ await self .wait_preload (preload_max , fail_on_timeout = False )
370419 self .assertEqual (1 , len (self .disp_base .get_feat_preload ()))
420+ logger .info ("end" )
371421
372422 def test_013_dvm_run_preload_gui (self ):
373- """Test preloading with GUI feature enabled"""
423+ """Test preloading with GUI feature enabled and use after pause. """
374424 self .loop .run_until_complete (self ._test_013_dvm_run_preload_gui ())
375425
376426 async def _test_013_dvm_run_preload_gui (self ):
427+ logger .info ("start" )
428+ preload_max = 1
377429 self .disp_base .features ["gui" ] = True
378- self .disp_base .features ["preload-dispvm-max" ] = "1"
379- for _ in range (10 ):
380- if len (self .disp_base .get_feat_preload ()) == 1 :
381- break
382- await asyncio .sleep (1 )
383- else :
384- self .fail ("didn't preload in time" )
430+ self .disp_base .features ["preload-dispvm-max" ] = str (preload_max )
431+ await self .wait_preload (preload_max )
385432 await self .run_preload ()
433+ logger .info ("end" )
386434
387435 def test_014_dvm_run_preload_nogui (self ):
388- """Test preloading with GUI feature disabled"""
436+ """Test preloading with GUI feature disabled and use before pause. """
389437 self .loop .run_until_complete (self ._test_014_dvm_run_preload_nogui ())
390438
391439 async def _test_014_dvm_run_preload_nogui (self ):
440+ logger .info ("start" )
441+ preload_max = 1
392442 self .disp_base .features ["gui" ] = False
393- self .disp_base .features ["preload-dispvm-max" ] = "1"
394- for _ in range (10 ):
395- if len (self .disp_base .get_feat_preload ()) == 1 :
396- break
397- await asyncio .sleep (1 )
398- else :
399- self .fail ("didn't preload in time" )
443+ self .disp_base .features ["preload-dispvm-max" ] = str (preload_max )
444+ await self .wait_preload (preload_max , wait_pause = False )
400445 self .preload_cmd .insert (1 , "--no-gui" )
401446 await self .run_preload ()
447+ logger .info ("end" )
402448
403449 def test_015_dvm_run_preload_race_more (self ):
404450 """Test race requesting multiple preloaded qubes"""
405451 self .loop .run_until_complete (self ._test_015_dvm_run_preload_race_more ())
406452
407- async def _test_preload_wait_pause (self , preload_max ):
408- """Waiting for pause avoids objects leaking."""
409- for _ in range (60 ):
410- if len (self .disp_base .get_feat_preload ()) == preload_max :
411- break
412- await asyncio .sleep (1 )
413- else :
414- self .fail ("didn't preload in time" )
415- preload_dispvm = self .disp_base .get_feat_preload ()
416- preload_unfinished = preload_dispvm
417- for _ in range (60 ):
418- for qube in preload_unfinished .copy ():
419- if self .app .domains [qube ].is_paused ():
420- preload_unfinished .remove (qube )
421- continue
422- if not preload_unfinished :
423- break
424- await asyncio .sleep (1 )
425- else :
426- self .fail ("last preloaded didn't pause in time" )
427-
428453 async def _test_015_dvm_run_preload_race_more (self ):
429454 # The limiting factor is how much memory is available on OpenQA and the
430455 # unreasonable memory allocated before the qube is paused due to:
431456 # https://github.com/QubesOS/qubes-issues/issues/9917
432457 # Whonix (Kicksecure) 17 fail more due to memory consumption. From the
433458 # templates deployed by default, only Debian and Fedora survives due to
434459 # using less memory than the other OSes.
460+ logger .info ("start" )
435461 preload_max = 4
436462 os_dist = self .disp_base .features .check_with_template ("os-distribution" )
437463 if os_dist in ["whonix" , "kicksecure" ]:
438464 preload_max -= 1
439465 self .disp_base .features ["preload-dispvm-max" ] = str (preload_max )
440- await self ._test_preload_wait_pause (preload_max )
466+ await self .wait_preload (preload_max )
441467 old_preload = self .disp_base .get_feat_preload ()
442468 tasks = [self .run_preload_proc () for _ in range (preload_max )]
443469 targets = await asyncio .gather (* tasks )
444- await self ._test_preload_wait_pause (preload_max )
470+ await self .wait_preload (preload_max )
445471 preload_dispvm = self .disp_base .get_feat_preload ()
446472 self .assertTrue (set (old_preload ).isdisjoint (preload_dispvm ))
447473 self .assertEqual (len (targets ), preload_max )
448474 self .assertEqual (len (targets ), len (set (targets )))
475+ logger .info ("end" )
449476
450477 def test_016_dvm_run_preload_race_less (self ):
451478 """Test race requesting preloaded qube while the maximum is zeroed."""
452479 self .loop .run_until_complete (self ._test_016_dvm_run_preload_race_less ())
453480
454481 async def _test_016_dvm_run_preload_race_less (self ):
455- self .disp_base .features ["preload-dispvm-max" ] = "1"
456- for _ in range (60 ):
457- if len (self .disp_base .get_feat_preload ()) == 1 :
458- break
459- await asyncio .sleep (1 )
460- else :
461- self .fail ("didn't preload in time" )
482+ logger .info ("start" )
483+ preload_max = 1
484+ self .disp_base .features ["preload-dispvm-max" ] = str (preload_max )
485+ await self .wait_preload (preload_max , wait_pause = False )
462486 tasks = [self .run_preload_proc (), self .no_preload ()]
463487 target = await asyncio .gather (* tasks )
464488 target_dispvm = target [0 ]
465489 self .assertTrue (target_dispvm .startswith ("disp" ))
490+ logger .info ("end" )
466491
467492 def test_017_dvm_run_preload_autostart (self ):
493+ logger .info ("start" )
494+ preload_max = 1
468495 proc = self .loop .run_until_complete (
469496 asyncio .create_subprocess_exec ("/usr/lib/qubes/preload-dispvm" )
470497 )
471498 self .loop .run_until_complete (
472499 asyncio .wait_for (proc .communicate (), timeout = 10 )
473500 )
474501 self .assertEqual (self .disp_base .get_feat_preload (), [])
475- self .disp_base .features ["preload-dispvm-max" ] = "1"
476- for _ in range (10 ):
477- if len (self .disp_base .get_feat_preload ()) == 1 :
478- break
479- self .loop .run_until_complete (asyncio .sleep (1 ))
480- else :
481- self .fail ("didn't preload in time" )
502+ self .disp_base .features ["preload-dispvm-max" ] = str (preload_max )
503+ self .loop .run_until_complete (self .wait_preload (preload_max ))
482504 old_preload = self .disp_base .get_feat_preload ()
483505 proc = self .loop .run_until_complete (
484506 asyncio .create_subprocess_exec ("/usr/lib/qubes/preload-dispvm" )
485507 )
486508 self .loop .run_until_complete (asyncio .wait_for (proc .wait (), timeout = 30 ))
487509 preload_dispvm = self .disp_base .get_feat_preload ()
488- self .assertEqual (len (old_preload ), 1 )
489- self .assertEqual (len (preload_dispvm ), 1 )
510+ self .assertEqual (len (old_preload ), preload_max )
511+ self .assertEqual (len (preload_dispvm ), preload_max )
490512 self .assertTrue (
491513 set (old_preload ).isdisjoint (preload_dispvm ),
492514 f"old_preload={ old_preload } preload_dispvm={ preload_dispvm } " ,
493515 )
516+ logger .info ("end" )
494517
495518 @unittest .skipUnless (
496519 spawn .find_executable ("xdotool" ), "xdotool not installed"
0 commit comments