瀏覽代碼

Merge tag 'pull-request-2025-03-13' of https://gitlab.com/thuth/qemu into staging

* Various fixes for functional tests
* Fix the name of the "configs" directory in the documentation

# -----BEGIN PGP SIGNATURE-----
#
# iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmfSjagRHHRodXRoQHJl
# ZGhhdC5jb20ACgkQLtnXdP5wLbWBmA//RhAHuF/fTmQagBsZPETXjU1g8ifw9aqm
# WPZcQEXyQFlqYYQZmtV7dk3aTGEw4kBDmm+SKTSQz1yUcBGptMl8xuWaxgdpcOw0
# Bqt+lYNgwGL9/OocCdNolU3+aVbETljr5l+rzbnwsTVIqGk63Qhmtwdupb8h1nfY
# 4vCXU+sY3BkvBF8HbV6Wb1aPtqC+iH/Ln8+yoKkC8UePD623dK58SsOVrhUQDfFr
# U/HUy4BZlHFCfGGmDVGBjHdEbOzQkLQ9N3ilsNSWcF87RPkWPft+qLs4RjDFW+oT
# oksXEFHcr8XQO03fwHBNTyv+NUfnrvDY8V+gl6C9ItQr58SZzse57caZKWrYppZ3
# l5iHoaLMV3juZFDNXNHkWHuveXi05+0V0UbZihzBeC4+zjNRyh3e1GuDoh5VoG8o
# XIb55RxU8eBG2/ulHZ71eAYrGpxO+tDdsdnak1coPFsU8HrC9QzRfywiAZe1Wwmx
# 5t5AHbZ7RdnxgStU1lWTUT2IDVSini4DKevt/FzhKkv1aD8NbhI/ooGDC0zbS6SU
# XK6PP2G5a5OnjQ904oRCQbnhrxFa5qNfryylvvreT2bVgX0BiE4pJ9JXdgQOMYlP
# kZERZZQcv3y6VVavAT67yeNKQpyb4HSHdTDQ2irgXP1UwHRpwLpKdqB1UhzNJ8m8
# k0faA8RXir4=
# =VtGZ
# -----END PGP SIGNATURE-----
# gpg: Signature made Thu 13 Mar 2025 15:47:52 HKT
# gpg:                using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5
# gpg:                issuer "thuth@redhat.com"
# gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full]
# gpg:                 aka "Thomas Huth <thuth@redhat.com>" [full]
# gpg:                 aka "Thomas Huth <huth@tuxfamily.org>" [full]
# gpg:                 aka "Thomas Huth <th.huth@posteo.de>" [unknown]
# Primary key fingerprint: 27B8 8847 EEE0 2501 18F3  EAB9 2ED9 D774 FE70 2DB5

* tag 'pull-request-2025-03-13' of https://gitlab.com/thuth/qemu:
  tests/functional: skip vulkan test if missing vulkaninfo
  tests/functional/asset: Add AssetError exception class
  tests/functional/asset: Verify downloaded size
  tests/functional/asset: Fail assert fetch when retries are exceeded
  docs/system: Fix the information on how to run certain functional tests
  tests/functional: Bump up arm_replay timeout
  tests/functional: Require 'user' netdev for ppc64 e500 test
  docs: Rename default-configs to configs

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Stefan Hajnoczi 5 月之前
父節點
當前提交
28ea66f6f9

+ 5 - 5
docs/devel/build-system.rst

@@ -260,7 +260,7 @@ Target-dependent emulator sourcesets:
   Each emulator also includes sources for files in the ``hw/`` and ``target/``
   Each emulator also includes sources for files in the ``hw/`` and ``target/``
   subdirectories.  The subdirectory used for each emulator comes
   subdirectories.  The subdirectory used for each emulator comes
   from the target's definition of ``TARGET_BASE_ARCH`` or (if missing)
   from the target's definition of ``TARGET_BASE_ARCH`` or (if missing)
