summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/docker/dockerfiles/alpine.docker1
-rw-r--r--tests/docker/dockerfiles/fedora-i386-cross.docker1
-rw-r--r--tests/docker/dockerfiles/fedora-win32-cross.docker1
-rw-r--r--tests/docker/dockerfiles/fedora-win64-cross.docker1
-rw-r--r--tests/docker/dockerfiles/opensuse-leap.docker1
-rw-r--r--tests/fp/fp-bench.c88
-rw-r--r--tests/fp/fp-test.c2
-rw-r--r--tests/fp/wrap.c.inc12
-rwxr-xr-xtests/qemu-iotests/2314
-rw-r--r--tests/qemu-iotests/231.out7
-rw-r--r--tests/qemu-iotests/240.out8
-rw-r--r--tests/qemu-iotests/245.out8
-rwxr-xr-xtests/qemu-iotests/2642
-rw-r--r--tests/qemu-iotests/295.out6
-rw-r--r--tests/qemu-iotests/296.out8
-rwxr-xr-xtests/qemu-iotests/check19
-rw-r--r--tests/qemu-iotests/iotests.py145
-rw-r--r--tests/qemu-iotests/pylintrc3
-rw-r--r--tests/qemu-iotests/testenv.py22
-rw-r--r--tests/qemu-iotests/testrunner.py37
-rw-r--r--tests/qtest/ahci-test.c4
-rw-r--r--tests/qtest/ipmi-bt-test.c6
-rw-r--r--tests/qtest/ipmi-kcs-test.c3
-rw-r--r--tests/qtest/libqos/qgraph.c2
-rw-r--r--tests/qtest/libqtest.c9
-rw-r--r--tests/qtest/npcm7xx_pwm-test.c4
-rw-r--r--tests/qtest/rtc-test.c6
-rw-r--r--tests/qtest/tpm-util.c4
-rw-r--r--tests/unit/test-write-threshold.c90
29 files changed, 288 insertions, 216 deletions
diff --git a/tests/docker/dockerfiles/alpine.docker b/tests/docker/dockerfiles/alpine.docker
index 88d3bbe5f2..0ac46ddd91 100644
--- a/tests/docker/dockerfiles/alpine.docker
+++ b/tests/docker/dockerfiles/alpine.docker
@@ -9,6 +9,7 @@ ENV PACKAGES \
alsa-lib-dev \
bash \
binutils \
+ ccache \
coreutils \
curl-dev \
g++ \
diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker
index 966072c08e..66cdb06c19 100644
--- a/tests/docker/dockerfiles/fedora-i386-cross.docker
+++ b/tests/docker/dockerfiles/fedora-i386-cross.docker
@@ -1,6 +1,7 @@
FROM fedora:33
ENV PACKAGES \
bzip2 \
+ ccache \
diffutils \
findutils \
gcc \
diff --git a/tests/docker/dockerfiles/fedora-win32-cross.docker b/tests/docker/dockerfiles/fedora-win32-cross.docker
index 81b5659e9c..3733df63e9 100644
--- a/tests/docker/dockerfiles/fedora-win32-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win32-cross.docker
@@ -4,6 +4,7 @@ FROM fedora:33
ENV PACKAGES \
bc \
bzip2 \
+ ccache \
diffutils \
findutils \
gcc \
diff --git a/tests/docker/dockerfiles/fedora-win64-cross.docker b/tests/docker/dockerfiles/fedora-win64-cross.docker
index bcb428e724..2564ce4979 100644
--- a/tests/docker/dockerfiles/fedora-win64-cross.docker
+++ b/tests/docker/dockerfiles/fedora-win64-cross.docker
@@ -4,6 +4,7 @@ FROM fedora:33
ENV PACKAGES \
bc \
bzip2 \
+ ccache \
diffutils \
findutils \
gcc \
diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker
index 0e64893e4a..f7e1cbfbe6 100644
--- a/tests/docker/dockerfiles/opensuse-leap.docker
+++ b/tests/docker/dockerfiles/opensuse-leap.docker
@@ -5,6 +5,7 @@ ENV PACKAGES \
bc \
brlapi-devel \
bzip2 \
+ ccache \
cyrus-sasl-devel \
gcc \
gcc-c++ \
diff --git a/tests/fp/fp-bench.c b/tests/fp/fp-bench.c
index 4ba5e1d2d4..c24baf8535 100644
--- a/tests/fp/fp-bench.c
+++ b/tests/fp/fp-bench.c
@@ -14,6 +14,7 @@
#include <math.h>
#include <fenv.h>
#include "qemu/timer.h"
+#include "qemu/int128.h"
#include "fpu/softfloat.h"
/* amortize the computation of random inputs */
@@ -50,8 +51,10 @@ static const char * const op_names[] = {
enum precision {
PREC_SINGLE,
PREC_DOUBLE,
+ PREC_QUAD,
PREC_FLOAT32,
PREC_FLOAT64,
+ PREC_FLOAT128,
PREC_MAX_NR,
};
@@ -89,6 +92,7 @@ union fp {
double d;
float32 f32;
float64 f64;
+ float128 f128;
uint64_t u64;
};
@@ -113,6 +117,10 @@ struct op_desc {
static uint64_t random_ops[MAX_OPERANDS] = {
SEED_A, SEED_B, SEED_C,
};
+
+static float128 random_quad_ops[MAX_OPERANDS] = {
+ {SEED_A, SEED_B}, {SEED_B, SEED_C}, {SEED_C, SEED_A},
+};
static float_status soft_status;
static enum precision precision;
static enum op operation;
@@ -141,25 +149,45 @@ static void update_random_ops(int n_ops, enum precision prec)
int i;
for (i = 0; i < n_ops; i++) {
- uint64_t r = random_ops[i];
switch (prec) {
case PREC_SINGLE:
case PREC_FLOAT32:
+ {
+ uint64_t r = random_ops[i];
do {
r = xorshift64star(r);
} while (!float32_is_normal(r));
+ random_ops[i] = r;
break;
+ }
case PREC_DOUBLE:
case PREC_FLOAT64:
+ {
+ uint64_t r = random_ops[i];
do {
r = xorshift64star(r);
} while (!float64_is_normal(r));
+ random_ops[i] = r;
break;
+ }
+ case PREC_QUAD:
+ case PREC_FLOAT128:
+ {
+ float128 r = random_quad_ops[i];
+ uint64_t hi = r.high;
+ uint64_t lo = r.low;
+ do {
+ hi = xorshift64star(hi);
+ lo = xorshift64star(lo);
+ r = make_float128(hi, lo);
+ } while (!float128_is_normal(r));
+ random_quad_ops[i] = r;
+ break;
+ }
default:
g_assert_not_reached();
}
- random_ops[i] = r;
}
}
@@ -184,6 +212,13 @@ static void fill_random(union fp *ops, int n_ops, enum precision prec,
ops[i].f64 = float64_chs(ops[i].f64);
}
break;
+ case PREC_QUAD:
+ case PREC_FLOAT128:
+ ops[i].f128 = random_quad_ops[i];
+ if (no_neg && float128_is_neg(ops[i].f128)) {
+ ops[i].f128 = float128_chs(ops[i].f128);
+ }
+ break;
default:
g_assert_not_reached();
}
@@ -345,6 +380,41 @@ static void bench(enum precision prec, enum op op, int n_ops, bool no_neg)
}
}
break;
+ case PREC_FLOAT128:
+ fill_random(ops, n_ops, prec, no_neg);
+ t0 = get_clock();
+ for (i = 0; i < OPS_PER_ITER; i++) {
+ float128 a = ops[0].f128;
+ float128 b = ops[1].f128;
+ float128 c = ops[2].f128;
+
+ switch (op) {
+ case OP_ADD:
+ res.f128 = float128_add(a, b, &soft_status);
+ break;
+ case OP_SUB:
+ res.f128 = float128_sub(a, b, &soft_status);
+ break;
+ case OP_MUL:
+ res.f128 = float128_mul(a, b, &soft_status);
+ break;
+ case OP_DIV:
+ res.f128 = float128_div(a, b, &soft_status);
+ break;
+ case OP_FMA:
+ res.f128 = float128_muladd(a, b, c, 0, &soft_status);
+ break;
+ case OP_SQRT:
+ res.f128 = float128_sqrt(a, &soft_status);
+ break;
+ case OP_CMP:
+ res.u64 = float128_compare_quiet(a, b, &soft_status);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ }
+ break;
default:
g_assert_not_reached();
}
@@ -369,7 +439,8 @@ static void bench(enum precision prec, enum op op, int n_ops, bool no_neg)
GEN_BENCH(bench_ ## opname ## _float, float, PREC_SINGLE, op, n_ops) \
GEN_BENCH(bench_ ## opname ## _double, double, PREC_DOUBLE, op, n_ops) \
GEN_BENCH(bench_ ## opname ## _float32, float32, PREC_FLOAT32, op, n_ops) \
- GEN_BENCH(bench_ ## opname ## _float64, float64, PREC_FLOAT64, op, n_ops)
+ GEN_BENCH(bench_ ## opname ## _float64, float64, PREC_FLOAT64, op, n_ops) \
+ GEN_BENCH(bench_ ## opname ## _float128, float128, PREC_FLOAT128, op, n_ops)
GEN_BENCH_ALL_TYPES(add, OP_ADD, 2)
GEN_BENCH_ALL_TYPES(sub, OP_SUB, 2)
@@ -383,7 +454,8 @@ GEN_BENCH_ALL_TYPES(cmp, OP_CMP, 2)
GEN_BENCH_NO_NEG(bench_ ## name ## _float, float, PREC_SINGLE, op, n) \
GEN_BENCH_NO_NEG(bench_ ## name ## _double, double, PREC_DOUBLE, op, n) \
GEN_BENCH_NO_NEG(bench_ ## name ## _float32, float32, PREC_FLOAT32, op, n) \
- GEN_BENCH_NO_NEG(bench_ ## name ## _float64, float64, PREC_FLOAT64, op, n)
+ GEN_BENCH_NO_NEG(bench_ ## name ## _float64, float64, PREC_FLOAT64, op, n) \
+ GEN_BENCH_NO_NEG(bench_ ## name ## _float128, float128, PREC_FLOAT128, op, n)
GEN_BENCH_ALL_TYPES_NO_NEG(sqrt, OP_SQRT, 1)
#undef GEN_BENCH_ALL_TYPES_NO_NEG
@@ -397,6 +469,7 @@ GEN_BENCH_ALL_TYPES_NO_NEG(sqrt, OP_SQRT, 1)
[PREC_DOUBLE] = bench_ ## opname ## _double, \
[PREC_FLOAT32] = bench_ ## opname ## _float32, \
[PREC_FLOAT64] = bench_ ## opname ## _float64, \
+ [PREC_FLOAT128] = bench_ ## opname ## _float128, \
}
static const bench_func_t bench_funcs[OP_MAX_NR][PREC_MAX_NR] = {
@@ -445,7 +518,7 @@ static void usage_complete(int argc, char *argv[])
fprintf(stderr, " -h = show this help message.\n");
fprintf(stderr, " -o = floating point operation (%s). Default: %s\n",
op_list, op_names[0]);
- fprintf(stderr, " -p = floating point precision (single, double). "
+ fprintf(stderr, " -p = floating point precision (single, double, quad[soft only]). "
"Default: single\n");
fprintf(stderr, " -r = rounding mode (even, zero, down, up, tieaway). "
"Default: even\n");
@@ -565,6 +638,8 @@ static void parse_args(int argc, char *argv[])
precision = PREC_SINGLE;
} else if (!strcmp(optarg, "double")) {
precision = PREC_DOUBLE;
+ } else if (!strcmp(optarg, "quad")) {
+ precision = PREC_QUAD;
} else {
fprintf(stderr, "Unsupported precision '%s'\n", optarg);
exit(EXIT_FAILURE);
@@ -608,6 +683,9 @@ static void parse_args(int argc, char *argv[])
case PREC_DOUBLE:
precision = PREC_FLOAT64;
break;
+ case PREC_QUAD:
+ precision = PREC_FLOAT128;
+ break;
default:
g_assert_not_reached();
}
diff --git a/tests/fp/fp-test.c b/tests/fp/fp-test.c
index 5a4cad8c8b..ff131afbde 100644
--- a/tests/fp/fp-test.c
+++ b/tests/fp/fp-test.c
@@ -717,7 +717,7 @@ static void do_testfloat(int op, int rmode, bool exact)
test_abz_f128(true_abz_f128M, subj_abz_f128M);
break;
case F128_MULADD:
- not_implemented();
+ test_abcz_f128(slow_f128M_mulAdd, qemu_f128M_mulAdd);
break;
case F128_SQRT:
test_az_f128(slow_f128M_sqrt, qemu_f128M_sqrt);
diff --git a/tests/fp/wrap.c.inc b/tests/fp/wrap.c.inc
index 0cbd20013e..cb1bb77e4c 100644
--- a/tests/fp/wrap.c.inc
+++ b/tests/fp/wrap.c.inc
@@ -574,6 +574,18 @@ WRAP_MULADD(qemu_f32_mulAdd, float32_muladd, float32)
WRAP_MULADD(qemu_f64_mulAdd, float64_muladd, float64)
#undef WRAP_MULADD
+static void qemu_f128M_mulAdd(const float128_t *ap, const float128_t *bp,
+ const float128_t *cp, float128_t *res)
+{
+ float128 a, b, c, ret;
+
+ a = soft_to_qemu128(*ap);
+ b = soft_to_qemu128(*bp);
+ c = soft_to_qemu128(*cp);
+ ret = float128_muladd(a, b, c, 0, &qsf);
+ *res = qemu_to_soft128(ret);
+}
+
#define WRAP_CMP16(name, func, retcond) \
static bool name(float16_t a, float16_t b) \
{ \
diff --git a/tests/qemu-iotests/231 b/tests/qemu-iotests/231
index 0f66d0ca36..8e6c6447c1 100755
--- a/tests/qemu-iotests/231
+++ b/tests/qemu-iotests/231
@@ -55,6 +55,10 @@ _filter_conf()
$QEMU_IMG info "json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=${BOGUS_CONF}'}" 2>&1 | _filter_conf
$QEMU_IMG info "json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'${BOGUS_CONF}'}" 2>&1 | _filter_conf
+# Regression test: the qemu-img invocation is expected to fail, but it should
+# not seg fault the parser.
+$QEMU_IMG create "rbd:rbd/aa\/bb:conf=${BOGUS_CONF}" 1M 2>&1 | _filter_conf
+
# success, all done
echo "*** done"
rm -f $seq.full
diff --git a/tests/qemu-iotests/231.out b/tests/qemu-iotests/231.out
index 579ba11c16..a785a6e859 100644
--- a/tests/qemu-iotests/231.out
+++ b/tests/qemu-iotests/231.out
@@ -1,9 +1,10 @@
QA output created by 231
-qemu-img: RBD options encoded in the filename as keyvalue pairs is deprecated. Future versions may cease to parse these options in the future.
+qemu-img: warning: RBD options encoded in the filename as keyvalue pairs is deprecated
unable to get monitor info from DNS SRV with service name: ceph-mon
-no monitors specified to connect to.
qemu-img: Could not open 'json:{'file.driver':'rbd','file.filename':'rbd:rbd/bogus:conf=BOGUS_CONF'}': error connecting: No such file or directory
unable to get monitor info from DNS SRV with service name: ceph-mon
-no monitors specified to connect to.
qemu-img: Could not open 'json:{'file.driver':'rbd','file.pool':'rbd','file.image':'bogus','file.conf':'BOGUS_CONF'}': error connecting: No such file or directory
+Formatting 'rbd:rbd/aa\/bb:conf=BOGUS_CONF', fmt=raw size=1048576
+unable to get monitor info from DNS SRV with service name: ceph-mon
+qemu-img: rbd:rbd/aa\/bb:conf=BOGUS_CONF: error connecting: No such file or directory
*** done
diff --git a/tests/qemu-iotests/240.out b/tests/qemu-iotests/240.out
index e0982831ae..89ed25e506 100644
--- a/tests/qemu-iotests/240.out
+++ b/tests/qemu-iotests/240.out
@@ -15,7 +15,7 @@
{"return": {}}
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
{"return": {}}
-==Attach two SCSI disks using the same block device and the same iothread==
+.==Attach two SCSI disks using the same block device and the same iothread==
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
{"return": {}}
{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
@@ -32,7 +32,7 @@
{"return": {}}
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
{"return": {}}
-==Attach two SCSI disks using the same block device but different iothreads==
+.==Attach two SCSI disks using the same block device but different iothreads==
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
{"return": {}}
{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
@@ -55,7 +55,7 @@
{"return": {}}
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
{"return": {}}
-==Attach a SCSI disks using the same block device as a NBD server==
+.==Attach a SCSI disks using the same block device as a NBD server==
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
{"return": {}}
{"execute": "nbd-server-start", "arguments": {"addr": {"data": {"path": "SOCK_DIR/PID-nbd.sock"}, "type": "unix"}}}
@@ -68,7 +68,7 @@
{"return": {}}
{"execute": "device_add", "arguments": {"drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}}
{"return": {}}
-....
+.
----------------------------------------------------------------------
Ran 4 tests
diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out
index 4b33dcaf5c..99c12f4f98 100644
--- a/tests/qemu-iotests/245.out
+++ b/tests/qemu-iotests/245.out
@@ -1,16 +1,16 @@
-{"execute": "job-finalize", "arguments": {"id": "commit0"}}
+..{"execute": "job-finalize", "arguments": {"id": "commit0"}}
{"return": {}}
{"data": {"id": "commit0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"device": "commit0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "commit"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
-{"execute": "job-finalize", "arguments": {"id": "stream0"}}
+...{"execute": "job-finalize", "arguments": {"id": "stream0"}}
{"return": {}}
{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
-{"execute": "job-finalize", "arguments": {"id": "stream0"}}
+.{"execute": "job-finalize", "arguments": {"id": "stream0"}}
{"return": {}}
{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
-.....................
+...............
----------------------------------------------------------------------
Ran 21 tests
diff --git a/tests/qemu-iotests/264 b/tests/qemu-iotests/264
index 4f96825a22..bc431d1a19 100755
--- a/tests/qemu-iotests/264
+++ b/tests/qemu-iotests/264
@@ -95,7 +95,7 @@ class TestNbdReconnect(iotests.QMPTestCase):
self.assert_qmp(result, 'return', {})
def cancel_job(self):
- result = self.vm.qmp('block-job-cancel', device='drive0')
+ result = self.vm.qmp('block-job-cancel', device='drive0', force=True)
self.assert_qmp(result, 'return', {})
start_t = time.time()
diff --git a/tests/qemu-iotests/295.out b/tests/qemu-iotests/295.out
index ad34b2ca2c..5ff91f116c 100644
--- a/tests/qemu-iotests/295.out
+++ b/tests/qemu-iotests/295.out
@@ -4,7 +4,7 @@
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
{"return": {}}
-{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
+.{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
{"return": {}}
@@ -13,7 +13,7 @@ Job failed: Invalid password, cannot unlock any keyslot
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
{"return": {}}
-{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
+.{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
{"return": {}}
@@ -33,7 +33,7 @@ Job failed: All the active keyslots match the (old) password that was given and
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
{"return": {}}
-...
+.
----------------------------------------------------------------------
Ran 3 tests
diff --git a/tests/qemu-iotests/296.out b/tests/qemu-iotests/296.out
index cb2859a15c..6c69735604 100644
--- a/tests/qemu-iotests/296.out
+++ b/tests/qemu-iotests/296.out
@@ -13,7 +13,7 @@ Job failed: Failed to get shared "consistent read" lock
qemu-img: Failed to get shared "consistent read" lock
Is another process using the image [TEST_DIR/test.img]?
-Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
+.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
Job failed: Block node is read-only
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
@@ -26,15 +26,15 @@ Job failed: Failed to get shared "consistent read" lock
{"return": {}}
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
{"return": {}}
-Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
+.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
{"return": {}}
{"error": {"class": "GenericError", "desc": "Failed to get \"write\" lock"}}
-Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
+.Formatting 'TEST_DIR/test.img', fmt=luks size=1048576 key-secret=keysec0 iter-time=10
{"return": {}}
{"return": {}}
-....
+.
----------------------------------------------------------------------
Ran 4 tests
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index 08f51366f1..2dd529eb75 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -19,6 +19,9 @@
import os
import sys
import argparse
+import shutil
+from pathlib import Path
+
from findtests import TestFinder
from testenv import TestEnv
from testrunner import TestRunner
@@ -100,7 +103,7 @@ def make_argparser() -> argparse.ArgumentParser:
'rerun failed ./check command, starting from the '
'middle of the process.')
g_sel.add_argument('tests', metavar='TEST_FILES', nargs='*',
- help='tests to run')
+ help='tests to run, or "--" followed by a command')
return p
@@ -113,6 +116,20 @@ if __name__ == '__main__':
imgopts=args.imgopts, misalign=args.misalign,
debug=args.debug, valgrind=args.valgrind)
+ if len(sys.argv) > 1 and sys.argv[-len(args.tests)-1] == '--':
+ if not args.tests:
+ sys.exit("missing command after '--'")
+ cmd = args.tests
+ env.print_env()
+ exec_pathstr = shutil.which(cmd[0])
+ if exec_pathstr is None:
+ sys.exit('command not found: ' + cmd[0])
+ exec_path = Path(exec_pathstr).resolve()
+ cmd[0] = str(exec_path)
+ full_env = env.prepare_subprocess(cmd)
+ os.chdir(exec_path.parent)
+ os.execve(cmd[0], cmd, full_env)
+
testfinder = TestFinder(test_dir=env.source_iotests)
groups = args.groups.split(',') if args.groups else None
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 5af0182895..777fa2ec0e 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -20,7 +20,6 @@ import atexit
import bz2
from collections import OrderedDict
import faulthandler
-import io
import json
import logging
import os
@@ -32,7 +31,7 @@ import subprocess
import sys
import time
from typing import (Any, Callable, Dict, Iterable,
- List, Optional, Sequence, Tuple, TypeVar)
+ List, Optional, Sequence, TextIO, Tuple, Type, TypeVar)
import unittest
from contextlib import contextmanager
@@ -113,15 +112,14 @@ def qemu_tool_pipe_and_status(tool: str, args: Sequence[str],
Run a tool and return both its output and its exit code
"""
stderr = subprocess.STDOUT if connect_stderr else None
- subp = subprocess.Popen(args,
- stdout=subprocess.PIPE,
- stderr=stderr,
- universal_newlines=True)
- output = subp.communicate()[0]
- if subp.returncode < 0:
- cmd = ' '.join(args)
- sys.stderr.write(f'{tool} received signal {-subp.returncode}: {cmd}\n')
- return (output, subp.returncode)
+ with subprocess.Popen(args, stdout=subprocess.PIPE,
+ stderr=stderr, universal_newlines=True) as subp:
+ output = subp.communicate()[0]
+ if subp.returncode < 0:
+ cmd = ' '.join(args)
+ sys.stderr.write(f'{tool} received signal \
+ {-subp.returncode}: {cmd}\n')
+ return (output, subp.returncode)
def qemu_img_pipe_and_status(*args: str) -> Tuple[str, int]:
"""
@@ -237,6 +235,9 @@ def qemu_io_silent_check(*args):
class QemuIoInteractive:
def __init__(self, *args):
self.args = qemu_io_args_no_fmt + list(args)
+ # We need to keep the Popen objext around, and not
+ # close it immediately. Therefore, disable the pylint check:
+ # pylint: disable=consider-using-with
self._p = subprocess.Popen(self.args, stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
@@ -310,22 +311,22 @@ def qemu_nbd_popen(*args):
cmd.extend(args)
log('Start NBD server')
- p = subprocess.Popen(cmd)
- try:
- while not os.path.exists(pid_file):
- if p.poll() is not None:
- raise RuntimeError(
- "qemu-nbd terminated with exit code {}: {}"
- .format(p.returncode, ' '.join(cmd)))
-
- time.sleep(0.01)
- yield
- finally:
- if os.path.exists(pid_file):
- os.remove(pid_file)
- log('Kill NBD server')
- p.kill()
- p.wait()
+ with subprocess.Popen(cmd) as p:
+ try:
+ while not os.path.exists(pid_file):
+ if p.poll() is not None:
+ raise RuntimeError(
+ "qemu-nbd terminated with exit code {}: {}"
+ .format(p.returncode, ' '.join(cmd)))
+
+ time.sleep(0.01)
+ yield
+ finally:
+ if os.path.exists(pid_file):
+ os.remove(pid_file)
+ log('Kill NBD server')
+ p.kill()
+ p.wait()
def compare_images(img1, img2, fmt1=imgfmt, fmt2=imgfmt):
'''Return True if two image files are identical'''
@@ -334,13 +335,12 @@ def compare_images(img1, img2, fmt1=imgfmt, fmt2=imgfmt):
def create_image(name, size):
'''Create a fully-allocated raw image with sector markers'''
- file = open(name, 'wb')
- i = 0
- while i < size:
- sector = struct.pack('>l504xl', i // 512, i // 512)
- file.write(sector)
- i = i + 512
- file.close()
+ with open(name, 'wb') as file:
+ i = 0
+ while i < size:
+ sector = struct.pack('>l504xl', i // 512, i // 512)
+ file.write(sector)
+ i = i + 512
def image_size(img):
'''Return image's virtual size'''
@@ -1271,37 +1271,54 @@ def skip_if_user_is_root(func):
return func(*args, **kwargs)
return func_wrapper
-def execute_unittest(debug=False):
+# We need to filter out the time taken from the output so that
+# qemu-iotest can reliably diff the results against master output,
+# and hide skipped tests from the reference output.
+
+class ReproducibleTestResult(unittest.TextTestResult):
+ def addSkip(self, test, reason):
+ # Same as TextTestResult, but print dot instead of "s"
+ unittest.TestResult.addSkip(self, test, reason)
+ if self.showAll:
+ self.stream.writeln("skipped {0!r}".format(reason))
+ elif self.dots:
+ self.stream.write(".")
+ self.stream.flush()
+
+class ReproducibleStreamWrapper:
+ def __init__(self, stream: TextIO):
+ self.stream = stream
+
+ def __getattr__(self, attr):
+ if attr in ('stream', '__getstate__'):
+ raise AttributeError(attr)
+ return getattr(self.stream, attr)
+
+ def write(self, arg=None):
+ arg = re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', arg)
+ arg = re.sub(r' \(skipped=\d+\)', r'', arg)
+ self.stream.write(arg)
+
+class ReproducibleTestRunner(unittest.TextTestRunner):
+ def __init__(self, stream: Optional[TextIO] = None,
+ resultclass: Type[unittest.TestResult] = ReproducibleTestResult,
+ **kwargs: Any) -> None:
+ rstream = ReproducibleStreamWrapper(stream or sys.stdout)
+ super().__init__(stream=rstream, # type: ignore
+ descriptions=True,
+ resultclass=resultclass,
+ **kwargs)
+
+def execute_unittest(argv: List[str], debug: bool = False) -> None:
"""Executes unittests within the calling module."""
- verbosity = 2 if debug else 1
-
- if debug:
- output = sys.stdout
- else:
- # We need to filter out the time taken from the output so that
- # qemu-iotest can reliably diff the results against master output.
- output = io.StringIO()
-
- runner = unittest.TextTestRunner(stream=output, descriptions=True,
- verbosity=verbosity)
- try:
- # unittest.main() will use sys.exit(); so expect a SystemExit
- # exception
- unittest.main(testRunner=runner)
- finally:
- # We need to filter out the time taken from the output so that
- # qemu-iotest can reliably diff the results against master output.
- if not debug:
- out = output.getvalue()
- out = re.sub(r'Ran (\d+) tests? in [\d.]+s', r'Ran \1 tests', out)
-
- # Hide skipped tests from the reference output
- out = re.sub(r'OK \(skipped=\d+\)', 'OK', out)
- out_first_line, out_rest = out.split('\n', 1)
- out = out_first_line.replace('s', '.') + '\n' + out_rest
-
- sys.stderr.write(out)
+ # Some tests have warnings, especially ResourceWarnings for unclosed
+ # files and sockets. Ignore them for now to ensure reproducibility of
+ # the test output.
+ unittest.main(argv=argv,
+ testRunner=ReproducibleTestRunner,
+ verbosity=2 if debug else 1,
+ warnings=None if sys.warnoptions else 'ignore')
def execute_setup_common(supported_fmts: Sequence[str] = (),
supported_platforms: Sequence[str] = (),
@@ -1338,7 +1355,7 @@ def execute_test(*args, test_function=None, **kwargs):
debug = execute_setup_common(*args, **kwargs)
if not test_function:
- execute_unittest(debug)
+ execute_unittest(sys.argv, debug)
else:
test_function()
diff --git a/tests/qemu-iotests/pylintrc b/tests/qemu-iotests/pylintrc
index 7a6c0a9474..f2c0b522ac 100644
--- a/tests/qemu-iotests/pylintrc
+++ b/tests/qemu-iotests/pylintrc
@@ -19,6 +19,9 @@ disable=invalid-name,
too-many-public-methods,
# pylint warns about Optional[] etc. as unsubscriptable in 3.9
unsubscriptable-object,
+ # Sometimes we need to disable a newly introduced pylint warning.
+ # Doing so should not produce a warning in older versions of pylint.
+ bad-option-value,
# These are temporary, and should be removed:
missing-docstring,
too-many-return-statements,
diff --git a/tests/qemu-iotests/testenv.py b/tests/qemu-iotests/testenv.py
index 6d27712617..0c3fe75636 100644
--- a/tests/qemu-iotests/testenv.py
+++ b/tests/qemu-iotests/testenv.py
@@ -25,7 +25,7 @@ import collections
import random
import subprocess
import glob
-from typing import Dict, Any, Optional, ContextManager
+from typing import List, Dict, Any, Optional, ContextManager
def isxfile(path: str) -> bool:
@@ -74,6 +74,21 @@ class TestEnv(ContextManager['TestEnv']):
'CACHEMODE_IS_DEFAULT', 'IMGFMT_GENERIC', 'IMGOPTSSYNTAX',
'IMGKEYSECRET', 'QEMU_DEFAULT_MACHINE', 'MALLOC_PERTURB_']
+ def prepare_subprocess(self, args: List[str]) -> Dict[str, str]:
+ if self.debug:
+ args.append('-d')
+
+ with open(args[0], encoding="utf-8") as f:
+ try:
+ if f.readline().rstrip() == '#!/usr/bin/env python3':
+ args.insert(0, self.python)
+ except UnicodeDecodeError: # binary test? for future.
+ pass
+
+ os_env = os.environ.copy()
+ os_env.update(self.get_env())
+ return os_env
+
def get_env(self) -> Dict[str, str]:
env = {}
for v in self.env_variables:
@@ -105,7 +120,7 @@ class TestEnv(ContextManager['TestEnv']):
try:
self.sock_dir = os.environ['SOCK_DIR']
self.tmp_sock_dir = False
- Path(self.test_dir).mkdir(parents=True, exist_ok=True)
+ Path(self.sock_dir).mkdir(parents=True, exist_ok=True)
except KeyError:
self.sock_dir = tempfile.mkdtemp()
self.tmp_sock_dir = True
@@ -269,7 +284,8 @@ IMGPROTO -- {IMGPROTO}
PLATFORM -- {platform}
TEST_DIR -- {TEST_DIR}
SOCK_DIR -- {SOCK_DIR}
-SOCKET_SCM_HELPER -- {SOCKET_SCM_HELPER}"""
+SOCKET_SCM_HELPER -- {SOCKET_SCM_HELPER}
+"""
args = collections.defaultdict(str, self.get_env())
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
index 1fc61fcaa3..4a6ec421ed 100644
--- a/tests/qemu-iotests/testrunner.py
+++ b/tests/qemu-iotests/testrunner.py
@@ -129,7 +129,6 @@ class TestRunner(ContextManager['TestRunner']):
def __init__(self, env: TestEnv, makecheck: bool = False,
color: str = 'auto') -> None:
self.env = env
- self.test_run_env = self.env.get_env()
self.makecheck = makecheck
self.last_elapsed = LastElapsedTime('.last-elapsed-cache', env)
@@ -243,32 +242,21 @@ class TestRunner(ContextManager['TestRunner']):
silent_unlink(p)
args = [str(f_test.resolve())]
- if self.env.debug:
- args.append('-d')
-
- with f_test.open(encoding="utf-8") as f:
- try:
- if f.readline().rstrip() == '#!/usr/bin/env python3':
- args.insert(0, self.env.python)
- except UnicodeDecodeError: # binary test? for future.
- pass
-
- env = os.environ.copy()
- env.update(self.test_run_env)
+ env = self.env.prepare_subprocess(args)
t0 = time.time()
with f_bad.open('w', encoding="utf-8") as f:
- proc = subprocess.Popen(args, cwd=str(f_test.parent), env=env,
- stdout=f, stderr=subprocess.STDOUT)
- try:
- proc.wait()
- except KeyboardInterrupt:
- proc.terminate()
- proc.wait()
- return TestResult(status='not run',
- description='Interrupted by user',
- interrupted=True)
- ret = proc.returncode
+ with subprocess.Popen(args, cwd=str(f_test.parent), env=env,
+ stdout=f, stderr=subprocess.STDOUT) as proc:
+ try:
+ proc.wait()
+ except KeyboardInterrupt:
+ proc.terminate()
+ proc.wait()
+ return TestResult(status='not run',
+ description='Interrupted by user',
+ interrupted=True)
+ ret = proc.returncode
elapsed = round(time.time() - t0, 1)
@@ -328,7 +316,6 @@ class TestRunner(ContextManager['TestRunner']):
if not self.makecheck:
self.env.print_env()
- print()
test_field_width = max(len(os.path.basename(t)) for t in tests) + 2
diff --git a/tests/qtest/ahci-test.c b/tests/qtest/ahci-test.c
index 5e1954852e..8073ccc205 100644
--- a/tests/qtest/ahci-test.c
+++ b/tests/qtest/ahci-test.c
@@ -1491,14 +1491,14 @@ static void ahci_test_cdrom(int nsectors, bool dma, uint8_t cmd,
char *iso;
int fd;
AHCIOpts opts = {
- .size = (ATAPI_SECTOR_SIZE * nsectors),
+ .size = ((uint64_t)ATAPI_SECTOR_SIZE * nsectors),
.atapi = true,
.atapi_dma = dma,
.post_cb = ahci_cb_cmp_buff,
.set_bcl = override_bcl,
.bcl = bcl,
};
- uint64_t iso_size = ATAPI_SECTOR_SIZE * (nsectors + 1);
+ uint64_t iso_size = (uint64_t)ATAPI_SECTOR_SIZE * (nsectors + 1);
/* Prepare ISO and fill 'tx' buffer */
fd = prepare_iso(iso_size, &tx, &iso);
diff --git a/tests/qtest/ipmi-bt-test.c b/tests/qtest/ipmi-bt-test.c
index a42207d416..8492f02a9c 100644
--- a/tests/qtest/ipmi-bt-test.c
+++ b/tests/qtest/ipmi-bt-test.c
@@ -98,7 +98,8 @@ static void bt_wait_b_busy(void)
{
unsigned int count = 1000;
while (IPMI_BT_CTLREG_GET_B_BUSY() != 0) {
- g_assert(--count != 0);
+ --count;
+ g_assert(count != 0);
usleep(100);
}
}
@@ -107,7 +108,8 @@ static void bt_wait_b2h_atn(void)
{
unsigned int count = 1000;
while (IPMI_BT_CTLREG_GET_B2H_ATN() == 0) {
- g_assert(--count != 0);
+ --count;
+ g_assert(count != 0);
usleep(100);
}
}
diff --git a/tests/qtest/ipmi-kcs-test.c b/tests/qtest/ipmi-kcs-test.c
index fc0a918c8d..afc24dd3e4 100644
--- a/tests/qtest/ipmi-kcs-test.c
+++ b/tests/qtest/ipmi-kcs-test.c
@@ -73,7 +73,8 @@ static void kcs_wait_ibf(void)
{
unsigned int count = 1000;
while (IPMI_KCS_CMDREG_GET_IBF() != 0) {
- g_assert(--count != 0);
+ --count;
+ g_assert(count != 0);
}
}
diff --git a/tests/qtest/libqos/qgraph.c b/tests/qtest/libqos/qgraph.c
index b3b1a31f81..d1dc491930 100644
--- a/tests/qtest/libqos/qgraph.c
+++ b/tests/qtest/libqos/qgraph.c
@@ -844,7 +844,7 @@ void qos_dump_graph(void)
}
qos_printf_literal("type=%d cmd_line='%s' [%s]\n",
node->type, node->command_line,
- node->available ? "available" : "UNAVAILBLE"
+ node->available ? "available" : "UNAVAILABLE"
);
}
g_list_free(keys);
diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
index 71e359efcd..825b13a44c 100644
--- a/tests/qtest/libqtest.c
+++ b/tests/qtest/libqtest.c
@@ -907,7 +907,14 @@ const char *qtest_get_arch(void)
if (!end) {
fprintf(stderr, "Can't determine architecture from binary name.\n");
- abort();
+ exit(1);
+ }
+
+ if (!strstr(qemu, "-system-")) {
+ fprintf(stderr, "QTEST_QEMU_BINARY must end with *-system-<arch> "
+ "where 'arch' is the target\narchitecture (x86_64, aarch64, "
+ "etc).\n");
+ exit(1);
}
return end + 1;
diff --git a/tests/qtest/npcm7xx_pwm-test.c b/tests/qtest/npcm7xx_pwm-test.c
index bd15a1c294..a54fd70d27 100644
--- a/tests/qtest/npcm7xx_pwm-test.c
+++ b/tests/qtest/npcm7xx_pwm-test.c
@@ -201,7 +201,7 @@ static int pwm_module_index(const PWMModule *module)
{
ptrdiff_t diff = module - pwm_module_list;
- g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_module_list));
+ g_assert(diff >= 0 && diff < ARRAY_SIZE(pwm_module_list));
return diff;
}
@@ -211,7 +211,7 @@ static int pwm_index(const PWM *pwm)
{
ptrdiff_t diff = pwm - pwm_list;
- g_assert_true(diff >= 0 && diff < ARRAY_SIZE(pwm_list));
+ g_assert(diff >= 0 && diff < ARRAY_SIZE(pwm_list));
return diff;
}
diff --git a/tests/qtest/rtc-test.c b/tests/qtest/rtc-test.c
index 402ce2c609..8126ab1bdb 100644
--- a/tests/qtest/rtc-test.c
+++ b/tests/qtest/rtc-test.c
@@ -686,7 +686,7 @@ static void periodic_timer(void)
int main(int argc, char **argv)
{
- QTestState *s = NULL;
+ QTestState *s;
int ret;
g_test_init(&argc, &argv, NULL);
@@ -712,9 +712,7 @@ int main(int argc, char **argv)
ret = g_test_run();
- if (s) {
- qtest_quit(s);
- }
+ qtest_quit(s);
return ret;
}
diff --git a/tests/qtest/tpm-util.c b/tests/qtest/tpm-util.c
index b70cc32d60..3a40ff3f96 100644
--- a/tests/qtest/tpm-util.c
+++ b/tests/qtest/tpm-util.c
@@ -289,6 +289,6 @@ void tpm_util_migration_start_qemu(QTestState **src_qemu,
*dst_qemu = qtest_init(dst_qemu_args);
- free(src_qemu_args);
- free(dst_qemu_args);
+ g_free(src_qemu_args);
+ g_free(dst_qemu_args);
}
diff --git a/tests/unit/test-write-threshold.c b/tests/unit/test-write-threshold.c
index fc1c45a2eb..0158e4637a 100644
--- a/tests/unit/test-write-threshold.c
+++ b/tests/unit/test-write-threshold.c
@@ -7,117 +7,41 @@
*/
#include "qemu/osdep.h"
-#include "qapi/error.h"
#include "block/block_int.h"
#include "block/write-threshold.h"
-static void test_threshold_not_set_on_init(void)
-{
- uint64_t res;
- BlockDriverState bs;
- memset(&bs, 0, sizeof(bs));
-
- g_assert(!bdrv_write_threshold_is_set(&bs));
-
- res = bdrv_write_threshold_get(&bs);
- g_assert_cmpint(res, ==, 0);
-}
-
-static void test_threshold_set_get(void)
-{
- uint64_t threshold = 4 * 1024 * 1024;
- uint64_t res;
- BlockDriverState bs;
- memset(&bs, 0, sizeof(bs));
-
- bdrv_write_threshold_set(&bs, threshold);
-
- g_assert(bdrv_write_threshold_is_set(&bs));
-
- res = bdrv_write_threshold_get(&bs);
- g_assert_cmpint(res, ==, threshold);
-}
-
-static void test_threshold_multi_set_get(void)
-{
- uint64_t threshold1 = 4 * 1024 * 1024;
- uint64_t threshold2 = 15 * 1024 * 1024;
- uint64_t res;
- BlockDriverState bs;
- memset(&bs, 0, sizeof(bs));
-
- bdrv_write_threshold_set(&bs, threshold1);
- bdrv_write_threshold_set(&bs, threshold2);
- res = bdrv_write_threshold_get(&bs);
- g_assert_cmpint(res, ==, threshold2);
-}
-
static void test_threshold_not_trigger(void)
{
- uint64_t amount = 0;
uint64_t threshold = 4 * 1024 * 1024;
BlockDriverState bs;
- BdrvTrackedRequest req;
memset(&bs, 0, sizeof(bs));
- memset(&req, 0, sizeof(req));
- req.offset = 1024;
- req.bytes = 1024;
-
- bdrv_check_request(req.offset, req.bytes, &error_abort);
bdrv_write_threshold_set(&bs, threshold);
- amount = bdrv_write_threshold_exceeded(&bs, &req);
- g_assert_cmpuint(amount, ==, 0);
+ bdrv_write_threshold_check_write(&bs, 1024, 1024);
+ g_assert_cmpuint(bdrv_write_threshold_get(&bs), ==, threshold);
}
static void test_threshold_trigger(void)
{
- uint64_t amount = 0;
uint64_t threshold = 4 * 1024 * 1024;
BlockDriverState bs;
- BdrvTrackedRequest req;
memset(&bs, 0, sizeof(bs));
- memset(&req, 0, sizeof(req));
- req.offset = (4 * 1024 * 1024) - 1024;
- req.bytes = 2 * 1024;
-
- bdrv_check_request(req.offset, req.bytes, &error_abort);
bdrv_write_threshold_set(&bs, threshold);
- amount = bdrv_write_threshold_exceeded(&bs, &req);
- g_assert_cmpuint(amount, >=, 1024);
+ bdrv_write_threshold_check_write(&bs, threshold - 1024, 2 * 1024);
+ g_assert_cmpuint(bdrv_write_threshold_get(&bs), ==, 0);
}
-typedef struct TestStruct {
- const char *name;
- void (*func)(void);
-} TestStruct;
-
int main(int argc, char **argv)
{
- size_t i;
- TestStruct tests[] = {
- { "/write-threshold/not-set-on-init",
- test_threshold_not_set_on_init },
- { "/write-threshold/set-get",
- test_threshold_set_get },
- { "/write-threshold/multi-set-get",
- test_threshold_multi_set_get },
- { "/write-threshold/not-trigger",
- test_threshold_not_trigger },
- { "/write-threshold/trigger",
- test_threshold_trigger },
- { NULL, NULL }
- };
-
g_test_init(&argc, &argv, NULL);
- for (i = 0; tests[i].name != NULL; i++) {
- g_test_add_func(tests[i].name, tests[i].func);
- }
+ g_test_add_func("/write-threshold/not-trigger", test_threshold_not_trigger);
+ g_test_add_func("/write-threshold/trigger", test_threshold_trigger);
+
return g_test_run();
}