From 371da004f74e19368a953adcaf8f84fd7c7f17c3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 14 Jun 2018 14:58:13 +0200 Subject: [PATCH 1/3] bpo-33718: regrtest: use format_duration() to display failed tests (GH-7686) * Enhance also format_duration(): work on integers and rounds towards +infinity (math.ceil). * Write unit tests on format_duration() (cherry picked from commit 4ffe9c2b251f6e027b26250b7a2618e78d4edd22) --- Lib/test/regrtest.py | 39 ++++++++++++++++++++++++--------------- Lib/test/test_regrtest.py | 28 +++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index 64aa46555621d2..6399cd4fa1be62 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -174,20 +174,21 @@ import StringIO import datetime import getopt +import imp import json +import math import os +import platform import random import re import shutil import sys +import sysconfig +import tempfile import time import traceback -import warnings import unittest -import tempfile -import imp -import platform -import sysconfig +import warnings # Some times __path__ and __file__ are not absolute (e.g. while running from @@ -270,17 +271,25 @@ def usage(code, msg=''): def format_duration(seconds): - if seconds < 1.0: - return '%.0f ms' % (seconds * 1e3) - if seconds < 60.0: - return '%.0f sec' % seconds + ms = int(math.ceil(seconds * 1e3)) + seconds, ms = divmod(ms, 1000) + minutes, seconds = divmod(seconds, 60) + hours, minutes = divmod(minutes, 60) - minutes, seconds = divmod(seconds, 60.0) - hours, minutes = divmod(minutes, 60.0) + parts = [] if hours: - return '%.0f hour %.0f min' % (hours, minutes) - else: - return '%.0f min %.0f sec' % (minutes, seconds) + parts.append('%s hour' % hours) + if minutes: + parts.append('%s min' % minutes) + if seconds: + parts.append('%s sec' % seconds) + if ms: + parts.append('%s ms' % ms) + if not parts: + return '0 ms' + + parts = parts[:2] + return ' '.join(parts) _FORMAT_TEST_RESULT = { @@ -809,7 +818,7 @@ def get_running(workers): if (ok not in (CHILD_ERROR, INTERRUPTED) and test_time >= PROGRESS_MIN_TIME and not pgo): - text += ' (%.0f sec)' % test_time + text += ' (%s)' % format_duration(test_time) running = get_running(workers) if running and not pgo: text += ' -- running: %s' % ', '.join(running) diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py index 1dd7bb581868ab..a459504e445e03 100644 --- a/Lib/test/test_regrtest.py +++ b/Lib/test/test_regrtest.py @@ -17,6 +17,8 @@ import textwrap import unittest from test import support +# Use utils alias to use the same code for TestUtils in master and 2.7 branches +import regrtest as utils Py_DEBUG = hasattr(sys, 'getobjects') @@ -683,8 +685,32 @@ def test_main(): failed=testname, rerun=testname) +class TestUtils(unittest.TestCase): + def test_format_duration(self): + self.assertEqual(utils.format_duration(0), + '0 ms') + self.assertEqual(utils.format_duration(1e-9), + '1 ms') + self.assertEqual(utils.format_duration(10e-3), + '10 ms') + self.assertEqual(utils.format_duration(1.5), + '1 sec 500 ms') + self.assertEqual(utils.format_duration(1), + '1 sec') + self.assertEqual(utils.format_duration(2 * 60), + '2 min') + self.assertEqual(utils.format_duration(2 * 60 + 1), + '2 min 1 sec') + self.assertEqual(utils.format_duration(3 * 3600), + '3 hour') + self.assertEqual(utils.format_duration(3 * 3600 + 2 * 60 + 1), + '3 hour 2 min') + self.assertEqual(utils.format_duration(3 * 3600 + 1), + '3 hour 1 sec') + + def test_main(): - support.run_unittest(ProgramsTestCase, ArgsTestCase) + support.run_unittest(ProgramsTestCase, ArgsTestCase, TestUtils) if __name__ == "__main__": From 7390ef6ef74377568e6b59313be837ecbc05d5bc Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Tue, 26 Jun 2018 23:23:12 +0200 Subject: [PATCH 2/3] bpo-33873: regrtest: Add warning on -R 1:3 (GH-7736) regrtest: Add warning when using less than 3 warmup runs like -R 1:3. (cherry picked from commit cac4fef8860e66a9da67d09762f5b614b9471a12) --- Lib/test/regrtest.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index 6399cd4fa1be62..11c36f1dae0ce5 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -691,6 +691,12 @@ def display_progress(test_index, test): if ncpu: print "== CPU count:", ncpu + if huntrleaks: + warmup, repetitions, _ = huntrleaks + if warmup < 3: + print("WARNING: Running tests with --huntrleaks/-R and less than " + "3 warmup repetitions can give false positives!") + if randomize: random.seed(random_seed) print "Using random seed", random_seed From b448166558fbdafb52aaca9c394db1dede7c635c Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Tue, 26 Jun 2018 23:27:14 +0200 Subject: [PATCH 3/3] bpo-33873: Fix bug in `runtest.py` and add checks for invalid `-R` parameters (GH-7735) Fix bug in `Lib/test/libregrtest/runtest.py` that makes running tests an extra time than the specified number of runs. Add check for invalid --huntrleaks/-R parameters. (cherry picked from commit 58ed7307ea0b5c5aa052291ebc3030f314f938d8) --- Lib/test/regrtest.py | 14 ++++++++++++-- .../Tests/2018-06-16-01-37-31.bpo-33873.d86vab.rst | 4 ++++ 2 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Tests/2018-06-16-01-37-31.bpo-33873.d86vab.rst diff --git a/Lib/test/regrtest.py b/Lib/test/regrtest.py index 11c36f1dae0ce5..6b49dafd9368f4 100755 --- a/Lib/test/regrtest.py +++ b/Lib/test/regrtest.py @@ -516,6 +516,15 @@ def main(tests=None, testdir=None, verbose=0, quiet=False, except ValueError: pass + if huntrleaks: + warmup, repetitions, _ = huntrleaks + if warmup < 1 or repetitions < 1: + msg = ("Invalid values for the --huntrleaks/-R parameters. The " + "number of warmups and repetitions must be at least 1 " + "each (1:1).") + print >>sys.stderr, msg + sys.exit(2) + if slaveargs is not None: args, kwargs = json.loads(slaveargs) if kwargs['huntrleaks']: @@ -1308,11 +1317,12 @@ def runtest_inner(test, verbose, quiet, huntrleaks=False, pgo=False, testdir=Non # being imported. For tests based on unittest or doctest, # explicitly invoke their test_main() function (if it exists). indirect_test = getattr(the_module, "test_main", None) - if indirect_test is not None: - indirect_test() if huntrleaks: refleak = dash_R(the_module, test, indirect_test, huntrleaks) + else: + if indirect_test is not None: + indirect_test() test_time = time.time() - start_time post_test_cleanup() finally: diff --git a/Misc/NEWS.d/next/Tests/2018-06-16-01-37-31.bpo-33873.d86vab.rst b/Misc/NEWS.d/next/Tests/2018-06-16-01-37-31.bpo-33873.d86vab.rst new file mode 100644 index 00000000000000..f4f425570267db --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2018-06-16-01-37-31.bpo-33873.d86vab.rst @@ -0,0 +1,4 @@ +Fix a bug in ``regrtest`` that caused an extra test to run if +--huntrleaks/-R was used. Exit with error in case that invalid +parameters are specified to --huntrleaks/-R (at least one warmup +run and one repetition must be used).