* Fix spurious EOFError messages from the device-crash-test script
* Fix various issues in the functional tests that pylint complained about * Improve logging information in the functional tests * Fix issue in the s390x clock-comparator code * Use address generation for register branch targets on s390x -----BEGIN PGP SIGNATURE----- iQJFBAABCgAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmkIincRHHRodXRoQHJl ZGhhdC5jb20ACgkQLtnXdP5wLbUpBg/+KQsh+JNxymwft6ohIiyUqP1vNFYbWMty MPRLhInAfT55Hkf6wBX0+WbhqePXvVcThjahh8+2ZlX7/9RVKA5xYn2zLe+tZc8P YayVfw0ferJkDoY5UjtQS2RxSpKvs+DaSEpnKzCXA5T5ytth70wM4doQ5h65qz45 31dLyBhkYLATF00otT62iKzcudpZosxdkC1nPd5FZDM5nXjzeA8CfdsWTW/wa7Kq OuMM9a9f7jp3i4OCsyOaPoHhZisP+RK/26m+cMFk2JR41anK4SZ5neunFYre5blg W1JkVI+JSLunPfNpKqAKPMPiJ4mKu0vxTeFsY6NMzeRINnr4ctoJf2zED1eMk+R5 qEJWZfcjXAfMHF0VGvmMHbISCygJXBUMjK0I58N2hJbQPinGiQvQMM8M8S+S3bUm 0bQxYJPB9ipIz2N3j/xcgQV60df7ut9qp1buVC9XyRiozkUadjFJBCFtB9+Fum+6 MmXwW94LZbKBYiB7gtEjnLdaqCyua5pnFqQG3BbWgpEpXbNlNVTw9cajKhqTD+H+ R63wPSojo0jc2idmdJCVeUxxQFW/tpWdBXQ0fDRAqIkTTZhF4e+vM82aPd61jpDO M4gFsddTXNDhElAw14/RK+wtIZQHliaSQSxRrzpb8n0tKR+41XvBKIsqYBQUDN3o 7xe3j9SzpU4= =fyHW -----END PGP SIGNATURE----- Merge tag 'pull-request-2025-11-03' of https://gitlab.com/thuth/qemu into staging * Fix spurious EOFError messages from the device-crash-test script * Fix various issues in the functional tests that pylint complained about * Improve logging information in the functional tests * Fix issue in the s390x clock-comparator code * Use address generation for register branch targets on s390x # -----BEGIN PGP SIGNATURE----- # # iQJFBAABCgAvFiEEJ7iIR+7gJQEY8+q5LtnXdP5wLbUFAmkIincRHHRodXRoQHJl # ZGhhdC5jb20ACgkQLtnXdP5wLbUpBg/+KQsh+JNxymwft6ohIiyUqP1vNFYbWMty # MPRLhInAfT55Hkf6wBX0+WbhqePXvVcThjahh8+2ZlX7/9RVKA5xYn2zLe+tZc8P # YayVfw0ferJkDoY5UjtQS2RxSpKvs+DaSEpnKzCXA5T5ytth70wM4doQ5h65qz45 # 31dLyBhkYLATF00otT62iKzcudpZosxdkC1nPd5FZDM5nXjzeA8CfdsWTW/wa7Kq # OuMM9a9f7jp3i4OCsyOaPoHhZisP+RK/26m+cMFk2JR41anK4SZ5neunFYre5blg # W1JkVI+JSLunPfNpKqAKPMPiJ4mKu0vxTeFsY6NMzeRINnr4ctoJf2zED1eMk+R5 # qEJWZfcjXAfMHF0VGvmMHbISCygJXBUMjK0I58N2hJbQPinGiQvQMM8M8S+S3bUm # 0bQxYJPB9ipIz2N3j/xcgQV60df7ut9qp1buVC9XyRiozkUadjFJBCFtB9+Fum+6 # MmXwW94LZbKBYiB7gtEjnLdaqCyua5pnFqQG3BbWgpEpXbNlNVTw9cajKhqTD+H+ # R63wPSojo0jc2idmdJCVeUxxQFW/tpWdBXQ0fDRAqIkTTZhF4e+vM82aPd61jpDO # M4gFsddTXNDhElAw14/RK+wtIZQHliaSQSxRrzpb8n0tKR+41XvBKIsqYBQUDN3o # 7xe3j9SzpU4= # =fyHW # -----END PGP SIGNATURE----- # gpg: Signature made Mon 03 Nov 2025 11:56:55 AM CET # gpg: using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5 # gpg: issuer "thuth@redhat.com" # gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [unknown] # gpg: aka "Thomas Huth <thuth@redhat.com>" [unknown] # gpg: aka "Thomas Huth <th.huth@posteo.de>" [unknown] # gpg: aka "Thomas Huth <huth@tuxfamily.org>" [unknown] # gpg: WARNING: The key's User ID is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 27B8 8847 EEE0 2501 18F3 EAB9 2ED9 D774 FE70 2DB5 * tag 'pull-request-2025-11-03' of https://gitlab.com/thuth/qemu: (22 commits) tests/tcg/s390x: Test SET CLOCK COMPARATOR target/s390x: Use address generation for register branch targets target/s390x: Fix missing clock-comparator interrupts after reset target/s390x: Fix missing interrupts for small CKC values hw/s390x: Use memory_region_size() tests/functional: include the lower level QMP log messages tests/functional: include logger name and function in messages tests/functional/ppc64: Fix class names to silence pylint warnings tests/functional/x86_64/test_virtio_balloon: Fix cosmetic issues from pylint tests/functional/x86_64/test_acpi_bits: Silence warnings reported by pylint tests/functional/rx/test_gdbsim: Remove unused variables tests/functional/ppc64/test_mac99: Fix style issues reported by pylint tests/functional/migration: Fix bad indentation MAINTAINERS: fix functional tests section tests/functional/.../testcase.py: better socketdir cleanup tests/functional/arm/test_aspeed_ast1030: Remove unused import tests/functional: Fix problems in utils.py reported by pylint tests/functional: Fix problems in uncompress.py reported by pylint tests/functional: Fix problems in linuxkernel.py reported by pylint tests/functional: Fix problems in decorators.py reported by pylint ... Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
7ae004869a
25 changed files with 262 additions and 179 deletions
|
|
@ -4423,6 +4423,7 @@ Functional testing framework
|
|||
M: Thomas Huth <thuth@redhat.com>
|
||||
R: Philippe Mathieu-Daudé <philmd@linaro.org>
|
||||
R: Daniel P. Berrange <berrange@redhat.com>
|
||||
S: Maintained
|
||||
F: docs/devel/testing/functional.rst
|
||||
F: scripts/clean_functional_cache.py
|
||||
F: tests/functional/qemu_test/
|
||||
|
|
|
|||
|
|
@ -396,7 +396,7 @@ static MemoryRegion *s390_get_subregion(MemoryRegion *mr, uint64_t offset,
|
|||
uint64_t subregion_size;
|
||||
|
||||
QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) {
|
||||
subregion_size = int128_get64(subregion->size);
|
||||
subregion_size = memory_region_size(subregion);
|
||||
if ((offset >= subregion->addr) &&
|
||||
(offset + len) <= (subregion->addr + subregion_size)) {
|
||||
mr = subregion;
|
||||
|
|
|
|||
|
|
@ -527,7 +527,7 @@ def main():
|
|||
# Async QMP, when in use, is chatty about connection failures.
|
||||
# This script knowingly generates a ton of connection errors.
|
||||
# Silence this logger.
|
||||
logging.getLogger('qemu.qmp.qmp_client').setLevel(logging.CRITICAL)
|
||||
logging.getLogger('qemu.qmp.protocol').setLevel(logging.CRITICAL)
|
||||
|
||||
fatal_failures = []
|
||||
wl_stats = {}
|
||||
|
|
|
|||
|
|
@ -1959,6 +1959,10 @@ void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
|
|||
if (env->cregs[i] != val && i >= 9 && i <= 11) {
|
||||
PERchanged = true;
|
||||
}
|
||||
if (i == 0 && !(env->cregs[i] & CR0_CKC_SC) && (val & CR0_CKC_SC)) {
|
||||
BQL_LOCK_GUARD();
|
||||
tcg_s390_tod_updated(env_cpu(env), RUN_ON_CPU_NULL);
|
||||
}
|
||||
env->cregs[i] = val;
|
||||
HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n",
|
||||
i, src, val);
|
||||
|
|
@ -1989,10 +1993,15 @@ void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3)
|
|||
|
||||
for (i = r1;; i = (i + 1) % 16) {
|
||||
uint32_t val = cpu_ldl_data_ra(env, src, ra);
|
||||
uint64_t val64 = deposit64(env->cregs[i], 0, 32, val);
|
||||
if ((uint32_t)env->cregs[i] != val && i >= 9 && i <= 11) {
|
||||
PERchanged = true;
|
||||
}
|
||||
env->cregs[i] = deposit64(env->cregs[i], 0, 32, val);
|
||||
if (i == 0 && !(env->cregs[i] & CR0_CKC_SC) && (val64 & CR0_CKC_SC)) {
|
||||
BQL_LOCK_GUARD();
|
||||
tcg_s390_tod_updated(env_cpu(env), RUN_ON_CPU_NULL);
|
||||
}
|
||||
env->cregs[i] = val64;
|
||||
HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%x\n", i, src, val);
|
||||
src += sizeof(uint32_t);
|
||||
|
||||
|
|
|
|||
|
|
@ -199,11 +199,15 @@ static void update_ckc_timer(CPUS390XState *env)
|
|||
return;
|
||||
}
|
||||
|
||||
/* difference between origins */
|
||||
time = env->ckc - td->base.low;
|
||||
if (env->ckc < td->base.low) {
|
||||
time = 0;
|
||||
} else {
|
||||
/* difference between origins */
|
||||
time = env->ckc - td->base.low;
|
||||
|
||||
/* nanoseconds */
|
||||
time = tod2time(time);
|
||||
/* nanoseconds */
|
||||
time = tod2time(time);
|
||||
}
|
||||
|
||||
timer_mod(env->tod_timer, time);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5613,6 +5613,7 @@ static void in2_r2_nz(DisasContext *s, DisasOps *o)
|
|||
int r2 = get_field(s, r2);
|
||||
if (r2 != 0) {
|
||||
o->in2 = load_reg(r2);
|
||||
gen_addi_and_wrap_i64(s, o->in2, o->in2, 0);
|
||||
}
|
||||
}
|
||||
#define SPEC_in2_r2_nz 0
|
||||
|
|
@ -6379,10 +6380,12 @@ static void s390x_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
|
|||
{
|
||||
DisasContext *dc = container_of(dcbase, DisasContext, base);
|
||||
|
||||
/* 31-bit mode */
|
||||
if (!(dc->base.tb->flags & FLAG_MASK_64)) {
|
||||
dc->base.pc_first &= 0x7fffffff;
|
||||
dc->base.pc_next = dc->base.pc_first;
|
||||
if (dc->base.tb->flags & FLAG_MASK_32) {
|
||||
if (!(dc->base.tb->flags & FLAG_MASK_64)) {
|
||||
assert(!(dc->base.pc_first & ~((1ULL << 31) - 1)));
|
||||
}
|
||||
} else {
|
||||
assert(!(dc->base.pc_first & ~((1ULL << 24) - 1)));
|
||||
}
|
||||
|
||||
dc->cc_op = CC_OP_DYNAMIC;
|
||||
|
|
|
|||
|
|
@ -6,9 +6,8 @@
|
|||
#
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
from qemu_test import LinuxKernelTest, Asset
|
||||
from aspeed import AspeedTest
|
||||
from qemu_test import exec_command_and_wait_for_pattern
|
||||
from qemu_test import Asset, exec_command_and_wait_for_pattern
|
||||
|
||||
|
||||
class AST1030Machine(AspeedTest):
|
||||
|
|
|
|||
|
|
@ -30,11 +30,11 @@ class MigrationTest(QemuSystemTest):
|
|||
|
||||
end = time.monotonic() + self.timeout
|
||||
while time.monotonic() < end and not self.migration_finished(src_vm):
|
||||
time.sleep(0.1)
|
||||
time.sleep(0.1)
|
||||
|
||||
end = time.monotonic() + self.timeout
|
||||
while time.monotonic() < end and not self.migration_finished(dst_vm):
|
||||
time.sleep(0.1)
|
||||
time.sleep(0.1)
|
||||
|
||||
self.assertEqual(src_vm.cmd('query-migrate')['status'], 'completed')
|
||||
self.assertEqual(dst_vm.cmd('query-migrate')['status'], 'completed')
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
from qemu_test import QemuSystemTest
|
||||
from qemu_test import wait_for_console_pattern
|
||||
|
||||
class ppc74xxCpu(QemuSystemTest):
|
||||
class Ppc74xxCpu(QemuSystemTest):
|
||||
|
||||
timeout = 5
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,11 @@ from qemu_test import LinuxKernelTest, Asset
|
|||
from qemu_test import exec_command_and_wait_for_pattern
|
||||
|
||||
|
||||
class sam460exTest(LinuxKernelTest):
|
||||
class Sam460exTest(LinuxKernelTest):
|
||||
|
||||
ASSET_BR2_SAM460EX_LINUX = Asset(
|
||||
'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/buildroot/qemu_ppc_sam460ex-2023.11-8-gdcd9f0f6eb-20240105/vmlinux',
|
||||
('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main'
|
||||
'/buildroot/qemu_ppc_sam460ex-2023.11-8-gdcd9f0f6eb-20240105/vmlinux'),
|
||||
'6f46346f3e20e8b5fc050ff363f350f8b9d76a051b9e0bd7ea470cc680c14df2')
|
||||
|
||||
def test_ppc_sam460ex_buildroot(self):
|
||||
|
|
|
|||
|
|
@ -7,14 +7,16 @@
|
|||
from qemu_test import LinuxKernelTest, Asset
|
||||
from qemu_test import exec_command_and_wait_for_pattern
|
||||
|
||||
class mac99Test(LinuxKernelTest):
|
||||
class Mac99Test(LinuxKernelTest):
|
||||
|
||||
ASSET_BR2_MAC99_LINUX = Asset(
|
||||
'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main/buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/vmlinux',
|
||||
('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main'
|
||||
'/buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/vmlinux'),
|
||||
'd59307437e4365f2cced0bbd1b04949f7397b282ef349b7cafd894d74aadfbff')
|
||||
|
||||
ASSET_BR2_MAC99_ROOTFS = Asset(
|
||||
'https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main//buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/rootfs.ext2',
|
||||
('https://github.com/legoater/qemu-ppc-boot/raw/refs/heads/main'
|
||||
'/buildroot/qemu_ppc64_mac99-2023.11-8-gdcd9f0f6eb-20240105/rootfs.ext2'),
|
||||
'bbd5fd8af62f580bc4e585f326fe584e22856572633a8333178ea6d4ed4955a4')
|
||||
|
||||
def test_ppc64_mac99_buildroot(self):
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
from qemu_test import LinuxKernelTest, Asset
|
||||
from qemu_test import wait_for_console_pattern
|
||||
|
||||
class powernvMachine(LinuxKernelTest):
|
||||
class PowernvMachine(LinuxKernelTest):
|
||||
|
||||
timeout = 90
|
||||
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 console=hvc0 '
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
from qemu_test import QemuSystemTest, Asset
|
||||
from qemu_test import wait_for_console_pattern
|
||||
|
||||
class pseriesMachine(QemuSystemTest):
|
||||
class PseriesMachine(QemuSystemTest):
|
||||
|
||||
timeout = 90
|
||||
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 console=hvc0 '
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ from qemu_test import skipFlakyTest
|
|||
from reverse_debugging import ReverseDebugging
|
||||
|
||||
|
||||
class ReverseDebugging_ppc64(ReverseDebugging):
|
||||
class ReverseDebuggingPpc64(ReverseDebugging):
|
||||
|
||||
@skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/1992")
|
||||
def test_ppc64_pseries(self):
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ class Asset:
|
|||
return False
|
||||
|
||||
self.log.debug("Time out while waiting for %s!", tmp_cache_file)
|
||||
raise
|
||||
raise TimeoutError(f"Time out while waiting for {tmp_cache_file}")
|
||||
|
||||
def _save_time_stamp(self):
|
||||
'''
|
||||
|
|
@ -141,7 +141,7 @@ class Asset:
|
|||
self.log.info("Downloading %s to %s...", self.url, self.cache_file)
|
||||
tmp_cache_file = self.cache_file.with_suffix(".download")
|
||||
|
||||
for retries in range(3):
|
||||
for _retries in range(3):
|
||||
try:
|
||||
with tmp_cache_file.open("xb") as dst:
|
||||
with urllib.request.urlopen(self.url) as resp:
|
||||
|
|
@ -181,7 +181,7 @@ class Asset:
|
|||
# server or networking problem
|
||||
if e.code == 404:
|
||||
raise AssetError(self, "Unable to download: "
|
||||
"HTTP error %d" % e.code)
|
||||
"HTTP error %d" % e.code) from e
|
||||
continue
|
||||
except URLError as e:
|
||||
# This is typically a network/service level error
|
||||
|
|
@ -190,7 +190,7 @@ class Asset:
|
|||
self.log.error("Unable to download %s: URL error %s",
|
||||
self.url, e.reason)
|
||||
raise AssetError(self, "Unable to download: URL error %s" %
|
||||
e.reason, transient=True)
|
||||
e.reason, transient=True) from e
|
||||
except ConnectionError as e:
|
||||
# A socket connection failure, such as dropped conn
|
||||
# or refused conn
|
||||
|
|
@ -201,7 +201,7 @@ class Asset:
|
|||
except Exception as e:
|
||||
tmp_cache_file.unlink()
|
||||
raise AssetError(self, "Unable to download: %s" % e,
|
||||
transient=True)
|
||||
transient=True) from e
|
||||
|
||||
if not os.path.exists(tmp_cache_file):
|
||||
raise AssetError(self, "Download retries exceeded", transient=True)
|
||||
|
|
@ -214,7 +214,6 @@ class Asset:
|
|||
self.hash.encode('utf8'))
|
||||
except Exception as e:
|
||||
self.log.debug("Unable to set xattr on %s: %s", tmp_cache_file, e)
|
||||
pass
|
||||
|
||||
if not self._check(tmp_cache_file):
|
||||
tmp_cache_file.unlink()
|
||||
|
|
@ -224,9 +223,10 @@ class Asset:
|
|||
# Remove write perms to stop tests accidentally modifying them
|
||||
os.chmod(self.cache_file, stat.S_IRUSR | stat.S_IRGRP)
|
||||
|
||||
self.log.info("Cached %s at %s" % (self.url, self.cache_file))
|
||||
self.log.info("Cached %s at %s", self.url, self.cache_file)
|
||||
return str(self.cache_file)
|
||||
|
||||
@staticmethod
|
||||
def precache_test(test):
|
||||
log = logging.getLogger('qemu-test')
|
||||
log.setLevel(logging.DEBUG)
|
||||
|
|
@ -237,16 +237,17 @@ class Asset:
|
|||
handler.setFormatter(formatter)
|
||||
log.addHandler(handler)
|
||||
for name, asset in vars(test.__class__).items():
|
||||
if name.startswith("ASSET_") and type(asset) == Asset:
|
||||
if name.startswith("ASSET_") and isinstance(asset, Asset):
|
||||
try:
|
||||
asset.fetch()
|
||||
except AssetError as e:
|
||||
if not e.transient:
|
||||
raise
|
||||
log.error("%s: skipping asset precache" % e)
|
||||
log.error("%s: skipping asset precache", e)
|
||||
|
||||
log.removeHandler(handler)
|
||||
|
||||
@staticmethod
|
||||
def precache_suite(suite):
|
||||
for test in suite:
|
||||
if isinstance(test, unittest.TestSuite):
|
||||
|
|
@ -254,9 +255,10 @@ class Asset:
|
|||
elif isinstance(test, unittest.TestCase):
|
||||
Asset.precache_test(test)
|
||||
|
||||
def precache_suites(path, cacheTstamp):
|
||||
@staticmethod
|
||||
def precache_suites(path, cache_tstamp):
|
||||
loader = unittest.loader.defaultTestLoader
|
||||
tests = loader.loadTestsFromNames([path], None)
|
||||
|
||||
with open(cacheTstamp, "w") as fh:
|
||||
with open(cache_tstamp, "w", encoding='utf-8'):
|
||||
Asset.precache_suite(tests)
|
||||
|
|
|
|||
|
|
@ -10,136 +10,134 @@ from unittest import skipIf, skipUnless
|
|||
|
||||
from .cmd import which
|
||||
|
||||
'''
|
||||
Decorator to skip execution of a test if the provided
|
||||
environment variables are not set.
|
||||
Example:
|
||||
|
||||
@skipIfMissingEnv("QEMU_ENV_VAR0", "QEMU_ENV_VAR1")
|
||||
'''
|
||||
def skipIfMissingEnv(*vars_):
|
||||
'''
|
||||
Decorator to skip execution of a test if the provided
|
||||
environment variables are not set.
|
||||
Example:
|
||||
|
||||
@skipIfMissingEnv("QEMU_ENV_VAR0", "QEMU_ENV_VAR1")
|
||||
'''
|
||||
missing_vars = []
|
||||
for var in vars_:
|
||||
if os.getenv(var) == None:
|
||||
if os.getenv(var) is None:
|
||||
missing_vars.append(var)
|
||||
|
||||
has_vars = True if len(missing_vars) == 0 else False
|
||||
has_vars = len(missing_vars) == 0
|
||||
|
||||
return skipUnless(has_vars, f"Missing env var(s): {', '.join(missing_vars)}")
|
||||
|
||||
'''
|
||||
|
||||
Decorator to skip execution of a test if the list
|
||||
of command binaries is not available in $PATH.
|
||||
Example:
|
||||
|
||||
@skipIfMissingCommands("mkisofs", "losetup")
|
||||
'''
|
||||
def skipIfMissingCommands(*args):
|
||||
'''
|
||||
Decorator to skip execution of a test if the list
|
||||
of command binaries is not available in $PATH.
|
||||
Example:
|
||||
|
||||
@skipIfMissingCommands("mkisofs", "losetup")
|
||||
'''
|
||||
has_cmds = True
|
||||
for cmd in args:
|
||||
if not which(cmd):
|
||||
has_cmds = False
|
||||
break
|
||||
if not which(cmd):
|
||||
has_cmds = False
|
||||
break
|
||||
|
||||
return skipUnless(has_cmds, 'required command(s) "%s" not installed' %
|
||||
", ".join(args))
|
||||
|
||||
'''
|
||||
Decorator to skip execution of a test if the current
|
||||
host operating system does match one of the prohibited
|
||||
ones.
|
||||
Example
|
||||
|
||||
@skipIfOperatingSystem("Linux", "Darwin")
|
||||
'''
|
||||
def skipIfOperatingSystem(*args):
|
||||
'''
|
||||
Decorator to skip execution of a test if the current host
|
||||
operating system does match one of the prohibited ones.
|
||||
Example:
|
||||
|
||||
@skipIfOperatingSystem("Linux", "Darwin")
|
||||
'''
|
||||
return skipIf(platform.system() in args,
|
||||
'running on an OS (%s) that is not able to run this test' %
|
||||
", ".join(args))
|
||||
|
||||
'''
|
||||
Decorator to skip execution of a test if the current
|
||||
host machine does not match one of the permitted
|
||||
machines.
|
||||
Example
|
||||
|
||||
@skipIfNotMachine("x86_64", "aarch64")
|
||||
'''
|
||||
def skipIfNotMachine(*args):
|
||||
'''
|
||||
Decorator to skip execution of a test if the current
|
||||
host machine does not match one of the permitted machines.
|
||||
Example:
|
||||
|
||||
@skipIfNotMachine("x86_64", "aarch64")
|
||||
'''
|
||||
return skipUnless(platform.machine() in args,
|
||||
'not running on one of the required machine(s) "%s"' %
|
||||
", ".join(args))
|
||||
|
||||
'''
|
||||
Decorator to skip execution of flaky tests, unless
|
||||
the $QEMU_TEST_FLAKY_TESTS environment variable is set.
|
||||
A bug URL must be provided that documents the observed
|
||||
failure behaviour, so it can be tracked & re-evaluated
|
||||
in future.
|
||||
|
||||
Historical tests may be providing "None" as the bug_url
|
||||
but this should not be done for new test.
|
||||
|
||||
Example:
|
||||
|
||||
@skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/NNN")
|
||||
'''
|
||||
def skipFlakyTest(bug_url):
|
||||
'''
|
||||
Decorator to skip execution of flaky tests, unless
|
||||
the $QEMU_TEST_FLAKY_TESTS environment variable is set.
|
||||
A bug URL must be provided that documents the observed
|
||||
failure behaviour, so it can be tracked & re-evaluated
|
||||
in future.
|
||||
|
||||
Historical tests may be providing "None" as the bug_url
|
||||
but this should not be done for new test.
|
||||
|
||||
Example:
|
||||
|
||||
@skipFlakyTest("https://gitlab.com/qemu-project/qemu/-/issues/NNN")
|
||||
'''
|
||||
if bug_url is None:
|
||||
bug_url = "FIXME: reproduce flaky test and file bug report or remove"
|
||||
return skipUnless(os.getenv('QEMU_TEST_FLAKY_TESTS'),
|
||||
f'Test is unstable: {bug_url}')
|
||||
|
||||
'''
|
||||
Decorator to skip execution of tests which are likely
|
||||
to execute untrusted commands on the host, or commands
|
||||
which process untrusted code, unless the
|
||||
$QEMU_TEST_ALLOW_UNTRUSTED_CODE env var is set.
|
||||
Example:
|
||||
|
||||
@skipUntrustedTest()
|
||||
'''
|
||||
def skipUntrustedTest():
|
||||
'''
|
||||
Decorator to skip execution of tests which are likely
|
||||
to execute untrusted commands on the host, or commands
|
||||
which process untrusted code, unless the
|
||||
$QEMU_TEST_ALLOW_UNTRUSTED_CODE env var is set.
|
||||
Example:
|
||||
|
||||
@skipUntrustedTest()
|
||||
'''
|
||||
return skipUnless(os.getenv('QEMU_TEST_ALLOW_UNTRUSTED_CODE'),
|
||||
'Test runs untrusted code / processes untrusted data')
|
||||
|
||||
'''
|
||||
Decorator to skip execution of tests which need large
|
||||
data storage (over around 500MB-1GB mark) on the host,
|
||||
unless the $QEMU_TEST_ALLOW_LARGE_STORAGE environment
|
||||
variable is set
|
||||
|
||||
Example:
|
||||
|
||||
@skipBigDataTest()
|
||||
'''
|
||||
def skipBigDataTest():
|
||||
'''
|
||||
Decorator to skip execution of tests which need large
|
||||
data storage (over around 500MB-1GB mark) on the host,
|
||||
unless the $QEMU_TEST_ALLOW_LARGE_STORAGE environment
|
||||
variable is set
|
||||
|
||||
Example:
|
||||
|
||||
@skipBigDataTest()
|
||||
'''
|
||||
return skipUnless(os.getenv('QEMU_TEST_ALLOW_LARGE_STORAGE'),
|
||||
'Test requires large host storage space')
|
||||
|
||||
'''
|
||||
Decorator to skip execution of tests which have a really long
|
||||
runtime (and might e.g. time out if QEMU has been compiled with
|
||||
debugging enabled) unless the $QEMU_TEST_ALLOW_SLOW
|
||||
environment variable is set
|
||||
|
||||
Example:
|
||||
|
||||
@skipSlowTest()
|
||||
'''
|
||||
def skipSlowTest():
|
||||
'''
|
||||
Decorator to skip execution of tests which have a really long
|
||||
runtime (and might e.g. time out if QEMU has been compiled with
|
||||
debugging enabled) unless the $QEMU_TEST_ALLOW_SLOW
|
||||
environment variable is set
|
||||
|
||||
Example:
|
||||
|
||||
@skipSlowTest()
|
||||
'''
|
||||
return skipUnless(os.getenv('QEMU_TEST_ALLOW_SLOW'),
|
||||
'Test has a very long runtime and might time out')
|
||||
|
||||
'''
|
||||
Decorator to skip execution of a test if the list
|
||||
of python imports is not available.
|
||||
Example:
|
||||
|
||||
@skipIfMissingImports("numpy", "cv2")
|
||||
'''
|
||||
def skipIfMissingImports(*args):
|
||||
'''
|
||||
Decorator to skip execution of a test if the list
|
||||
of python imports is not available.
|
||||
Example:
|
||||
|
||||
@skipIfMissingImports("numpy", "cv2")
|
||||
'''
|
||||
has_imports = True
|
||||
for impname in args:
|
||||
try:
|
||||
|
|
@ -151,15 +149,15 @@ def skipIfMissingImports(*args):
|
|||
return skipUnless(has_imports, 'required import(s) "%s" not installed' %
|
||||
", ".join(args))
|
||||
|
||||
'''
|
||||
Decorator to skip execution of a test if the system's
|
||||
locked memory limit is below the required threshold.
|
||||
Takes required locked memory threshold in kB.
|
||||
Example:
|
||||
|
||||
@skipLockedMemoryTest(2_097_152)
|
||||
'''
|
||||
def skipLockedMemoryTest(locked_memory):
|
||||
'''
|
||||
Decorator to skip execution of a test if the system's
|
||||
locked memory limit is below the required threshold.
|
||||
Takes required locked memory threshold in kB.
|
||||
Example:
|
||||
|
||||
@skipLockedMemoryTest(2_097_152)
|
||||
'''
|
||||
# get memlock hard limit in bytes
|
||||
_, ulimit_memory = resource.getrlimit(resource.RLIMIT_MEMLOCK)
|
||||
|
||||
|
|
|
|||
|
|
@ -83,12 +83,12 @@ class LinuxKernelTest(QemuSystemTest):
|
|||
self.vm.set_console(console_index=console_index)
|
||||
self.vm.add_args('-kernel', kernel)
|
||||
if initrd:
|
||||
self.vm.add_args('-initrd', initrd)
|
||||
self.vm.add_args('-initrd', initrd)
|
||||
if dtb:
|
||||
self.vm.add_args('-dtb', dtb)
|
||||
self.vm.add_args('-dtb', dtb)
|
||||
self.vm.launch()
|
||||
if wait_for:
|
||||
self.wait_for_console_pattern(wait_for)
|
||||
self.wait_for_console_pattern(wait_for)
|
||||
|
||||
def check_http_download(self, filename, hashsum, guestport=8080,
|
||||
pythoncmd='python3 -m http.server'):
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ class QemuBaseTest(unittest.TestCase):
|
|||
self._log_fh = logging.FileHandler(self.log_filename, mode='w')
|
||||
self._log_fh.setLevel(logging.DEBUG)
|
||||
fileFormatter = logging.Formatter(
|
||||
'%(asctime)s - %(levelname)s: %(message)s')
|
||||
'%(asctime)s - %(levelname)s: %(name)s.%(funcName)s %(message)s')
|
||||
self._log_fh.setFormatter(fileFormatter)
|
||||
self.log.addHandler(self._log_fh)
|
||||
|
||||
|
|
@ -225,6 +225,9 @@ class QemuBaseTest(unittest.TestCase):
|
|||
self.machinelog = logging.getLogger('qemu.machine')
|
||||
self.machinelog.setLevel(logging.DEBUG)
|
||||
self.machinelog.addHandler(self._log_fh)
|
||||
self.qmplog = logging.getLogger('qemu.qmp')
|
||||
self.qmplog.setLevel(logging.DEBUG)
|
||||
self.qmplog.addHandler(self._log_fh)
|
||||
|
||||
if not self.assets_available():
|
||||
self.skipTest('One or more assets is not available')
|
||||
|
|
@ -233,8 +236,9 @@ class QemuBaseTest(unittest.TestCase):
|
|||
if "QEMU_TEST_KEEP_SCRATCH" not in os.environ:
|
||||
shutil.rmtree(self.workdir)
|
||||
if self.socketdir is not None:
|
||||
shutil.rmtree(self.socketdir.name)
|
||||
self.socketdir.cleanup()
|
||||
self.socketdir = None
|
||||
self.qmplog.removeHandler(self._log_fh)
|
||||
self.machinelog.removeHandler(self._log_fh)
|
||||
self.log.removeHandler(self._log_fh)
|
||||
self._log_fh.close()
|
||||
|
|
|
|||
|
|
@ -58,20 +58,20 @@ def zstd_uncompress(zstd_path, output_path):
|
|||
os.chmod(output_path, stat.S_IRUSR | stat.S_IWUSR)
|
||||
|
||||
|
||||
'''
|
||||
@params compressed: filename, Asset, or file-like object to uncompress
|
||||
@params uncompressed: filename to uncompress into
|
||||
@params format: optional compression format (gzip, lzma)
|
||||
|
||||
Uncompresses @compressed into @uncompressed
|
||||
|
||||
If @format is None, heuristics will be applied to guess the format
|
||||
from the filename or Asset URL. @format must be non-None if @uncompressed
|
||||
is a file-like object.
|
||||
|
||||
Returns the fully qualified path to the uncompessed file
|
||||
'''
|
||||
def uncompress(compressed, uncompressed, format=None):
|
||||
'''
|
||||
@params compressed: filename, Asset, or file-like object to uncompress
|
||||
@params uncompressed: filename to uncompress into
|
||||
@params format: optional compression format (gzip, lzma)
|
||||
|
||||
Uncompresses @compressed into @uncompressed
|
||||
|
||||
If @format is None, heuristics will be applied to guess the
|
||||
format from the filename or Asset URL. @format must be non-None
|
||||
if @uncompressed is a file-like object.
|
||||
|
||||
Returns the fully qualified path to the uncompessed file
|
||||
'''
|
||||
if format is None:
|
||||
format = guess_uncompress_format(compressed)
|
||||
|
||||
|
|
@ -84,19 +84,19 @@ def uncompress(compressed, uncompressed, format=None):
|
|||
else:
|
||||
raise Exception(f"Unknown compression format {format}")
|
||||
|
||||
'''
|
||||
@params compressed: filename, Asset, or file-like object to guess
|
||||
|
||||
Guess the format of @compressed, raising an exception if
|
||||
no format can be determined
|
||||
'''
|
||||
def guess_uncompress_format(compressed):
|
||||
if type(compressed) == Asset:
|
||||
'''
|
||||
@params compressed: filename, Asset, or file-like object to guess
|
||||
|
||||
Guess the format of @compressed, raising an exception if
|
||||
no format can be determined
|
||||
'''
|
||||
if isinstance(compressed, Asset):
|
||||
compressed = urlparse(compressed.url).path
|
||||
elif type(compressed) != str:
|
||||
elif not isinstance(compressed, str):
|
||||
raise Exception(f"Unable to guess compression cformat for {compressed}")
|
||||
|
||||
(name, ext) = os.path.splitext(compressed)
|
||||
(_name, ext) = os.path.splitext(compressed)
|
||||
if ext == ".xz":
|
||||
return "xz"
|
||||
elif ext == ".gz":
|
||||
|
|
|
|||
|
|
@ -17,10 +17,10 @@ def get_usernet_hostfwd_port(vm):
|
|||
res = vm.cmd('human-monitor-command', command_line='info usernet')
|
||||
return get_info_usernet_hostfwd_port(res)
|
||||
|
||||
"""
|
||||
Round up to next power of 2
|
||||
"""
|
||||
def pow2ceil(x):
|
||||
"""
|
||||
Round up to next power of 2
|
||||
"""
|
||||
return 1 if x == 0 else 2**(x - 1).bit_length()
|
||||
|
||||
def file_truncate(path, size):
|
||||
|
|
@ -28,12 +28,12 @@ def file_truncate(path, size):
|
|||
with open(path, 'ab+') as fd:
|
||||
fd.truncate(size)
|
||||
|
||||
"""
|
||||
Expand file size to next power of 2
|
||||
"""
|
||||
def image_pow2ceil_expand(path):
|
||||
size = os.path.getsize(path)
|
||||
size_aligned = pow2ceil(size)
|
||||
if size != size_aligned:
|
||||
with open(path, 'ab+') as fd:
|
||||
fd.truncate(size_aligned)
|
||||
"""
|
||||
Expand file size to next power of 2
|
||||
"""
|
||||
size = os.path.getsize(path)
|
||||
size_aligned = pow2ceil(size)
|
||||
if size != size_aligned:
|
||||
with open(path, 'ab+') as fd:
|
||||
fd.truncate(size_aligned)
|
||||
|
|
|
|||
|
|
@ -17,9 +17,6 @@ from qemu_test import wait_for_console_pattern, skipFlakyTest
|
|||
|
||||
class RxGdbSimMachine(QemuSystemTest):
|
||||
|
||||
timeout = 30
|
||||
KERNEL_COMMON_COMMAND_LINE = 'printk.time=0 '
|
||||
|
||||
ASSET_UBOOT = Asset(
|
||||
('https://github.com/philmd/qemu-testing-blob/raw/rx-gdbsim/rx/gdbsim/'
|
||||
'u-boot.bin'),
|
||||
|
|
@ -47,7 +44,7 @@ class RxGdbSimMachine(QemuSystemTest):
|
|||
self.vm.launch()
|
||||
uboot_version = 'U-Boot 2016.05-rc3-23705-ga1ef3c71cb-dirty'
|
||||
wait_for_console_pattern(self, uboot_version)
|
||||
gcc_version = 'rx-unknown-linux-gcc (GCC) 9.0.0 20181105 (experimental)'
|
||||
#gcc_version = 'rx-unknown-linux-gcc (GCC) 9.0.0 20181105 (experimental)'
|
||||
# FIXME limit baudrate on chardev, else we type too fast
|
||||
# https://gitlab.com/qemu-project/qemu/-/issues/2691
|
||||
#exec_command_and_wait_for_pattern(self, 'version', gcc_version)
|
||||
|
|
@ -63,7 +60,6 @@ class RxGdbSimMachine(QemuSystemTest):
|
|||
kernel_path = self.ASSET_KERNEL.fetch()
|
||||
|
||||
self.vm.set_console()
|
||||
kernel_command_line = self.KERNEL_COMMON_COMMAND_LINE + 'earlycon'
|
||||
self.vm.add_args('-kernel', kernel_path,
|
||||
'-dtb', dtb_path,
|
||||
'-no-reboot')
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ class QEMUBitsMachine(QEMUMachine): # pylint: disable=too-few-public-methods
|
|||
"""
|
||||
def __init__(self,
|
||||
binary: str,
|
||||
*,
|
||||
args: Sequence[str] = (),
|
||||
wrapper: Sequence[str] = (),
|
||||
name: Optional[str] = None,
|
||||
|
|
@ -225,7 +226,7 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute
|
|||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
check=True)
|
||||
self.log.info("grub-mkrescue output %s" % proc.stdout)
|
||||
self.log.info("grub-mkrescue output %s", proc.stdout)
|
||||
else:
|
||||
subprocess.check_call([mkrescue_script, '-o',
|
||||
iso_file, bits_dir],
|
||||
|
|
@ -287,9 +288,8 @@ class AcpiBitsTest(QemuSystemTest): #pylint: disable=too-many-instance-attribute
|
|||
except AssertionError as e:
|
||||
self._print_log(log)
|
||||
raise e
|
||||
else:
|
||||
if os.getenv('V') or os.getenv('BITS_DEBUG'):
|
||||
self._print_log(log)
|
||||
if os.getenv('V') or os.getenv('BITS_DEBUG'):
|
||||
self._print_log(log)
|
||||
|
||||
def tearDown(self):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ class VirtioBalloonx86(QemuSystemTest):
|
|||
when = ret.get('last-update')
|
||||
assert when == 0
|
||||
stats = ret.get('stats')
|
||||
for name, val in stats.items():
|
||||
for _name, val in stats.items():
|
||||
assert val == UNSET_STATS_VALUE
|
||||
|
||||
def assert_running_stats(self, then):
|
||||
|
|
@ -87,10 +87,10 @@ class VirtioBalloonx86(QemuSystemTest):
|
|||
|
||||
now = time.time()
|
||||
|
||||
assert when > then and when < now
|
||||
assert now > when > then
|
||||
stats = ret.get('stats')
|
||||
# Stat we expect this particular Kernel to have set
|
||||
expectData = [
|
||||
expect_data = [
|
||||
"stat-available-memory",
|
||||
"stat-disk-caches",
|
||||
"stat-free-memory",
|
||||
|
|
@ -103,7 +103,7 @@ class VirtioBalloonx86(QemuSystemTest):
|
|||
"stat-total-memory",
|
||||
]
|
||||
for name, val in stats.items():
|
||||
if name in expectData:
|
||||
if name in expect_data:
|
||||
assert val != UNSET_STATS_VALUE
|
||||
else:
|
||||
assert val == UNSET_STATS_VALUE
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ ASM_TESTS = \
|
|||
mc \
|
||||
per \
|
||||
precise-smc-softmmu \
|
||||
sckc \
|
||||
ssm-early \
|
||||
stosm-early \
|
||||
stpq \
|
||||
|
|
|
|||
63
tests/tcg/s390x/sckc.S
Normal file
63
tests/tcg/s390x/sckc.S
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Test clock comparator.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
.org 0x130
|
||||
ext_old_psw:
|
||||
.org 0x1b0
|
||||
ext_new_psw:
|
||||
.quad 0x180000000, _ext /* 64-bit mode */
|
||||
.org 0x1d0
|
||||
pgm_new_psw:
|
||||
.quad 0x2000000000000,0 /* disabled wait */
|
||||
.org 0x200 /* lowcore padding */
|
||||
|
||||
.globl _start
|
||||
_start:
|
||||
lpswe start31_psw
|
||||
_start31:
|
||||
stctg %c0,%c0,c0
|
||||
oi c0+6,8 /* set clock-comparator subclass mask */
|
||||
lctlg %c0,%c0,c0
|
||||
|
||||
0:
|
||||
brasl %r14,_f /* %r14's most significant bit is 1 */
|
||||
jg 0b
|
||||
_f:
|
||||
br %r14 /* it must not end up in ext_old_psw */
|
||||
|
||||
_ext:
|
||||
stg %r0,ext_saved_r0
|
||||
|
||||
lg %r0,ext_counter
|
||||
aghi %r0,1
|
||||
stg %r0,ext_counter
|
||||
|
||||
cgfi %r0,0x1000
|
||||
jnz 0f
|
||||
lpswe success_psw
|
||||
0:
|
||||
|
||||
stck clock
|
||||
lg %r0,clock
|
||||
agfi %r0,0x40000 /* 64us * 0x1000 =~ 0.25s */
|
||||
stg %r0,clock
|
||||
sckc clock
|
||||
|
||||
lg %r0,ext_saved_r0
|
||||
lpswe ext_old_psw
|
||||
|
||||
.align 8
|
||||
start31_psw:
|
||||
.quad 0x100000080000000,_start31 /* EX, 31-bit mode */
|
||||
success_psw:
|
||||
.quad 0x2000000000000,0xfff /* see is_special_wait_psw() */
|
||||
c0:
|
||||
.skip 8
|
||||
clock:
|
||||
.quad 0
|
||||
ext_counter:
|
||||
.quad 0
|
||||
ext_saved_r0:
|
||||
.skip 8
|
||||
Loading…
Add table
Add a link
Reference in a new issue