mirror of
https://github.com/xemu-project/xemu.git
synced 2025-04-02 11:11:48 -04:00
qemu-iotests: do not buffer the test output
Instead of buffering the test output into a StringIO, patch it on the fly by wrapping sys.stdout's write method. This can be done unconditionally, even if using -d, which makes execute_unittest a bit simpler. Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> Tested-by: Emanuele Giuseppe Esposito <eesposit@redhat.com> Message-Id: <20210323181928.311862-2-pbonzini@redhat.com> Message-Id: <20210503110110.476887-2-pbonzini@redhat.com> Signed-off-by: Max Reitz <mreitz@redhat.com>
This commit is contained in:
parent
9c785cd714
commit
f29f4c25eb
5 changed files with 56 additions and 44 deletions
|
@ -15,7 +15,7 @@
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
|
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
|
||||||
{"return": {}}
|
{"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}}
|
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
|
{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
|
||||||
|
@ -32,7 +32,7 @@
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
|
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
|
||||||
{"return": {}}
|
{"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}}
|
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
|
{"execute": "object-add", "arguments": {"id": "iothread0", "qom-type": "iothread"}}
|
||||||
|
@ -55,7 +55,7 @@
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
|
{"execute": "blockdev-del", "arguments": {"node-name": "hd0"}}
|
||||||
{"return": {}}
|
{"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}}
|
{"execute": "blockdev-add", "arguments": {"driver": "null-co", "node-name": "hd0", "read-only": true, "read-zeroes": true}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "nbd-server-start", "arguments": {"addr": {"data": {"path": "SOCK_DIR/PID-nbd.sock"}, "type": "unix"}}}
|
{"execute": "nbd-server-start", "arguments": {"addr": {"data": {"path": "SOCK_DIR/PID-nbd.sock"}, "type": "unix"}}}
|
||||||
|
@ -68,7 +68,7 @@
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "device_add", "arguments": {"drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}}
|
{"execute": "device_add", "arguments": {"drive": "hd0", "driver": "scsi-hd", "id": "scsi-hd0"}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
....
|
.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
Ran 4 tests
|
Ran 4 tests
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
{"execute": "job-finalize", "arguments": {"id": "commit0"}}
|
..{"execute": "job-finalize", "arguments": {"id": "commit0"}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"data": {"id": "commit0", "type": "commit"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
|
{"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"}}
|
{"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": {}}
|
{"return": {}}
|
||||||
{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
|
{"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"}}
|
{"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": {}}
|
{"return": {}}
|
||||||
{"data": {"id": "stream0", "type": "stream"}, "event": "BLOCK_JOB_PENDING", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
|
{"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"}}
|
{"data": {"device": "stream0", "len": 3145728, "offset": 3145728, "speed": 0, "type": "stream"}, "event": "BLOCK_JOB_COMPLETED", "timestamp": {"microseconds": "USECS", "seconds": "SECS"}}
|
||||||
.....................
|
...............
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
Ran 21 tests
|
Ran 21 tests
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
|
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
|
.{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
|
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
|
@ -13,7 +13,7 @@ Job failed: Invalid password, cannot unlock any keyslot
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
|
{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
|
.{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
|
{"execute": "job-dismiss", "arguments": {"id": "job_add_key"}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
|
@ -33,7 +33,7 @@ Job failed: All the active keyslots match the (old) password that was given and
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
|
{"execute": "job-dismiss", "arguments": {"id": "job_erase_key"}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
...
|
.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
Ran 3 tests
|
Ran 3 tests
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ Job failed: Failed to get shared "consistent read" lock
|
||||||
qemu-img: 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]?
|
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
|
Job failed: Block node is read-only
|
||||||
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
|
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
|
||||||
|
@ -26,15 +26,15 @@ Job failed: Failed to get shared "consistent read" lock
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
|
{"execute": "job-dismiss", "arguments": {"id": "job0"}}
|
||||||
{"return": {}}
|
{"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": {}}
|
{"return": {}}
|
||||||
{"error": {"class": "GenericError", "desc": "Failed to get \"write\" lock"}}
|
{"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": {}}
|
||||||
{"return": {}}
|
{"return": {}}
|
||||||
....
|
.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
Ran 4 tests
|
Ran 4 tests
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ import atexit
|
||||||
import bz2
|
import bz2
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import faulthandler
|
import faulthandler
|
||||||
import io
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
@ -32,7 +31,7 @@ import subprocess
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
from typing import (Any, Callable, Dict, Iterable,
|
from typing import (Any, Callable, Dict, Iterable,
|
||||||
List, Optional, Sequence, Tuple, TypeVar)
|
List, Optional, Sequence, TextIO, Tuple, Type, TypeVar)
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
@ -1271,37 +1270,50 @@ def skip_if_user_is_root(func):
|
||||||
return func(*args, **kwargs)
|
return func(*args, **kwargs)
|
||||||
return func_wrapper
|
return func_wrapper
|
||||||
|
|
||||||
|
# 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(debug=False):
|
def execute_unittest(debug=False):
|
||||||
"""Executes unittests within the calling module."""
|
"""Executes unittests within the calling module."""
|
||||||
|
|
||||||
verbosity = 2 if debug else 1
|
verbosity = 2 if debug else 1
|
||||||
|
runner = ReproducibleTestRunner(verbosity=verbosity)
|
||||||
if debug:
|
unittest.main(testRunner=runner)
|
||||||
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)
|
|
||||||
|
|
||||||
def execute_setup_common(supported_fmts: Sequence[str] = (),
|
def execute_setup_common(supported_fmts: Sequence[str] = (),
|
||||||
supported_platforms: Sequence[str] = (),
|
supported_platforms: Sequence[str] = (),
|
||||||
|
|
Loading…
Add table
Reference in a new issue