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