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:
Paolo Bonzini 2021-05-03 13:01:06 +02:00 committed by Max Reitz
parent 9c785cd714
commit f29f4c25eb
5 changed files with 56 additions and 44 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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] = (),