-  ``TARGET_ARCH``, as found in ``default-configs/targets/*.mak``.
+  ``TARGET_ARCH``, as found in ``configs/targets/*.mak``.
 
 
   Each subdirectory in ``hw/`` adds one sourceset to the ``hw_arch`` dictionary,
   Each subdirectory in ``hw/`` adds one sourceset to the ``hw_arch`` dictionary,
   for example::
   for example::
@@ -317,8 +317,8 @@ Utility sourcesets:
 The following files concur in the definition of which files are linked
 The following files concur in the definition of which files are linked
 into each emulator:
 into each emulator:
 
 
-``default-configs/devices/*.mak``
-  The files under ``default-configs/devices/`` control the boards and devices
+``configs/devices/*.mak``
+  The files under ``configs/devices/`` control the boards and devices
   that are built into each QEMU system emulation targets. They merely contain
   that are built into each QEMU system emulation targets. They merely contain
   a list of config variable definitions such as::
   a list of config variable definitions such as::
 
 
@@ -327,11 +327,11 @@ into each emulator:
     CONFIG_XLNX_VERSAL=y
     CONFIG_XLNX_VERSAL=y
 
 
 ``*/Kconfig``
 ``*/Kconfig``
-  These files are processed together with ``default-configs/devices/*.mak`` and
+  These files are processed together with ``configs/devices/*.mak`` and
   describe the dependencies between various features, subsystems and
   describe the dependencies between various features, subsystems and
   device models.  They are described in :ref:`kconfig`
   device models.  They are described in :ref:`kconfig`
 
 
-``default-configs/targets/*.mak``
+``configs/targets/*.mak``
   These files mostly define symbols that appear in the ``*-config-target.h``
   These files mostly define symbols that appear in the ``*-config-target.h``
   file for each emulator\ [#cfgtarget]_.  However, the ``TARGET_ARCH``
   file for each emulator\ [#cfgtarget]_.  However, the ``TARGET_ARCH``
   and ``TARGET_BASE_ARCH`` will also be used to select the ``hw/`` and
   and ``TARGET_BASE_ARCH`` will also be used to select the ``hw/`` and

+ 8 - 8
docs/devel/kconfig.rst

@@ -38,7 +38,7 @@ originated in the Linux kernel, though it was heavily simplified and
 the handling of dependencies is stricter in QEMU.
 the handling of dependencies is stricter in QEMU.
 
 
 Unlike Linux, there is no user interface to edit the configuration, which
 Unlike Linux, there is no user interface to edit the configuration, which
-is instead specified in per-target files under the ``default-configs/``
+is instead specified in per-target files under the ``configs/``
 directory of the QEMU source tree.  This is because, unlike Linux,
 directory of the QEMU source tree.  This is because, unlike Linux,
 configuration and dependencies can be treated as a black box when building
 configuration and dependencies can be treated as a black box when building
 QEMU; the default configuration that QEMU ships with should be okay in
 QEMU; the default configuration that QEMU ships with should be okay in
@@ -103,7 +103,7 @@ directives can be included:
 **default value**: ``default <value> [if <expr>]``
 **default value**: ``default <value> [if <expr>]``
 
 
   Default values are assigned to the config symbol if no other value was
   Default values are assigned to the config symbol if no other value was
-  set by the user via ``default-configs/*.mak`` files, and only if
+  set by the user via ``configs/*.mak`` files, and only if
   ``select`` or ``depends on`` directives do not force the value to true
   ``select`` or ``depends on`` directives do not force the value to true
   or false respectively.  ``<value>`` can be ``y`` or ``n``; it cannot
   or false respectively.  ``<value>`` can be ``y`` or ``n``; it cannot
   be an arbitrary Boolean expression.  However, a condition for applying
   be an arbitrary Boolean expression.  However, a condition for applying
@@ -119,7 +119,7 @@ directives can be included:
   This is similar to ``select`` as it applies a lower limit of ``y``
   This is similar to ``select`` as it applies a lower limit of ``y``
   to another symbol.  However, the lower limit is only a default
   to another symbol.  However, the lower limit is only a default
   and the "implied" symbol's value may still be set to ``n`` from a
   and the "implied" symbol's value may still be set to ``n`` from a
-  ``default-configs/*.mak`` files.  The following two examples are
+  ``configs/*.mak`` files.  The following two examples are
   equivalent::
   equivalent::
 
 
     config FOO
     config FOO
@@ -146,7 +146,7 @@ declares its dependencies in different ways:
       bool
       bool
 
 
   Subsystems always default to false (they have no ``default`` directive)
   Subsystems always default to false (they have no ``default`` directive)
-  and are never visible in ``default-configs/*.mak`` files.  It's
+  and are never visible in ``configs/*.mak`` files.  It's
   up to other symbols to ``select`` whatever subsystems they require.
   up to other symbols to ``select`` whatever subsystems they require.
 
 
   They sometimes have ``select`` directives to bring in other required
   They sometimes have ``select`` directives to bring in other required
@@ -238,7 +238,7 @@ declares its dependencies in different ways:
   include libraries (such as ``FDT``) or ``TARGET_BIG_ENDIAN``
   include libraries (such as ``FDT``) or ``TARGET_BIG_ENDIAN``
   (possibly negated).
   (possibly negated).
 
 
-  Boards are listed for convenience in the ``default-configs/*.mak``
+  Boards are listed for convenience in the ``configs/*.mak``
   for the target they apply to.
   for the target they apply to.
 
 
 **internal elements**
 **internal elements**
@@ -251,18 +251,18 @@ declares its dependencies in different ways:
 
 
   Internal elements group code that is useful in several boards or
   Internal elements group code that is useful in several boards or
   devices.  They are usually enabled with ``select`` and in turn select
   devices.  They are usually enabled with ``select`` and in turn select
-  other elements; they are never visible in ``default-configs/*.mak``
+  other elements; they are never visible in ``configs/*.mak``
   files, and often not even in the Makefile.
   files, and often not even in the Makefile.
 
 
 Writing and modifying default configurations
 Writing and modifying default configurations
 --------------------------------------------
 --------------------------------------------
 
 
 In addition to the Kconfig files under hw/, each target also includes
 In addition to the Kconfig files under hw/, each target also includes
-a file called ``default-configs/TARGETNAME-softmmu.mak``.  These files
+a file called ``configs/TARGETNAME-softmmu.mak``.  These files
 initialize some Kconfig variables to non-default values and provide the
 initialize some Kconfig variables to non-default values and provide the
 starting point to turn on devices and subsystems.
 starting point to turn on devices and subsystems.
 
 
-A file in ``default-configs/`` looks like the following example::
+A file in ``configs/`` looks like the following example::
 
 
     # Default configuration for alpha-softmmu
     # Default configuration for alpha-softmmu
 
 

+ 2 - 3
docs/system/arm/bananapi_m2u.rst

@@ -135,6 +135,5 @@ provide the following command:
 .. code-block:: bash
 .. code-block:: bash
 
 
   $ cd qemu-build-dir
   $ cd qemu-build-dir
-  $ AVOCADO_ALLOW_LARGE_STORAGE=yes tests/venv/bin/avocado \
-    --verbose --show=app,console run -t machine:bpim2u \
-    ../tests/avocado/boot_linux_console.py
+  $ QEMU_TEST_ALLOW_LARGE_STORAGE=1 \
+    meson test --suite thorough func-arm-arm_bpim2u

+ 3 - 3
docs/system/arm/orangepi.rst

@@ -257,9 +257,9 @@ Orange Pi PC integration tests
 
 
 The Orange Pi PC machine has several integration tests included.
 The Orange Pi PC machine has several integration tests included.
 To run the whole set of tests, build QEMU from source and simply
 To run the whole set of tests, build QEMU from source and simply
-provide the following command:
+provide the following command from the build directory:
 
 
 .. code-block:: bash
 .. code-block:: bash
 
 
-  $ AVOCADO_ALLOW_LARGE_STORAGE=yes avocado --show=app,console run \
-     -t machine:orangepi-pc tests/avocado/boot_linux_console.py
+  $ QEMU_TEST_ALLOW_LARGE_STORAGE=1 \
+    meson test --suite thorough func-arm-arm_orangepi

+ 2 - 2
docs/system/devices/igb.rst

@@ -57,11 +57,11 @@ directory:
   meson test qtest-x86_64/qos-test
   meson test qtest-x86_64/qos-test
 
 
 ethtool can test register accesses, interrupts, etc. It is automated as an
 ethtool can test register accesses, interrupts, etc. It is automated as an
-Avocado test and can be ran with the following command:
+functional test and can be ran with the following command:
 
 
 .. code:: shell
 .. code:: shell
 
 
-  make check-avocado AVOCADO_TESTS=tests/avocado/netdev-ethtool.py
+  meson test --suite thorough func-x86_64-netdev_ethtool
 
 
 References
 References
 ==========
 ==========

+ 1 - 0
tests/functional/meson.build

@@ -34,6 +34,7 @@ test_timeouts = {
   'arm_orangepi' : 540,
   'arm_orangepi' : 540,
   'arm_quanta_gsj' : 240,
   'arm_quanta_gsj' : 240,
   'arm_raspi2' : 120,
   'arm_raspi2' : 120,
+  'arm_replay' : 240,
   'arm_tuxrun' : 240,
   'arm_tuxrun' : 240,
   'arm_sx1' : 360,
   'arm_sx1' : 360,
   'intel_iommu': 300,
   'intel_iommu': 300,

+ 44 - 14
tests/functional/qemu_test/asset.py

@@ -17,6 +17,14 @@
 from shutil import copyfileobj
 from shutil import copyfileobj
 from urllib.error import HTTPError
 from urllib.error import HTTPError
 
 
+class AssetError(Exception):
+    def __init__(self, asset, msg, transient=False):
+        self.url = asset.url
+        self.msg = msg
+        self.transient = transient
+
+    def __str__(self):
+        return "%s: %s" % (self.url, self.msg)
 
 
 # Instances of this class must be declared as class level variables
 # Instances of this class must be declared as class level variables
 # starting with a name "ASSET_". This enables the pre-caching logic
 # starting with a name "ASSET_". This enables the pre-caching logic
@@ -51,7 +59,7 @@ def _check(self, cache_file):
         elif len(self.hash) == 128:
         elif len(self.hash) == 128:
             hl = hashlib.sha512()
             hl = hashlib.sha512()
         else:
         else:
-            raise Exception("unknown hash type")
+            raise AssetError(self, "unknown hash type")
 
 
         # Calculate the hash of the file:
         # Calculate the hash of the file:
         with open(cache_file, 'rb') as file:
         with open(cache_file, 'rb') as file:
@@ -111,7 +119,8 @@ def fetch(self):
             return str(self.cache_file)
             return str(self.cache_file)
 
 
         if not self.fetchable():
         if not self.fetchable():
-            raise Exception("Asset cache is invalid and downloads disabled")
+            raise AssetError(self,
+                             "Asset cache is invalid and downloads disabled")
 
 
         self.log.info("Downloading %s to %s...", self.url, self.cache_file)
         self.log.info("Downloading %s to %s...", self.url, self.cache_file)
         tmp_cache_file = self.cache_file.with_suffix(".download")
         tmp_cache_file = self.cache_file.with_suffix(".download")
@@ -121,6 +130,20 @@ def fetch(self):
                 with tmp_cache_file.open("xb") as dst:
                 with tmp_cache_file.open("xb") as dst:
                     with urllib.request.urlopen(self.url) as resp:
                     with urllib.request.urlopen(self.url) as resp:
                         copyfileobj(resp, dst)
                         copyfileobj(resp, dst)
+                        length_hdr = resp.getheader("Content-Length")
+
+                # Verify downloaded file size against length metadata, if
+                # available.
+                if length_hdr is not None:
+                    length = int(length_hdr)
+                    fsize = tmp_cache_file.stat().st_size
+                    if fsize != length:
+                        self.log.error("Unable to download %s: "
+                                       "connection closed before "
+                                       "transfer complete (%d/%d)",
+                                       self.url, fsize, length)
+                        tmp_cache_file.unlink()
+                        continue
                 break
                 break
             except FileExistsError:
             except FileExistsError:
                 self.log.debug("%s already exists, "
                 self.log.debug("%s already exists, "
@@ -133,10 +156,23 @@ def fetch(self):
                                tmp_cache_file)
                                tmp_cache_file)
                 tmp_cache_file.unlink()
                 tmp_cache_file.unlink()
                 continue
                 continue
+            except HTTPError as e:
+                tmp_cache_file.unlink()
+                self.log.error("Unable to download %s: HTTP error %d",
+                               self.url, e.code)
+                # Treat 404 as fatal, since it is highly likely to
+                # indicate a broken test rather than a transient
+                # server or networking problem
+                if e.code == 404:
+                    raise AssetError(self, "Unable to download: "
+                                     "HTTP error %d" % e.code)
+                continue
             except Exception as e:
             except Exception as e:
-                self.log.error("Unable to download %s: %s", self.url, e)
                 tmp_cache_file.unlink()
                 tmp_cache_file.unlink()
-                raise
+                raise AssetError(self, "Unable to download: " % e)
+
+        if not os.path.exists(tmp_cache_file):
+            raise AssetError(self, "Download retries exceeded", transient=True)
 
 
         try:
         try:
             # Set these just for informational purposes
             # Set these just for informational purposes
@@ -150,8 +186,7 @@ def fetch(self):
 
 
         if not self._check(tmp_cache_file):
         if not self._check(tmp_cache_file):
             tmp_cache_file.unlink()
             tmp_cache_file.unlink()
-            raise Exception("Hash of %s does not match %s" %
-                            (self.url, self.hash))
+            raise AssetError(self, "Hash does not match %s" % self.hash)
         tmp_cache_file.replace(self.cache_file)
         tmp_cache_file.replace(self.cache_file)
         # Remove write perms to stop tests accidentally modifying them
         # Remove write perms to stop tests accidentally modifying them
         os.chmod(self.cache_file, stat.S_IRUSR | stat.S_IRGRP)
         os.chmod(self.cache_file, stat.S_IRUSR | stat.S_IRGRP)
@@ -173,15 +208,10 @@ def precache_test(test):
                 log.info("Attempting to cache '%s'" % asset)
                 log.info("Attempting to cache '%s'" % asset)
                 try:
                 try:
                     asset.fetch()
                     asset.fetch()
-                except HTTPError as e:
-                    # Treat 404 as fatal, since it is highly likely to
-                    # indicate a broken test rather than a transient
-                    # server or networking problem
-                    if e.code == 404:
+                except AssetError as e:
+                    if not e.transient:
                         raise
                         raise
-
-                    log.debug(f"HTTP error {e.code} from {asset.url} " +
-                              "skipping asset precache")
+                    log.error("%s: skipping asset precache" % e)
 
 
         log.removeHandler(handler)
         log.removeHandler(handler)
 
 

+ 1 - 0
tests/functional/test_aarch64_virt_gpu.py

@@ -115,6 +115,7 @@ def test_aarch64_virt_with_virgl_blobs_gpu(self):
         self._run_virt_weston_test("glmark2-wayland -b:duration=1.0")
         self._run_virt_weston_test("glmark2-wayland -b:duration=1.0")
 
 
     @skipIfMissingCommands('zstd')
     @skipIfMissingCommands('zstd')
+    @skipIfMissingCommands('vulkaninfo')
     def test_aarch64_virt_with_vulkan_gpu(self):
     def test_aarch64_virt_with_vulkan_gpu(self):
 
 
         self.require_device('virtio-gpu-gl-pci')
         self.require_device('virtio-gpu-gl-pci')

+ 1 - 0
tests/functional/test_ppc64_e500.py

@@ -20,6 +20,7 @@ class E500Test(LinuxKernelTest):
 
 
     def test_ppc64_e500_buildroot(self):
     def test_ppc64_e500_buildroot(self):
         self.set_machine('ppce500')
         self.set_machine('ppce500')
+        self.require_netdev('user')
         self.cpu = 'e5500'
         self.cpu = 'e5500'
 
 
         uimage_path = self.ASSET_BR2_E5500_UIMAGE.fetch()
         uimage_path = self.ASSET_BR2_E5500_UIMAGE.fetch()