qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: qemu-devel@nongnu.org
Cc: eesposit@redhat.com, kwolf@redhat.com, vsementsov@virtuozzo.com,
	qemu-block@nongnu.org, mreitz@redhat.com
Subject: [PATCH 1/4] qemu-iotests: allow passing unittest.main arguments to the test scripts
Date: Tue, 23 Mar 2021 14:06:11 +0100	[thread overview]
Message-ID: <20210323130614.146399-2-pbonzini@redhat.com> (raw)
In-Reply-To: <20210323130614.146399-1-pbonzini@redhat.com>

Python test scripts that use unittest consist of multiple tests.
unittest.main allows selecting which tests to run, but currently this
is not possible because the iotests wrapper ignores sys.argv.

unittest.main command line options also allow the user to pick the
desired options for verbosity, failfast mode, etc.  While "-d" is
currently translated to "-v", it also enables extra debug output,
and also there are no other options available.  Unfortunately, these
command line options only work if the unittest.main testRunner argument
is a type, rather than a TestRunner instance, and right now iotests.py
is using a TextTestRunner instance in order to pass the output stream.
By moving the machinery to obtain reproducible unittest output into a
TextTestRunner subclass, we can just pass the class name to unittest.main.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/qemu-iotests/iotests.py | 60 ++++++++++++++++++++---------------
 1 file changed, 35 insertions(+), 25 deletions(-)

diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index 90d0b62523..b9f4edfc42 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -1271,38 +1271,49 @@ def func_wrapper(*args, **kwargs):
             return func(*args, **kwargs)
     return func_wrapper
 
-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()
+# We need to filter out the time taken from the output so that
+# qemu-iotest can reliably diff the results against master output.
+class ReproducibleTextTestRunner(unittest.TextTestRunner):
+    __output = None
+
+    @classmethod
+    @property
+    def output(cls):
+        if cls.__output is not None:
+            return cls.__output
+
+        cls.__output = io.StringIO()
+        def print_output():
+            out = cls.__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)
 
+        atexit.register(print_output)
+        return cls.__output
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(stream=ReproducibleTextTestRunner.output, *args, **kwargs)
+
+def execute_unittest(argv, debug=False):
+    """Executes unittests within the calling module."""
+
+    # If we see non-empty argv we must not be invoked as a test script,
+    # so do not bother making constant output; debuggability is more
+    # important.
+    if debug or len(argv) > 1:
+        argv += ['-v']
+        runner = unittest.TextTestRunner
+    else:
+        runner = ReproducibleTextTestRunner
+
+    unittest.main(argv=argv, testRunner=runner,
+                  warnings=None if sys.warnoptions else 'ignore')
+
 def execute_setup_common(supported_fmts: Sequence[str] = (),
                          supported_platforms: Sequence[str] = (),
                          supported_cache_modes: Sequence[str] = (),
@@ -1338,7 +1348,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()
 
-- 
2.30.1




  reply	other threads:[~2021-03-23 13:07 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-03-23 13:06 [PATCH 0/4] qemu-iotests: quality of life improvements Paolo Bonzini
2021-03-23 13:06 ` Paolo Bonzini [this message]
2021-03-23 14:34   ` [PATCH 1/4] qemu-iotests: allow passing unittest.main arguments to the test scripts Vladimir Sementsov-Ogievskiy
2021-03-23 15:29     ` Paolo Bonzini
2021-03-23 16:04       ` Vladimir Sementsov-Ogievskiy
2021-03-23 16:56       ` Vladimir Sementsov-Ogievskiy
2021-03-23 17:04         ` Paolo Bonzini
2021-03-23 17:27           ` Vladimir Sementsov-Ogievskiy
2021-03-23 17:35             ` Paolo Bonzini
2021-03-23 13:06 ` [PATCH 2/4] qemu-iotests: move command line and environment handling from TestRunner to TestEnv Paolo Bonzini
2021-03-23 16:22   ` Vladimir Sementsov-Ogievskiy
2021-03-23 13:06 ` [PATCH 3/4] qemu-iotests: let "check" spawn an arbitrary test command Paolo Bonzini
2021-03-23 16:43   ` Vladimir Sementsov-Ogievskiy
2021-03-23 17:00     ` Paolo Bonzini
2021-03-23 17:11       ` Vladimir Sementsov-Ogievskiy
2021-03-23 17:22         ` Paolo Bonzini
2021-03-23 17:39           ` Vladimir Sementsov-Ogievskiy
2021-03-23 13:06 ` [PATCH 4/4] qemu-iotests: fix case of SOCK_DIR already in the environment Paolo Bonzini
2021-03-23 16:45   ` Vladimir Sementsov-Ogievskiy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210323130614.146399-2-pbonzini@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=eesposit@redhat.com \
    --cc=kwolf@redhat.com \
    --cc=mreitz@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    --cc=vsementsov@virtuozzo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).