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
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
@ -1271,37 +1270,50 @@ def skip_if_user_is_root(func):
|
||||
return func(*args, **kwargs)
|
||||
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):
|
||||
"""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)
|
||||
runner = ReproducibleTestRunner(verbosity=verbosity)
|
||||
unittest.main(testRunner=runner)
|
||||
|
||||
def execute_setup_common(supported_fmts: Sequence[str] = (),
|
||||
supported_platforms: Sequence[str] = (),
|
||||
|
Loading…
Reference in New Issue
Block a user