File tree Expand file tree Collapse file tree 5 files changed +91
-1
lines changed
docs/source/guides/writer/chapters Expand file tree Collapse file tree 5 files changed +91
-1
lines changed Original file line number Diff line number Diff line change 2424import logging
2525import os
2626import shutil
27+ import signal
2728import sys
2829import tempfile
30+ import threading
2931import time
3032import unittest
3133import warnings
34+ from contextlib import contextmanager
3235
3336from avocado .core import exceptions , parameters
3437from avocado .core .settings import settings
@@ -514,6 +517,29 @@ def phase(self):
514517 """
515518 return self .__phase
516519
520+ @contextmanager
521+ def wait_max (self , timeout ):
522+ """
523+ Context manager for getting block of code with its specific timeout.
524+
525+ Usage:
526+ with self.wait_max(3):
527+ # code which should take max 3 seconds
528+ ...
529+
530+ :param timeout: Timeout in seconds for block of code.
531+ :type timeout: int
532+ """
533+
534+ def raise_timeout ():
535+ os .kill (os .getpid (), signal .SIGTERM )
536+
537+ timeout = timeout * self .params .get ("timeout_factor" , default = 1.0 )
538+ alarm = threading .Timer (timeout , raise_timeout )
539+ alarm .start ()
540+ yield timeout
541+ alarm .cancel ()
542+
517543 def __str__ (self ):
518544 return str (self .name )
519545
Original file line number Diff line number Diff line change @@ -773,6 +773,19 @@ runner task, making it raise a
773773process is specific to spawner implementation, for more information
774774see :class :`avocado.core.plugin_interfaces.Spawner.terminate_task` .
775775
776+
777+ Block Timeout
778+ ------------ -
779+ On more complex (and thus usually) longer tests, there may be multiple
780+ steps to complete. It may be known that some of these steps should not
781+ take more than a small percentage of the overall expected time for the
782+ test as a whole. Therefore, it is not convenient to set the timeout for
783+ the whole test, but it would be better to have timeout for each of those
784+ steps. For such use- case avocado supports `wait_max` context manager,
785+ which let you set specific timeout (in seconds) for a block of code:
786+
787+ .. literalinclude:: ../ ../ ../ ../ ../ examples/ tests/ blocktimeouttest.py
788+
776789Timeout Factor
777790~~~~~~~~~~~~~~
778791
@@ -810,6 +823,9 @@ test logs. For the previous test execution it shows::
810823 ...
811824 [stdlog] 2023 - 11 - 29 11 :16 :23 ,746 test L0354 DEBUG | actual timeout: 6.0
812825
826+
827+ .. note:: Be aweare that timeout factor will also affect timeouts created by `wait_max` context manager.
828+
813829Skipping Tests
814830--------------
815831
Original file line number Diff line number Diff line change 1+ import time
2+
3+ from avocado import Test
4+
5+
6+ class TimeoutTest (Test ):
7+ """
8+ Functional test for avocado. Throw a TestTimeoutError.
9+
10+ :param sleep_time: How long should the test sleep
11+ """
12+
13+ def test (self ):
14+ """
15+ This should throw a TestTimeoutError.
16+ """
17+ with self .wait_max (3 ):
18+ sleep_time = float (self .params .get ("sleep_time" , default = 5.0 ))
19+ self .log .info (
20+ "Sleeping for %.2f seconds (2 more than the timeout)" , sleep_time
21+ )
22+ time .sleep (sleep_time )
Original file line number Diff line number Diff line change 2929 "nrunner-requirement" : 28 ,
3030 "unit" : 678 ,
3131 "jobs" : 11 ,
32- "functional-parallel" : 309 ,
32+ "functional-parallel" : 310 ,
3333 "functional-serial" : 7 ,
3434 "optional-plugins" : 0 ,
3535 "optional-plugins-golang" : 2 ,
Original file line number Diff line number Diff line change @@ -543,6 +543,32 @@ def test_runner_timeout(self):
543543 # Ensure no test aborted error messages show up
544544 self .assertNotIn (b"TestAbortError: Test aborted unexpectedly" , output )
545545
546+ def test_runner_block_timeout (self ):
547+ cmd_line = (
548+ f"{ AVOCADO } run --disable-sysinfo --job-results-dir "
549+ f"{ self .tmpdir .name } examples/tests/blocktimeouttest.py"
550+ )
551+ result = process .run (cmd_line , ignore_status = True )
552+ json_path = os .path .join (self .tmpdir .name , "latest" , "results.json" )
553+ with open (json_path , encoding = "utf-8" ) as json_file :
554+ result_json = json .load (json_file )
555+ output = result .stdout
556+ expected_rc = exit_codes .AVOCADO_JOB_INTERRUPTED
557+ unexpected_rc = exit_codes .AVOCADO_FAIL
558+ self .assertNotEqual (
559+ result .exit_status ,
560+ unexpected_rc ,
561+ f"Avocado crashed (rc { unexpected_rc } ):\n { result } " ,
562+ )
563+ self .assertEqual (
564+ result .exit_status ,
565+ expected_rc ,
566+ f"Avocado did not return rc { expected_rc } :\n { result } " ,
567+ )
568+ self .assertIn ("Timeout reached" , result_json ["tests" ][0 ]["fail_reason" ])
569+ # Ensure no test aborted error messages show up
570+ self .assertNotIn (b"TestAbortError: Test aborted unexpectedly" , output )
571+
546572 def test_runner_timeout_factor (self ):
547573 cmd_line = (
548574 f"{ AVOCADO } run --disable-sysinfo --job-results-dir "
You can’t perform that action at this time.
0 commit comments