1# SPDX-License-Identifier: GPL-2.0-or-later 2# 3# Decorators useful in functional tests 4 5import importlib 6import os 7import platform 8import resource 9from unittest import skipIf, skipUnless 10 11from .cmd import which 12 13''' 14Decorator to skip execution of a test if the list 15of command binaries is not available in $PATH. 16Example: 17 18 @skipIfMissingCommands("mkisofs", "losetup") 19''' 20def skipIfMissingCommands(*args): 21 has_cmds = True 22 for cmd in args: 23 if not which(cmd): 24 has_cmds = False 25 break 26 27 return skipUnless(has_cmds, 'required command(s) "%s" not installed' % 28 ", ".join(args)) 29 30''' 31Decorator to skip execution of a test if the current 32host operating system does match one of the prohibited 33ones. 34Example 35 36 @skipIfOperatingSystem("Linux", "Darwin") 37''' 38def skipIfOperatingSystem(*args): 39 return skipIf(platform.system() in args, 40 'running on an OS (%s) that is not able to run this test' % 41 ", ".join(args)) 42 43''' 44Decorator to skip execution of a test if the current 45host machine does not match one of the permitted 46machines. 47Example 48 49 @skipIfNotMachine("x86_64", "aarch64") 50''' 51def skipIfNotMachine(*args): 52 return skipUnless(platform.machine() in args, 53 'not running on one of the required machine(s) "%s"' % 54 ", ".join(args)) 55 56''' 57Decorator to skip execution of flaky tests, unless 58the $QEMU_TEST_FLAKY_TESTS environment variable is set. 59A bug URL must be provided that documents the observed 60failure behaviour, so it can be tracked & re-evaluated 61in future. 62 63Historical tests may be providing "None" as the bug_url 64but this should not be done for new test. 65 66Example: 67 68 @skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/NNN") 69''' 70def skipFlakyTest(bug_url): 71 if bug_url is None: 72 bug_url = "FIXME: reproduce flaky test and file bug report or remove" 73 return skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 74 f'Test is unstable: {bug_url}') 75 76''' 77Decorator to skip execution of tests which are likely 78to execute untrusted commands on the host, or commands 79which process untrusted code, unless the 80$QEMU_TEST_ALLOW_UNTRUSTED_CODE env var is set. 81Example: 82 83 @skipUntrustedTest() 84''' 85def skipUntrustedTest(): 86 return skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'), 87 'Test runs untrusted code / processes untrusted data') 88 89''' 90Decorator to skip execution of tests which need large 91data storage (over around 500MB-1GB mark) on the host, 92unless the $QEMU_TEST_ALLOW_LARGE_STORAGE environment 93variable is set 94 95Example: 96 97 @skipBigDataTest() 98''' 99def skipBigDataTest(): 100 return skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'), 101 'Test requires large host storage space') 102 103''' 104Decorator to skip execution of tests which have a really long 105runtime (and might e.g. time out if QEMU has been compiled with 106debugging enabled) unless the $QEMU_TEST_ALLOW_SLOW 107environment variable is set 108 109Example: 110 111 @skipSlowTest() 112''' 113def skipSlowTest(): 114 return skipUnless(os.getenv('QEMU_TEST_ALLOW_SLOW'), 115 'Test has a very long runtime and might time out') 116 117''' 118Decorator to skip execution of a test if the list 119of python imports is not available. 120Example: 121 122 @skipIfMissingImports("numpy", "cv2") 123''' 124def skipIfMissingImports(*args): 125 has_imports = True 126 for impname in args: 127 try: 128 importlib.import_module(impname) 129 except ImportError: 130 has_imports = False 131 break 132 133 return skipUnless(has_imports, 'required import(s) "%s" not installed' % 134 ", ".join(args)) 135 136''' 137Decorator to skip execution of a test if the system's 138locked memory limit is below the required threshold. 139Takes required locked memory threshold in kB. 140Example: 141 142 @skipLockedMemoryTest(2_097_152) 143''' 144def skipLockedMemoryTest(locked_memory): 145 # get memlock hard limit in bytes 146 _, ulimit_memory = resource.getrlimit(resource.RLIMIT_MEMLOCK) 147 148 return skipUnless( 149 ulimit_memory == resource.RLIM_INFINITY or ulimit_memory >= locked_memory * 1024, 150 f'Test required {locked_memory} kB of available locked memory', 151 ) 152