decorators.py 3.6 KB

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