mirror of https://github.com/xemu-project/xemu.git
* Minor clean-ups and fixes for the qtests and Avocado tests
* Fix crash that happens when introspecting scsi-block on older machine types * s390x: filter deprecated properties based on model expansion type -----BEGIN PGP SIGNATURE----- iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmaeSUMRHHRodXRoQHJl ZGhhdC5jb20ACgkQLtnXdP5wLbVdQw/8DvGymXKwpS0F2aSHg3AZvjSCpkv3Y+fK myQrzh30cv9Vhe/Y9do47HpfJ6Ug9SK6xG64K2o+BIW+G3+ZUwSHk24PoiALsrJf 9qqya1upBJkEC5B4PhqRPS3GlbvBnKKEk8W6BMpUa2BToFV9MsG256cBVhUrRpGc 6u80DgTNxCI1czsNkWVGJAt1oVLYYJIjz7UZ4VbZCH48o6r0iSUV6C01wccOFmNy IXbspyyUftWFh9lO0i8PiYlXG2YEAmFry3gqD5vc+6BsFT4lMeoRFFxbVCddGKFc iNwlH4ayjeISlEJeClImIdbHyZ+sDhPyy5x4cpQqmZudEPn+GVnZ0arm7OvXW/k8 Yog4n7/cUz7GHnWbqYIFZMS1g1wmqm/9VPsVTzXAlTva4dTTs2p0tKAADHIAtPCI jxSPpbuCuukDzUZGsNZyRGbex6g4B0tP4TMHRFxo5LVy9dKn2BLOHBWuzPevD9OO FphZHUuGngcPi4GSFmlv7aCS0pqyWsCO+5EqoYUgO8yadyfiXN9pwjB6OnBZux0U kbJOkkBJwEalhsiHmPFMnS8rkWa4Ye4ZJjj8XHRiecxSZOcNOcxyE+l2x8CV2aFB UBR83nm86vXXpu86Yod3E+txDEUzKN5+B8X0q7Se0YvsWbB+1Dq/Co0Bdh/Wp70E EPk5eqaSp8k= =zB5F -----END PGP SIGNATURE----- Merge tag 'pull-request-2024-07-22' of https://gitlab.com/thuth/qemu into staging * Minor clean-ups and fixes for the qtests and Avocado tests * Fix crash that happens when introspecting scsi-block on older machine types * s390x: filter deprecated properties based on model expansion type # -----BEGIN PGP SIGNATURE----- # # iQJFBAABCAAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmaeSUMRHHRodXRoQHJl # ZGhhdC5jb20ACgkQLtnXdP5wLbVdQw/8DvGymXKwpS0F2aSHg3AZvjSCpkv3Y+fK # myQrzh30cv9Vhe/Y9do47HpfJ6Ug9SK6xG64K2o+BIW+G3+ZUwSHk24PoiALsrJf # 9qqya1upBJkEC5B4PhqRPS3GlbvBnKKEk8W6BMpUa2BToFV9MsG256cBVhUrRpGc # 6u80DgTNxCI1czsNkWVGJAt1oVLYYJIjz7UZ4VbZCH48o6r0iSUV6C01wccOFmNy # IXbspyyUftWFh9lO0i8PiYlXG2YEAmFry3gqD5vc+6BsFT4lMeoRFFxbVCddGKFc # iNwlH4ayjeISlEJeClImIdbHyZ+sDhPyy5x4cpQqmZudEPn+GVnZ0arm7OvXW/k8 # Yog4n7/cUz7GHnWbqYIFZMS1g1wmqm/9VPsVTzXAlTva4dTTs2p0tKAADHIAtPCI # jxSPpbuCuukDzUZGsNZyRGbex6g4B0tP4TMHRFxo5LVy9dKn2BLOHBWuzPevD9OO # FphZHUuGngcPi4GSFmlv7aCS0pqyWsCO+5EqoYUgO8yadyfiXN9pwjB6OnBZux0U # kbJOkkBJwEalhsiHmPFMnS8rkWa4Ye4ZJjj8XHRiecxSZOcNOcxyE+l2x8CV2aFB # UBR83nm86vXXpu86Yod3E+txDEUzKN5+B8X0q7Se0YvsWbB+1Dq/Co0Bdh/Wp70E # EPk5eqaSp8k= # =zB5F # -----END PGP SIGNATURE----- # gpg: Signature made Mon 22 Jul 2024 09:57:55 PM AEST # 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 <th.huth@posteo.de>" [unknown] # gpg: aka "Thomas Huth <huth@tuxfamily.org>" [full] * tag 'pull-request-2024-07-22' of https://gitlab.com/thuth/qemu: target/s390x: filter deprecated properties based on model expansion type tests: increase timeout per instance of bios-tables-test qtest/fuzz: make range overlap check more readable hw: Fix crash that happens when introspecting scsi-block on older machine types tests/avocado/machine_aspeed.py: Increase timeout for TPM test tests/avocado: Remove the remainders of the virtiofs_submounts test tests/avocado/mem-addr-space-check: Remove unused "import signal" tests/avocado: Move LinuxTest related code into a separate file tests/avocado: Allow overwriting AVOCADO_SHOW env variable tests/avocado/boot_xen.py: use class attribute tests/avocado/boot_xen.py: unify tags tests/avocado/boot_xen.py: merge base classes Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
d92cf77b79
|
@ -36,7 +36,8 @@
|
||||||
|
|
||||||
GlobalProperty hw_compat_9_0[] = {
|
GlobalProperty hw_compat_9_0[] = {
|
||||||
{"arm-cpu", "backcompat-cntfrq", "true" },
|
{"arm-cpu", "backcompat-cntfrq", "true" },
|
||||||
{"scsi-disk-base", "migrate-emulated-scsi-request", "false" },
|
{ "scsi-hd", "migrate-emulated-scsi-request", "false" },
|
||||||
|
{ "scsi-cd", "migrate-emulated-scsi-request", "false" },
|
||||||
{"vfio-pci", "skip-vsc-check", "false" },
|
{"vfio-pci", "skip-vsc-check", "false" },
|
||||||
{ "virtio-pci", "x-pcie-pm-no-soft-reset", "off" },
|
{ "virtio-pci", "x-pcie-pm-no-soft-reset", "off" },
|
||||||
{"sd-card", "spec_version", "2" },
|
{"sd-card", "spec_version", "2" },
|
||||||
|
|
|
@ -21,8 +21,9 @@
|
||||||
# @props: a dictionary of QOM properties to be applied
|
# @props: a dictionary of QOM properties to be applied
|
||||||
#
|
#
|
||||||
# @deprecated-props: a list of properties that are flagged as deprecated
|
# @deprecated-props: a list of properties that are flagged as deprecated
|
||||||
# by the CPU vendor. These props are a subset of the full model's
|
# by the CPU vendor. These properties are either a subset of the
|
||||||
# definition list of properties. (since 9.1)
|
# properties enabled on the CPU model, or a set of properties
|
||||||
|
# deprecated across all models for the architecture.
|
||||||
#
|
#
|
||||||
# Since: 2.8
|
# Since: 2.8
|
||||||
##
|
##
|
||||||
|
|
|
@ -174,11 +174,15 @@ static void cpu_info_from_model(CpuModelInfo *info, const S390CPUModel *model,
|
||||||
bool delta_changes)
|
bool delta_changes)
|
||||||
{
|
{
|
||||||
QDict *qdict = qdict_new();
|
QDict *qdict = qdict_new();
|
||||||
S390FeatBitmap bitmap;
|
S390FeatBitmap bitmap, deprecated;
|
||||||
|
|
||||||
/* always fallback to the static base model */
|
/* always fallback to the static base model */
|
||||||
info->name = g_strdup_printf("%s-base", model->def->name);
|
info->name = g_strdup_printf("%s-base", model->def->name);
|
||||||
|
|
||||||
|
/* features flagged as deprecated */
|
||||||
|
bitmap_zero(deprecated, S390_FEAT_MAX);
|
||||||
|
s390_get_deprecated_features(deprecated);
|
||||||
|
|
||||||
if (delta_changes) {
|
if (delta_changes) {
|
||||||
/* features deleted from the base feature set */
|
/* features deleted from the base feature set */
|
||||||
bitmap_andnot(bitmap, model->def->base_feat, model->features,
|
bitmap_andnot(bitmap, model->def->base_feat, model->features,
|
||||||
|
@ -193,6 +197,9 @@ static void cpu_info_from_model(CpuModelInfo *info, const S390CPUModel *model,
|
||||||
if (!bitmap_empty(bitmap, S390_FEAT_MAX)) {
|
if (!bitmap_empty(bitmap, S390_FEAT_MAX)) {
|
||||||
s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_enabled_feat);
|
s390_feat_bitmap_to_ascii(bitmap, qdict, qdict_add_enabled_feat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* deprecated features that are a subset of the model's enabled features */
|
||||||
|
bitmap_and(deprecated, deprecated, model->features, S390_FEAT_MAX);
|
||||||
} else {
|
} else {
|
||||||
/* expand all features */
|
/* expand all features */
|
||||||
s390_feat_bitmap_to_ascii(model->features, qdict,
|
s390_feat_bitmap_to_ascii(model->features, qdict,
|
||||||
|
@ -207,12 +214,7 @@ static void cpu_info_from_model(CpuModelInfo *info, const S390CPUModel *model,
|
||||||
info->props = QOBJECT(qdict);
|
info->props = QOBJECT(qdict);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* features flagged as deprecated */
|
s390_feat_bitmap_to_ascii(deprecated, &info->deprecated_props, list_add_feat);
|
||||||
bitmap_zero(bitmap, S390_FEAT_MAX);
|
|
||||||
s390_get_deprecated_features(bitmap);
|
|
||||||
|
|
||||||
bitmap_and(bitmap, bitmap, model->def->full_feat, S390_FEAT_MAX);
|
|
||||||
s390_feat_bitmap_to_ascii(bitmap, &info->deprecated_props, list_add_feat);
|
|
||||||
info->has_deprecated_props = !!info->deprecated_props;
|
info->has_deprecated_props = !!info->deprecated_props;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ endif
|
||||||
# Controls the output generated by Avocado when running tests.
|
# Controls the output generated by Avocado when running tests.
|
||||||
# Any number of command separated loggers are accepted. For more
|
# Any number of command separated loggers are accepted. For more
|
||||||
# information please refer to "avocado --help".
|
# information please refer to "avocado --help".
|
||||||
AVOCADO_SHOW=app
|
AVOCADO_SHOW?=app
|
||||||
ifndef AVOCADO_TAGS
|
ifndef AVOCADO_TAGS
|
||||||
AVOCADO_CMDLINE_TAGS=$(patsubst %-softmmu,-t arch:%, \
|
AVOCADO_CMDLINE_TAGS=$(patsubst %-softmmu,-t arch:%, \
|
||||||
$(filter %-softmmu,$(TARGETS)))
|
$(filter %-softmmu,$(TARGETS)))
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import shutil
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
@ -18,7 +17,7 @@ import time
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
import avocado
|
import avocado
|
||||||
from avocado.utils import cloudinit, datadrainer, process, ssh, vmimage
|
from avocado.utils import ssh
|
||||||
from avocado.utils.path import find_command
|
from avocado.utils.path import find_command
|
||||||
|
|
||||||
from qemu.machine import QEMUMachine
|
from qemu.machine import QEMUMachine
|
||||||
|
@ -32,14 +31,6 @@ from qemu.utils import (get_info_usernet_hostfwd_port, kvm_available,
|
||||||
#: and build tree, it will not be accurate.
|
#: and build tree, it will not be accurate.
|
||||||
BUILD_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
BUILD_DIR = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
|
||||||
|
|
||||||
if os.path.islink(os.path.dirname(os.path.dirname(__file__))):
|
|
||||||
# The link to the avocado tests dir in the source code directory
|
|
||||||
lnk = os.path.dirname(os.path.dirname(__file__))
|
|
||||||
#: The QEMU root source directory
|
|
||||||
SOURCE_DIR = os.path.dirname(os.path.dirname(os.readlink(lnk)))
|
|
||||||
else:
|
|
||||||
SOURCE_DIR = BUILD_DIR
|
|
||||||
|
|
||||||
|
|
||||||
def has_cmd(name, args=None):
|
def has_cmd(name, args=None):
|
||||||
"""
|
"""
|
||||||
|
@ -451,231 +442,3 @@ class LinuxSSHMixIn:
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
self.fail('"%s" output does not contain "%s"' % (cmd, exp))
|
self.fail('"%s" output does not contain "%s"' % (cmd, exp))
|
||||||
|
|
||||||
class LinuxDistro:
|
|
||||||
"""Represents a Linux distribution
|
|
||||||
|
|
||||||
Holds information of known distros.
|
|
||||||
"""
|
|
||||||
#: A collection of known distros and their respective image checksum
|
|
||||||
KNOWN_DISTROS = {
|
|
||||||
'fedora': {
|
|
||||||
'31': {
|
|
||||||
'x86_64':
|
|
||||||
{'checksum': ('e3c1b309d9203604922d6e255c2c5d09'
|
|
||||||
'8a309c2d46215d8fc026954f3c5c27a0'),
|
|
||||||
'pxeboot_url': ('https://archives.fedoraproject.org/'
|
|
||||||
'pub/archive/fedora/linux/releases/31/'
|
|
||||||
'Everything/x86_64/os/images/pxeboot/'),
|
|
||||||
'kernel_params': ('root=UUID=b1438b9b-2cab-4065-a99a-'
|
|
||||||
'08a96687f73c ro no_timer_check '
|
|
||||||
'net.ifnames=0 console=tty1 '
|
|
||||||
'console=ttyS0,115200n8'),
|
|
||||||
},
|
|
||||||
'aarch64':
|
|
||||||
{'checksum': ('1e18d9c0cf734940c4b5d5ec592facae'
|
|
||||||
'd2af0ad0329383d5639c997fdf16fe49'),
|
|
||||||
'pxeboot_url': 'https://archives.fedoraproject.org/'
|
|
||||||
'pub/archive/fedora/linux/releases/31/'
|
|
||||||
'Everything/aarch64/os/images/pxeboot/',
|
|
||||||
'kernel_params': ('root=UUID=b6950a44-9f3c-4076-a9c2-'
|
|
||||||
'355e8475b0a7 ro earlyprintk=pl011,0x9000000'
|
|
||||||
' ignore_loglevel no_timer_check'
|
|
||||||
' printk.time=1 rd_NO_PLYMOUTH'
|
|
||||||
' console=ttyAMA0'),
|
|
||||||
},
|
|
||||||
'ppc64':
|
|
||||||
{'checksum': ('7c3528b85a3df4b2306e892199a9e1e4'
|
|
||||||
'3f991c506f2cc390dc4efa2026ad2f58')},
|
|
||||||
's390x':
|
|
||||||
{'checksum': ('4caaab5a434fd4d1079149a072fdc789'
|
|
||||||
'1e354f834d355069ca982fdcaf5a122d')},
|
|
||||||
},
|
|
||||||
'32': {
|
|
||||||
'aarch64':
|
|
||||||
{'checksum': ('b367755c664a2d7a26955bbfff985855'
|
|
||||||
'adfa2ca15e908baf15b4b176d68d3967'),
|
|
||||||
'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
|
|
||||||
'releases/32/Server/aarch64/os/images/'
|
|
||||||
'pxeboot/'),
|
|
||||||
'kernel_params': ('root=UUID=3df75b65-be8d-4db4-8655-'
|
|
||||||
'14d95c0e90c5 ro no_timer_check net.ifnames=0'
|
|
||||||
' console=tty1 console=ttyS0,115200n8'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'33': {
|
|
||||||
'aarch64':
|
|
||||||
{'checksum': ('e7f75cdfd523fe5ac2ca9eeece68edc1'
|
|
||||||
'a81f386a17f969c1d1c7c87031008a6b'),
|
|
||||||
'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
|
|
||||||
'releases/33/Server/aarch64/os/images/'
|
|
||||||
'pxeboot/'),
|
|
||||||
'kernel_params': ('root=UUID=d20b3ffa-6397-4a63-a734-'
|
|
||||||
'1126a0208f8a ro no_timer_check net.ifnames=0'
|
|
||||||
' console=tty1 console=ttyS0,115200n8'
|
|
||||||
' console=tty0'),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self, name, version, arch):
|
|
||||||
self.name = name
|
|
||||||
self.version = version
|
|
||||||
self.arch = arch
|
|
||||||
try:
|
|
||||||
info = self.KNOWN_DISTROS.get(name).get(version).get(arch)
|
|
||||||
except AttributeError:
|
|
||||||
# Unknown distro
|
|
||||||
info = None
|
|
||||||
self._info = info or {}
|
|
||||||
|
|
||||||
@property
|
|
||||||
def checksum(self):
|
|
||||||
"""Gets the cloud-image file checksum"""
|
|
||||||
return self._info.get('checksum', None)
|
|
||||||
|
|
||||||
@checksum.setter
|
|
||||||
def checksum(self, value):
|
|
||||||
self._info['checksum'] = value
|
|
||||||
|
|
||||||
@property
|
|
||||||
def pxeboot_url(self):
|
|
||||||
"""Gets the repository url where pxeboot files can be found"""
|
|
||||||
return self._info.get('pxeboot_url', None)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def default_kernel_params(self):
|
|
||||||
"""Gets the default kernel parameters"""
|
|
||||||
return self._info.get('kernel_params', None)
|
|
||||||
|
|
||||||
|
|
||||||
class LinuxTest(LinuxSSHMixIn, QemuSystemTest):
|
|
||||||
"""Facilitates having a cloud-image Linux based available.
|
|
||||||
|
|
||||||
For tests that intend to interact with guests, this is a better choice
|
|
||||||
to start with than the more vanilla `QemuSystemTest` class.
|
|
||||||
"""
|
|
||||||
|
|
||||||
distro = None
|
|
||||||
username = 'root'
|
|
||||||
password = 'password'
|
|
||||||
smp = '2'
|
|
||||||
memory = '1024'
|
|
||||||
|
|
||||||
def _set_distro(self):
|
|
||||||
distro_name = self.params.get(
|
|
||||||
'distro',
|
|
||||||
default=self._get_unique_tag_val('distro'))
|
|
||||||
if not distro_name:
|
|
||||||
distro_name = 'fedora'
|
|
||||||
|
|
||||||
distro_version = self.params.get(
|
|
||||||
'distro_version',
|
|
||||||
default=self._get_unique_tag_val('distro_version'))
|
|
||||||
if not distro_version:
|
|
||||||
distro_version = '31'
|
|
||||||
|
|
||||||
self.distro = LinuxDistro(distro_name, distro_version, self.arch)
|
|
||||||
|
|
||||||
# The distro checksum behaves differently than distro name and
|
|
||||||
# version. First, it does not respect a tag with the same
|
|
||||||
# name, given that it's not expected to be used for filtering
|
|
||||||
# (distro name versions are the natural choice). Second, the
|
|
||||||
# order of precedence is: parameter, attribute and then value
|
|
||||||
# from KNOWN_DISTROS.
|
|
||||||
distro_checksum = self.params.get('distro_checksum',
|
|
||||||
default=None)
|
|
||||||
if distro_checksum:
|
|
||||||
self.distro.checksum = distro_checksum
|
|
||||||
|
|
||||||
def setUp(self, ssh_pubkey=None, network_device_type='virtio-net'):
|
|
||||||
super().setUp()
|
|
||||||
self.require_netdev('user')
|
|
||||||
self._set_distro()
|
|
||||||
self.vm.add_args('-smp', self.smp)
|
|
||||||
self.vm.add_args('-m', self.memory)
|
|
||||||
# The following network device allows for SSH connections
|
|
||||||
self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
|
|
||||||
'-device', '%s,netdev=vnet' % network_device_type)
|
|
||||||
self.set_up_boot()
|
|
||||||
if ssh_pubkey is None:
|
|
||||||
ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys()
|
|
||||||
self.set_up_cloudinit(ssh_pubkey)
|
|
||||||
|
|
||||||
def set_up_existing_ssh_keys(self):
|
|
||||||
ssh_public_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa.pub')
|
|
||||||
source_private_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa')
|
|
||||||
ssh_dir = os.path.join(self.workdir, '.ssh')
|
|
||||||
os.mkdir(ssh_dir, mode=0o700)
|
|
||||||
ssh_private_key = os.path.join(ssh_dir,
|
|
||||||
os.path.basename(source_private_key))
|
|
||||||
shutil.copyfile(source_private_key, ssh_private_key)
|
|
||||||
os.chmod(ssh_private_key, 0o600)
|
|
||||||
return (ssh_public_key, ssh_private_key)
|
|
||||||
|
|
||||||
def download_boot(self):
|
|
||||||
# Set the qemu-img binary.
|
|
||||||
# If none is available, the test will cancel.
|
|
||||||
vmimage.QEMU_IMG = super().get_qemu_img()
|
|
||||||
|
|
||||||
self.log.info('Downloading/preparing boot image')
|
|
||||||
# Fedora 31 only provides ppc64le images
|
|
||||||
image_arch = self.arch
|
|
||||||
if self.distro.name == 'fedora':
|
|
||||||
if image_arch == 'ppc64':
|
|
||||||
image_arch = 'ppc64le'
|
|
||||||
|
|
||||||
try:
|
|
||||||
boot = vmimage.get(
|
|
||||||
self.distro.name, arch=image_arch, version=self.distro.version,
|
|
||||||
checksum=self.distro.checksum,
|
|
||||||
algorithm='sha256',
|
|
||||||
cache_dir=self.cache_dirs[0],
|
|
||||||
snapshot_dir=self.workdir)
|
|
||||||
except:
|
|
||||||
self.cancel('Failed to download/prepare boot image')
|
|
||||||
return boot.path
|
|
||||||
|
|
||||||
def prepare_cloudinit(self, ssh_pubkey=None):
|
|
||||||
self.log.info('Preparing cloudinit image')
|
|
||||||
try:
|
|
||||||
cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso')
|
|
||||||
pubkey_content = None
|
|
||||||
if ssh_pubkey:
|
|
||||||
with open(ssh_pubkey) as pubkey:
|
|
||||||
pubkey_content = pubkey.read()
|
|
||||||
cloudinit.iso(cloudinit_iso, self.name,
|
|
||||||
username=self.username,
|
|
||||||
password=self.password,
|
|
||||||
# QEMU's hard coded usermode router address
|
|
||||||
phone_home_host='10.0.2.2',
|
|
||||||
phone_home_port=self.phone_server.server_port,
|
|
||||||
authorized_key=pubkey_content)
|
|
||||||
except Exception:
|
|
||||||
self.cancel('Failed to prepare the cloudinit image')
|
|
||||||
return cloudinit_iso
|
|
||||||
|
|
||||||
def set_up_boot(self):
|
|
||||||
path = self.download_boot()
|
|
||||||
self.vm.add_args('-drive', 'file=%s' % path)
|
|
||||||
|
|
||||||
def set_up_cloudinit(self, ssh_pubkey=None):
|
|
||||||
self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0),
|
|
||||||
self.name)
|
|
||||||
cloudinit_iso = self.prepare_cloudinit(ssh_pubkey)
|
|
||||||
self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
|
|
||||||
|
|
||||||
def launch_and_wait(self, set_up_ssh_connection=True):
|
|
||||||
self.vm.set_console()
|
|
||||||
self.vm.launch()
|
|
||||||
console_drainer = datadrainer.LineLogger(self.vm.console_socket.fileno(),
|
|
||||||
logger=self.log.getChild('console'))
|
|
||||||
console_drainer.start()
|
|
||||||
self.log.info('VM launched, waiting for boot confirmation from guest')
|
|
||||||
while not self.phone_server.instance_phoned_back:
|
|
||||||
self.phone_server.handle_request()
|
|
||||||
|
|
||||||
if set_up_ssh_connection:
|
|
||||||
self.log.info('Setting up the SSH connection')
|
|
||||||
self.ssh_connect(self.username, self.ssh_key)
|
|
||||||
|
|
|
@ -0,0 +1,253 @@
|
||||||
|
# Test class and utilities for functional Linux-based tests
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018 Red Hat, Inc.
|
||||||
|
#
|
||||||
|
# Author:
|
||||||
|
# Cleber Rosa <crosa@redhat.com>
|
||||||
|
#
|
||||||
|
# This work is licensed under the terms of the GNU GPL, version 2 or
|
||||||
|
# later. See the COPYING file in the top-level directory.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from avocado.utils import cloudinit, datadrainer, process, vmimage
|
||||||
|
|
||||||
|
from . import LinuxSSHMixIn
|
||||||
|
from . import QemuSystemTest
|
||||||
|
|
||||||
|
if os.path.islink(os.path.dirname(os.path.dirname(__file__))):
|
||||||
|
# The link to the avocado tests dir in the source code directory
|
||||||
|
lnk = os.path.dirname(os.path.dirname(__file__))
|
||||||
|
#: The QEMU root source directory
|
||||||
|
SOURCE_DIR = os.path.dirname(os.path.dirname(os.readlink(lnk)))
|
||||||
|
else:
|
||||||
|
SOURCE_DIR = BUILD_DIR
|
||||||
|
|
||||||
|
class LinuxDistro:
|
||||||
|
"""Represents a Linux distribution
|
||||||
|
|
||||||
|
Holds information of known distros.
|
||||||
|
"""
|
||||||
|
#: A collection of known distros and their respective image checksum
|
||||||
|
KNOWN_DISTROS = {
|
||||||
|
'fedora': {
|
||||||
|
'31': {
|
||||||
|
'x86_64':
|
||||||
|
{'checksum': ('e3c1b309d9203604922d6e255c2c5d09'
|
||||||
|
'8a309c2d46215d8fc026954f3c5c27a0'),
|
||||||
|
'pxeboot_url': ('https://archives.fedoraproject.org/'
|
||||||
|
'pub/archive/fedora/linux/releases/31/'
|
||||||
|
'Everything/x86_64/os/images/pxeboot/'),
|
||||||
|
'kernel_params': ('root=UUID=b1438b9b-2cab-4065-a99a-'
|
||||||
|
'08a96687f73c ro no_timer_check '
|
||||||
|
'net.ifnames=0 console=tty1 '
|
||||||
|
'console=ttyS0,115200n8'),
|
||||||
|
},
|
||||||
|
'aarch64':
|
||||||
|
{'checksum': ('1e18d9c0cf734940c4b5d5ec592facae'
|
||||||
|
'd2af0ad0329383d5639c997fdf16fe49'),
|
||||||
|
'pxeboot_url': 'https://archives.fedoraproject.org/'
|
||||||
|
'pub/archive/fedora/linux/releases/31/'
|
||||||
|
'Everything/aarch64/os/images/pxeboot/',
|
||||||
|
'kernel_params': ('root=UUID=b6950a44-9f3c-4076-a9c2-'
|
||||||
|
'355e8475b0a7 ro earlyprintk=pl011,0x9000000'
|
||||||
|
' ignore_loglevel no_timer_check'
|
||||||
|
' printk.time=1 rd_NO_PLYMOUTH'
|
||||||
|
' console=ttyAMA0'),
|
||||||
|
},
|
||||||
|
'ppc64':
|
||||||
|
{'checksum': ('7c3528b85a3df4b2306e892199a9e1e4'
|
||||||
|
'3f991c506f2cc390dc4efa2026ad2f58')},
|
||||||
|
's390x':
|
||||||
|
{'checksum': ('4caaab5a434fd4d1079149a072fdc789'
|
||||||
|
'1e354f834d355069ca982fdcaf5a122d')},
|
||||||
|
},
|
||||||
|
'32': {
|
||||||
|
'aarch64':
|
||||||
|
{'checksum': ('b367755c664a2d7a26955bbfff985855'
|
||||||
|
'adfa2ca15e908baf15b4b176d68d3967'),
|
||||||
|
'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
|
||||||
|
'releases/32/Server/aarch64/os/images/'
|
||||||
|
'pxeboot/'),
|
||||||
|
'kernel_params': ('root=UUID=3df75b65-be8d-4db4-8655-'
|
||||||
|
'14d95c0e90c5 ro no_timer_check net.ifnames=0'
|
||||||
|
' console=tty1 console=ttyS0,115200n8'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'33': {
|
||||||
|
'aarch64':
|
||||||
|
{'checksum': ('e7f75cdfd523fe5ac2ca9eeece68edc1'
|
||||||
|
'a81f386a17f969c1d1c7c87031008a6b'),
|
||||||
|
'pxeboot_url': ('http://dl.fedoraproject.org/pub/fedora/linux/'
|
||||||
|
'releases/33/Server/aarch64/os/images/'
|
||||||
|
'pxeboot/'),
|
||||||
|
'kernel_params': ('root=UUID=d20b3ffa-6397-4a63-a734-'
|
||||||
|
'1126a0208f8a ro no_timer_check net.ifnames=0'
|
||||||
|
' console=tty1 console=ttyS0,115200n8'
|
||||||
|
' console=tty0'),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, name, version, arch):
|
||||||
|
self.name = name
|
||||||
|
self.version = version
|
||||||
|
self.arch = arch
|
||||||
|
try:
|
||||||
|
info = self.KNOWN_DISTROS.get(name).get(version).get(arch)
|
||||||
|
except AttributeError:
|
||||||
|
# Unknown distro
|
||||||
|
info = None
|
||||||
|
self._info = info or {}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def checksum(self):
|
||||||
|
"""Gets the cloud-image file checksum"""
|
||||||
|
return self._info.get('checksum', None)
|
||||||
|
|
||||||
|
@checksum.setter
|
||||||
|
def checksum(self, value):
|
||||||
|
self._info['checksum'] = value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pxeboot_url(self):
|
||||||
|
"""Gets the repository url where pxeboot files can be found"""
|
||||||
|
return self._info.get('pxeboot_url', None)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def default_kernel_params(self):
|
||||||
|
"""Gets the default kernel parameters"""
|
||||||
|
return self._info.get('kernel_params', None)
|
||||||
|
|
||||||
|
|
||||||
|
class LinuxTest(LinuxSSHMixIn, QemuSystemTest):
|
||||||
|
"""Facilitates having a cloud-image Linux based available.
|
||||||
|
|
||||||
|
For tests that intend to interact with guests, this is a better choice
|
||||||
|
to start with than the more vanilla `QemuSystemTest` class.
|
||||||
|
"""
|
||||||
|
|
||||||
|
distro = None
|
||||||
|
username = 'root'
|
||||||
|
password = 'password'
|
||||||
|
smp = '2'
|
||||||
|
memory = '1024'
|
||||||
|
|
||||||
|
def _set_distro(self):
|
||||||
|
distro_name = self.params.get(
|
||||||
|
'distro',
|
||||||
|
default=self._get_unique_tag_val('distro'))
|
||||||
|
if not distro_name:
|
||||||
|
distro_name = 'fedora'
|
||||||
|
|
||||||
|
distro_version = self.params.get(
|
||||||
|
'distro_version',
|
||||||
|
default=self._get_unique_tag_val('distro_version'))
|
||||||
|
if not distro_version:
|
||||||
|
distro_version = '31'
|
||||||
|
|
||||||
|
self.distro = LinuxDistro(distro_name, distro_version, self.arch)
|
||||||
|
|
||||||
|
# The distro checksum behaves differently than distro name and
|
||||||
|
# version. First, it does not respect a tag with the same
|
||||||
|
# name, given that it's not expected to be used for filtering
|
||||||
|
# (distro name versions are the natural choice). Second, the
|
||||||
|
# order of precedence is: parameter, attribute and then value
|
||||||
|
# from KNOWN_DISTROS.
|
||||||
|
distro_checksum = self.params.get('distro_checksum',
|
||||||
|
default=None)
|
||||||
|
if distro_checksum:
|
||||||
|
self.distro.checksum = distro_checksum
|
||||||
|
|
||||||
|
def setUp(self, ssh_pubkey=None, network_device_type='virtio-net'):
|
||||||
|
super().setUp()
|
||||||
|
self.require_netdev('user')
|
||||||
|
self._set_distro()
|
||||||
|
self.vm.add_args('-smp', self.smp)
|
||||||
|
self.vm.add_args('-m', self.memory)
|
||||||
|
# The following network device allows for SSH connections
|
||||||
|
self.vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
|
||||||
|
'-device', '%s,netdev=vnet' % network_device_type)
|
||||||
|
self.set_up_boot()
|
||||||
|
if ssh_pubkey is None:
|
||||||
|
ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys()
|
||||||
|
self.set_up_cloudinit(ssh_pubkey)
|
||||||
|
|
||||||
|
def set_up_existing_ssh_keys(self):
|
||||||
|
ssh_public_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa.pub')
|
||||||
|
source_private_key = os.path.join(SOURCE_DIR, 'tests', 'keys', 'id_rsa')
|
||||||
|
ssh_dir = os.path.join(self.workdir, '.ssh')
|
||||||
|
os.mkdir(ssh_dir, mode=0o700)
|
||||||
|
ssh_private_key = os.path.join(ssh_dir,
|
||||||
|
os.path.basename(source_private_key))
|
||||||
|
shutil.copyfile(source_private_key, ssh_private_key)
|
||||||
|
os.chmod(ssh_private_key, 0o600)
|
||||||
|
return (ssh_public_key, ssh_private_key)
|
||||||
|
|
||||||
|
def download_boot(self):
|
||||||
|
# Set the qemu-img binary.
|
||||||
|
# If none is available, the test will cancel.
|
||||||
|
vmimage.QEMU_IMG = super().get_qemu_img()
|
||||||
|
|
||||||
|
self.log.info('Downloading/preparing boot image')
|
||||||
|
# Fedora 31 only provides ppc64le images
|
||||||
|
image_arch = self.arch
|
||||||
|
if self.distro.name == 'fedora':
|
||||||
|
if image_arch == 'ppc64':
|
||||||
|
image_arch = 'ppc64le'
|
||||||
|
|
||||||
|
try:
|
||||||
|
boot = vmimage.get(
|
||||||
|
self.distro.name, arch=image_arch, version=self.distro.version,
|
||||||
|
checksum=self.distro.checksum,
|
||||||
|
algorithm='sha256',
|
||||||
|
cache_dir=self.cache_dirs[0],
|
||||||
|
snapshot_dir=self.workdir)
|
||||||
|
except:
|
||||||
|
self.cancel('Failed to download/prepare boot image')
|
||||||
|
return boot.path
|
||||||
|
|
||||||
|
def prepare_cloudinit(self, ssh_pubkey=None):
|
||||||
|
self.log.info('Preparing cloudinit image')
|
||||||
|
try:
|
||||||
|
cloudinit_iso = os.path.join(self.workdir, 'cloudinit.iso')
|
||||||
|
pubkey_content = None
|
||||||
|
if ssh_pubkey:
|
||||||
|
with open(ssh_pubkey) as pubkey:
|
||||||
|
pubkey_content = pubkey.read()
|
||||||
|
cloudinit.iso(cloudinit_iso, self.name,
|
||||||
|
username=self.username,
|
||||||
|
password=self.password,
|
||||||
|
# QEMU's hard coded usermode router address
|
||||||
|
phone_home_host='10.0.2.2',
|
||||||
|
phone_home_port=self.phone_server.server_port,
|
||||||
|
authorized_key=pubkey_content)
|
||||||
|
except Exception:
|
||||||
|
self.cancel('Failed to prepare the cloudinit image')
|
||||||
|
return cloudinit_iso
|
||||||
|
|
||||||
|
def set_up_boot(self):
|
||||||
|
path = self.download_boot()
|
||||||
|
self.vm.add_args('-drive', 'file=%s' % path)
|
||||||
|
|
||||||
|
def set_up_cloudinit(self, ssh_pubkey=None):
|
||||||
|
self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0),
|
||||||
|
self.name)
|
||||||
|
cloudinit_iso = self.prepare_cloudinit(ssh_pubkey)
|
||||||
|
self.vm.add_args('-drive', 'file=%s,format=raw' % cloudinit_iso)
|
||||||
|
|
||||||
|
def launch_and_wait(self, set_up_ssh_connection=True):
|
||||||
|
self.vm.set_console()
|
||||||
|
self.vm.launch()
|
||||||
|
console_drainer = datadrainer.LineLogger(self.vm.console_socket.fileno(),
|
||||||
|
logger=self.log.getChild('console'))
|
||||||
|
console_drainer.start()
|
||||||
|
self.log.info('VM launched, waiting for boot confirmation from guest')
|
||||||
|
while not self.phone_server.instance_phoned_back:
|
||||||
|
self.phone_server.handle_request()
|
||||||
|
|
||||||
|
if set_up_ssh_connection:
|
||||||
|
self.log.info('Setting up the SSH connection')
|
||||||
|
self.ssh_connect(self.username, self.ssh_key)
|
|
@ -10,7 +10,8 @@
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from avocado_qemu import LinuxTest, BUILD_DIR
|
from avocado_qemu.linuxtest import LinuxTest
|
||||||
|
from avocado_qemu import BUILD_DIR
|
||||||
|
|
||||||
from avocado import skipUnless
|
from avocado import skipUnless
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,14 @@ from avocado_qemu import wait_for_console_pattern
|
||||||
from boot_linux_console import LinuxKernelTest
|
from boot_linux_console import LinuxKernelTest
|
||||||
|
|
||||||
|
|
||||||
class BootXenBase(LinuxKernelTest):
|
class BootXen(LinuxKernelTest):
|
||||||
"""
|
"""
|
||||||
Boots a Xen hypervisor with a Linux DomU kernel.
|
Boots a Xen hypervisor with a Linux DomU kernel.
|
||||||
|
|
||||||
|
:avocado: tags=arch:aarch64
|
||||||
|
:avocado: tags=accel:tcg
|
||||||
|
:avocado: tags=cpu:cortex-a57
|
||||||
|
:avocado: tags=machine:virt
|
||||||
"""
|
"""
|
||||||
|
|
||||||
timeout = 90
|
timeout = 90
|
||||||
|
@ -45,11 +50,10 @@ class BootXenBase(LinuxKernelTest):
|
||||||
|
|
||||||
self.vm.set_console()
|
self.vm.set_console()
|
||||||
|
|
||||||
xen_command_line = self.XEN_COMMON_COMMAND_LINE
|
|
||||||
self.vm.add_args('-machine', 'virtualization=on',
|
self.vm.add_args('-machine', 'virtualization=on',
|
||||||
'-m', '768',
|
'-m', '768',
|
||||||
'-kernel', xen_path,
|
'-kernel', xen_path,
|
||||||
'-append', xen_command_line,
|
'-append', self.XEN_COMMON_COMMAND_LINE,
|
||||||
'-device',
|
'-device',
|
||||||
'guest-loader,addr=0x47000000,kernel=%s,bootargs=console=hvc0'
|
'guest-loader,addr=0x47000000,kernel=%s,bootargs=console=hvc0'
|
||||||
% (kernel_path))
|
% (kernel_path))
|
||||||
|
@ -59,17 +63,7 @@ class BootXenBase(LinuxKernelTest):
|
||||||
console_pattern = 'VFS: Cannot open root device'
|
console_pattern = 'VFS: Cannot open root device'
|
||||||
wait_for_console_pattern(self, console_pattern, "Panic on CPU 0:")
|
wait_for_console_pattern(self, console_pattern, "Panic on CPU 0:")
|
||||||
|
|
||||||
|
|
||||||
class BootXen(BootXenBase):
|
|
||||||
|
|
||||||
def test_arm64_xen_411_and_dom0(self):
|
def test_arm64_xen_411_and_dom0(self):
|
||||||
"""
|
|
||||||
:avocado: tags=arch:aarch64
|
|
||||||
:avocado: tags=accel:tcg
|
|
||||||
:avocado: tags=cpu:cortex-a57
|
|
||||||
:avocado: tags=machine:virt
|
|
||||||
"""
|
|
||||||
|
|
||||||
# archive of file from https://deb.debian.org/debian/pool/main/x/xen/
|
# archive of file from https://deb.debian.org/debian/pool/main/x/xen/
|
||||||
xen_url = ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/'
|
xen_url = ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/'
|
||||||
'download?path=%2F&files='
|
'download?path=%2F&files='
|
||||||
|
@ -81,13 +75,6 @@ class BootXen(BootXenBase):
|
||||||
self.launch_xen(xen_path)
|
self.launch_xen(xen_path)
|
||||||
|
|
||||||
def test_arm64_xen_414_and_dom0(self):
|
def test_arm64_xen_414_and_dom0(self):
|
||||||
"""
|
|
||||||
:avocado: tags=arch:aarch64
|
|
||||||
:avocado: tags=accel:tcg
|
|
||||||
:avocado: tags=cpu:cortex-a57
|
|
||||||
:avocado: tags=machine:virt
|
|
||||||
"""
|
|
||||||
|
|
||||||
# archive of file from https://deb.debian.org/debian/pool/main/x/xen/
|
# archive of file from https://deb.debian.org/debian/pool/main/x/xen/
|
||||||
xen_url = ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/'
|
xen_url = ('https://fileserver.linaro.org/s/JSsewXGZ6mqxPr5/'
|
||||||
'download?path=%2F&files='
|
'download?path=%2F&files='
|
||||||
|
@ -99,13 +86,6 @@ class BootXen(BootXenBase):
|
||||||
self.launch_xen(xen_path)
|
self.launch_xen(xen_path)
|
||||||
|
|
||||||
def test_arm64_xen_415_and_dom0(self):
|
def test_arm64_xen_415_and_dom0(self):
|
||||||
"""
|
|
||||||
:avocado: tags=arch:aarch64
|
|
||||||
:avocado: tags=accel:tcg
|
|
||||||
:avocado: tags=cpu:cortex-a57
|
|
||||||
:avocado: tags=machine:virt
|
|
||||||
"""
|
|
||||||
|
|
||||||
xen_url = ('https://fileserver.linaro.org/'
|
xen_url = ('https://fileserver.linaro.org/'
|
||||||
's/JSsewXGZ6mqxPr5/download'
|
's/JSsewXGZ6mqxPr5/download'
|
||||||
'?path=%2F&files=xen-upstream-4.15-unstable.deb')
|
'?path=%2F&files=xen-upstream-4.15-unstable.deb')
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from avocado_qemu import LinuxTest
|
from avocado_qemu.linuxtest import LinuxTest
|
||||||
|
|
||||||
|
|
||||||
class HotPlug(LinuxTest):
|
class HotPlug(LinuxTest):
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
# This work is licensed under the terms of the GNU GPL, version 2 or
|
# This work is licensed under the terms of the GNU GPL, version 2 or
|
||||||
# later. See the COPYING file in the top-level directory.
|
# later. See the COPYING file in the top-level directory.
|
||||||
|
|
||||||
from avocado_qemu import LinuxTest
|
from avocado_qemu.linuxtest import LinuxTest
|
||||||
|
|
||||||
|
|
||||||
class HotPlugCPU(LinuxTest):
|
class HotPlugCPU(LinuxTest):
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from avocado import skipUnless
|
from avocado import skipUnless
|
||||||
from avocado_qemu import LinuxTest
|
from avocado_qemu.linuxtest import LinuxTest
|
||||||
|
|
||||||
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
|
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,7 @@ class AST1030Machine(QemuSystemTest):
|
||||||
|
|
||||||
class AST2x00Machine(QemuSystemTest):
|
class AST2x00Machine(QemuSystemTest):
|
||||||
|
|
||||||
timeout = 90
|
timeout = 180
|
||||||
|
|
||||||
def wait_for_console_pattern(self, success_message, vm=None):
|
def wait_for_console_pattern(self, success_message, vm=None):
|
||||||
wait_for_console_pattern(self, success_message,
|
wait_for_console_pattern(self, success_message,
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
from avocado_qemu import QemuSystemTest
|
from avocado_qemu import QemuSystemTest
|
||||||
import signal
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
class MemAddrCheck(QemuSystemTest):
|
class MemAddrCheck(QemuSystemTest):
|
||||||
|
|
|
@ -19,7 +19,7 @@ from avocado.utils import network
|
||||||
from avocado.utils import vmimage
|
from avocado.utils import vmimage
|
||||||
from avocado.utils import datadrainer
|
from avocado.utils import datadrainer
|
||||||
from avocado.utils.path import find_command
|
from avocado.utils.path import find_command
|
||||||
from avocado_qemu import LinuxTest
|
from avocado_qemu.linuxtest import LinuxTest
|
||||||
|
|
||||||
class ReplayLinux(LinuxTest):
|
class ReplayLinux(LinuxTest):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -10,7 +10,8 @@
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from avocado import skipUnless
|
from avocado import skipUnless
|
||||||
from avocado_qemu import LinuxTest, BUILD_DIR
|
from avocado_qemu import BUILD_DIR
|
||||||
|
from avocado_qemu.linuxtest import LinuxTest
|
||||||
|
|
||||||
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
|
@skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'), 'Test is unstable on GitLab')
|
||||||
|
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
function print_usage()
|
|
||||||
{
|
|
||||||
if [ -n "$2" ]; then
|
|
||||||
echo "Error: $2"
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
echo "Usage: $1 <scratch dir>"
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_dir=$1
|
|
||||||
if [ -z "$scratch_dir" ]; then
|
|
||||||
print_usage "$0" 'Scratch dir not given' >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$scratch_dir/share" || exit 1
|
|
||||||
mps=(mnt*)
|
|
||||||
mp_i=0
|
|
||||||
for mp in "${mps[@]}"; do
|
|
||||||
mp_i=$((mp_i + 1))
|
|
||||||
printf "Unmounting %i/%i...\r" "$mp_i" "${#mps[@]}"
|
|
||||||
|
|
||||||
sudo umount -R "$mp"
|
|
||||||
rm -rf "$mp"
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
|
|
||||||
rm some-file
|
|
||||||
cd ..
|
|
||||||
rmdir share
|
|
||||||
|
|
||||||
imgs=(fs*.img)
|
|
||||||
img_i=0
|
|
||||||
for img in "${imgs[@]}"; do
|
|
||||||
img_i=$((img_i + 1))
|
|
||||||
printf "Detaching and deleting %i/%i...\r" "$img_i" "${#imgs[@]}"
|
|
||||||
|
|
||||||
dev=$(losetup -j "$img" | sed -e 's/:.*//')
|
|
||||||
sudo losetup -d "$dev"
|
|
||||||
rm -f "$img"
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
|
|
||||||
echo 'Done.'
|
|
|
@ -1,30 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
function print_usage()
|
|
||||||
{
|
|
||||||
if [ -n "$2" ]; then
|
|
||||||
echo "Error: $2"
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
echo "Usage: $1 <scratch dir>"
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_dir=$1
|
|
||||||
if [ -z "$scratch_dir" ]; then
|
|
||||||
print_usage "$0" 'Scratch dir not given' >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$scratch_dir/share" || exit 1
|
|
||||||
|
|
||||||
mps=(mnt*)
|
|
||||||
mp_i=0
|
|
||||||
for mp in "${mps[@]}"; do
|
|
||||||
mp_i=$((mp_i + 1))
|
|
||||||
printf "Unmounting %i/%i...\r" "$mp_i" "${#mps[@]}"
|
|
||||||
|
|
||||||
sudo umount -R "$mp"
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
|
|
||||||
echo 'Done.'
|
|
|
@ -1,138 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
function print_usage()
|
|
||||||
{
|
|
||||||
if [ -n "$2" ]; then
|
|
||||||
echo "Error: $2"
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
echo "Usage: $1 <shared dir>"
|
|
||||||
echo '(The shared directory is the "share" directory in the scratch' \
|
|
||||||
'directory)'
|
|
||||||
}
|
|
||||||
|
|
||||||
shared_dir=$1
|
|
||||||
if [ -z "$shared_dir" ]; then
|
|
||||||
print_usage "$0" 'Shared dir not given' >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd "$shared_dir"
|
|
||||||
|
|
||||||
# FIXME: This should not be necessary, but it is. In order for all
|
|
||||||
# submounts to be proper mount points, we need to visit them.
|
|
||||||
# (Before we visit them, they will not be auto-mounted, and so just
|
|
||||||
# appear as normal directories, with the catch that their st_ino will
|
|
||||||
# be the st_ino of the filesystem they host, while the st_dev will
|
|
||||||
# still be the st_dev of the parent.)
|
|
||||||
# `find` does not work, because it will refuse to touch the mount
|
|
||||||
# points as long as they are not mounted; their st_dev being shared
|
|
||||||
# with the parent and st_ino just being the root node's inode ID
|
|
||||||
# will practically ensure that this node exists elsewhere on the
|
|
||||||
# filesystem, and `find` is required to recognize loops and not to
|
|
||||||
# follow them.
|
|
||||||
# Thus, we have to manually visit all nodes first.
|
|
||||||
|
|
||||||
mnt_i=0
|
|
||||||
|
|
||||||
function recursively_visit()
|
|
||||||
{
|
|
||||||
pushd "$1" >/dev/null
|
|
||||||
for entry in *; do
|
|
||||||
if [[ "$entry" == mnt* ]]; then
|
|
||||||
mnt_i=$((mnt_i + 1))
|
|
||||||
printf "Triggering auto-mount $mnt_i...\r"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d "$entry" ]; then
|
|
||||||
recursively_visit "$entry"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
popd >/dev/null
|
|
||||||
}
|
|
||||||
|
|
||||||
recursively_visit .
|
|
||||||
echo
|
|
||||||
|
|
||||||
|
|
||||||
if [ -n "$(find -name not-mounted)" ]; then
|
|
||||||
echo "Error: not-mounted files visible on mount points:" >&2
|
|
||||||
find -name not-mounted >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -f some-file -o "$(cat some-file)" != 'root' ]; then
|
|
||||||
echo "Error: Bad file in the share root" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
shopt -s nullglob
|
|
||||||
|
|
||||||
function check_submounts()
|
|
||||||
{
|
|
||||||
local base_path=$1
|
|
||||||
|
|
||||||
for mp in mnt*; do
|
|
||||||
printf "Checking submount %i...\r" "$((${#devs[@]} + 1))"
|
|
||||||
|
|
||||||
mp_i=$(echo "$mp" | sed -e 's/mnt//')
|
|
||||||
dev=$(stat -c '%D' "$mp")
|
|
||||||
|
|
||||||
if [ -n "${devs[mp_i]}" ]; then
|
|
||||||
echo "Error: $mp encountered twice" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
devs[mp_i]=$dev
|
|
||||||
|
|
||||||
pushd "$mp" >/dev/null
|
|
||||||
path="$base_path$mp"
|
|
||||||
while true; do
|
|
||||||
expected_content="$(printf '%s\n%s\n' "$mp_i" "$path")"
|
|
||||||
if [ ! -f some-file ]; then
|
|
||||||
echo "Error: $PWD/some-file does not exist" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$(cat some-file)" != "$expected_content" ]; then
|
|
||||||
echo "Error: Bad content in $PWD/some-file:" >&2
|
|
||||||
echo '--- found ---'
|
|
||||||
cat some-file
|
|
||||||
echo '--- expected ---'
|
|
||||||
echo "$expected_content"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ "$(stat -c '%D' some-file)" != "$dev" ]; then
|
|
||||||
echo "Error: $PWD/some-file has the wrong device ID" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d sub ]; then
|
|
||||||
if [ "$(stat -c '%D' sub)" != "$dev" ]; then
|
|
||||||
echo "Error: $PWD/some-file has the wrong device ID" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
cd sub
|
|
||||||
path="$path/sub"
|
|
||||||
else
|
|
||||||
if [ -n "$(echo mnt*)" ]; then
|
|
||||||
check_submounts "$path/"
|
|
||||||
fi
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
popd >/dev/null
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
root_dev=$(stat -c '%D' some-file)
|
|
||||||
devs=()
|
|
||||||
check_submounts ''
|
|
||||||
echo
|
|
||||||
|
|
||||||
reused_devs=$(echo "$root_dev ${devs[@]}" | tr ' ' '\n' | sort | uniq -d)
|
|
||||||
if [ -n "$reused_devs" ]; then
|
|
||||||
echo "Error: Reused device IDs: $reused_devs" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Test passed for ${#devs[@]} submounts."
|
|
|
@ -1,127 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
mount_count=128
|
|
||||||
|
|
||||||
function print_usage()
|
|
||||||
{
|
|
||||||
if [ -n "$2" ]; then
|
|
||||||
echo "Error: $2"
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
echo "Usage: $1 <scratch dir> [seed]"
|
|
||||||
echo "(If no seed is given, it will be randomly generated.)"
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_dir=$1
|
|
||||||
if [ -z "$scratch_dir" ]; then
|
|
||||||
print_usage "$0" 'No scratch dir given' >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ ! -d "$scratch_dir" ]; then
|
|
||||||
print_usage "$0" "$scratch_dir is not a directory" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
seed=$2
|
|
||||||
if [ -z "$seed" ]; then
|
|
||||||
seed=$RANDOM
|
|
||||||
fi
|
|
||||||
RANDOM=$seed
|
|
||||||
|
|
||||||
echo "Seed: $seed"
|
|
||||||
|
|
||||||
set -e
|
|
||||||
shopt -s nullglob
|
|
||||||
|
|
||||||
cd "$scratch_dir"
|
|
||||||
if [ -d share ]; then
|
|
||||||
echo 'Error: This directory seems to be in use already' >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
for ((i = 0; i < $mount_count; i++)); do
|
|
||||||
printf "Setting up fs %i/%i...\r" "$((i + 1))" "$mount_count"
|
|
||||||
|
|
||||||
rm -f fs$i.img
|
|
||||||
truncate -s 512M fs$i.img
|
|
||||||
mkfs.xfs -q fs$i.img
|
|
||||||
devs[i]=$(sudo losetup -f --show fs$i.img)
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
|
|
||||||
top_level_mounts=$((RANDOM % mount_count + 1))
|
|
||||||
|
|
||||||
mkdir -p share
|
|
||||||
echo 'root' > share/some-file
|
|
||||||
|
|
||||||
for ((i = 0; i < $top_level_mounts; i++)); do
|
|
||||||
printf "Mounting fs %i/%i...\r" "$((i + 1))" "$mount_count"
|
|
||||||
|
|
||||||
mkdir -p share/mnt$i
|
|
||||||
touch share/mnt$i/not-mounted
|
|
||||||
sudo mount "${devs[i]}" share/mnt$i
|
|
||||||
sudo chown "$(id -u):$(id -g)" share/mnt$i
|
|
||||||
|
|
||||||
pushd share/mnt$i >/dev/null
|
|
||||||
path=mnt$i
|
|
||||||
nesting=$((RANDOM % 4))
|
|
||||||
for ((j = 0; j < $nesting; j++)); do
|
|
||||||
cat > some-file <<EOF
|
|
||||||
$i
|
|
||||||
$path
|
|
||||||
EOF
|
|
||||||
mkdir sub
|
|
||||||
cd sub
|
|
||||||
path="$path/sub"
|
|
||||||
done
|
|
||||||
cat > some-file <<EOF
|
|
||||||
$i
|
|
||||||
$path
|
|
||||||
EOF
|
|
||||||
popd >/dev/null
|
|
||||||
done
|
|
||||||
|
|
||||||
for ((; i < $mount_count; i++)); do
|
|
||||||
printf "Mounting fs %i/%i...\r" "$((i + 1))" "$mount_count"
|
|
||||||
|
|
||||||
mp_i=$((i % top_level_mounts))
|
|
||||||
|
|
||||||
pushd share/mnt$mp_i >/dev/null
|
|
||||||
path=mnt$mp_i
|
|
||||||
while true; do
|
|
||||||
sub_mp="$(echo mnt*)"
|
|
||||||
if cd sub 2>/dev/null; then
|
|
||||||
path="$path/sub"
|
|
||||||
elif [ -n "$sub_mp" ] && cd "$sub_mp" 2>/dev/null; then
|
|
||||||
path="$path/$sub_mp"
|
|
||||||
else
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
mkdir mnt$i
|
|
||||||
touch mnt$i/not-mounted
|
|
||||||
sudo mount "${devs[i]}" mnt$i
|
|
||||||
sudo chown "$(id -u):$(id -g)" mnt$i
|
|
||||||
|
|
||||||
cd mnt$i
|
|
||||||
path="$path/mnt$i"
|
|
||||||
nesting=$((RANDOM % 4))
|
|
||||||
for ((j = 0; j < $nesting; j++)); do
|
|
||||||
cat > some-file <<EOF
|
|
||||||
$i
|
|
||||||
$path
|
|
||||||
EOF
|
|
||||||
mkdir sub
|
|
||||||
cd sub
|
|
||||||
path="$path/sub"
|
|
||||||
done
|
|
||||||
cat > some-file <<EOF
|
|
||||||
$i
|
|
||||||
$path
|
|
||||||
EOF
|
|
||||||
popd >/dev/null
|
|
||||||
done
|
|
||||||
echo
|
|
||||||
|
|
||||||
echo 'Done.'
|
|
|
@ -11,6 +11,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
|
#include "qemu/range.h"
|
||||||
|
|
||||||
#include <wordexp.h>
|
#include <wordexp.h>
|
||||||
|
|
||||||
|
@ -211,7 +212,7 @@ void fuzz_dma_read_cb(size_t addr, size_t len, MemoryRegion *mr)
|
||||||
i < dma_regions->len && (avoid_double_fetches || qtest_log_enabled);
|
i < dma_regions->len && (avoid_double_fetches || qtest_log_enabled);
|
||||||
++i) {
|
++i) {
|
||||||
region = g_array_index(dma_regions, address_range, i);
|
region = g_array_index(dma_regions, address_range, i);
|
||||||
if (addr < region.addr + region.size && addr + len > region.addr) {
|
if (ranges_overlap(addr, len, region.addr, region.size)) {
|
||||||
double_fetch = true;
|
double_fetch = true;
|
||||||
if (addr < region.addr
|
if (addr < region.addr
|
||||||
&& avoid_double_fetches) {
|
&& avoid_double_fetches) {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
slow_qtests = {
|
slow_qtests = {
|
||||||
'aspeed_smc-test': 360,
|
'aspeed_smc-test': 360,
|
||||||
'bios-tables-test' : 610,
|
'bios-tables-test' : 910,
|
||||||
'cdrom-test' : 610,
|
'cdrom-test' : 610,
|
||||||
'device-introspect-test' : 720,
|
'device-introspect-test' : 720,
|
||||||
'migration-test' : 480,
|
'migration-test' : 480,
|
||||||
|
|
Loading…
Reference in New Issue