tests/test-util.py
author Augie Fackler <augie@google.com>
Tue, 21 Aug 2018 17:15:51 -0400
changeset 39258 331ab85e910b
parent 38812 9d49bb117dde
child 43076 2372284d9457
permissions -rw-r--r--
cleanup: make all uses of timedcm specify what they're timing It's not used in the timing itself, but it's valuable for the trace events we emit. Differential Revision: https://phab.mercurial-scm.org/D4349
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
38797
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
     1
# unit tests for mercuril.util utilities
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
     2
from __future__ import absolute_import
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
     3
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
     4
import contextlib
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
     5
import itertools
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
     6
import unittest
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
     7
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
     8
from mercurial import pycompat, util, utils
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
     9
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    10
@contextlib.contextmanager
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    11
def mocktimer(incr=0.1, *additional_targets):
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    12
    """Replaces util.timer and additional_targets with a mock
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    13
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    14
    The timer starts at 0. On each call the time incremented by the value
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    15
    of incr. If incr is an iterable, then the time is incremented by the
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    16
    next value from that iterable, looping in a cycle when reaching the end.
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    17
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    18
    additional_targets must be a sequence of (object, attribute_name) tuples;
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    19
    the mock is set with setattr(object, attribute_name, mock).
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    20
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    21
    """
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    22
    time = [0]
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    23
    try:
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    24
        incr = itertools.cycle(incr)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    25
    except TypeError:
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    26
        incr = itertools.repeat(incr)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    27
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    28
    def timer():
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    29
        time[0] += next(incr)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    30
        return time[0]
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    31
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    32
    # record original values
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    33
    orig = util.timer
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    34
    additional_origs = [(o, a, getattr(o, a)) for o, a in additional_targets]
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    35
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    36
    # mock out targets
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    37
    util.timer = timer
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    38
    for obj, attr in additional_targets:
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    39
        setattr(obj, attr, timer)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    40
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    41
    try:
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    42
        yield
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    43
    finally:
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    44
        # restore originals
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    45
        util.timer = orig
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    46
        for args in additional_origs:
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    47
            setattr(*args)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    48
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    49
# attr.s default factory for util.timedstats.start binds the timer we
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    50
# need to mock out.
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    51
_start_default = (util.timedcmstats.start.default, 'factory')
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    52
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    53
@contextlib.contextmanager
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    54
def capturestderr():
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    55
    """Replace utils.procutil.stderr with a pycompat.bytesio instance
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    56
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    57
    The instance is made available as the return value of __enter__.
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    58
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    59
    This contextmanager is reentrant.
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    60
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    61
    """
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    62
    orig = utils.procutil.stderr
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    63
    utils.procutil.stderr = pycompat.bytesio()
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    64
    try:
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    65
        yield utils.procutil.stderr
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    66
    finally:
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    67
        utils.procutil.stderr = orig
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    68
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    69
class timedtests(unittest.TestCase):
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    70
    def testtimedcmstatsstr(self):
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    71
        stats = util.timedcmstats()
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    72
        self.assertEqual(str(stats), '<unknown>')
38812
9d49bb117dde util: make new timedcmstats class Python 3 compatible
Martijn Pieters <mj@zopatista.com>
parents: 38797
diff changeset
    73
        self.assertEqual(bytes(stats), b'<unknown>')
38797
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    74
        stats.elapsed = 12.34
38812
9d49bb117dde util: make new timedcmstats class Python 3 compatible
Martijn Pieters <mj@zopatista.com>
parents: 38797
diff changeset
    75
        self.assertEqual(str(stats), pycompat.sysstr(util.timecount(12.34)))
9d49bb117dde util: make new timedcmstats class Python 3 compatible
Martijn Pieters <mj@zopatista.com>
parents: 38797
diff changeset
    76
        self.assertEqual(bytes(stats), util.timecount(12.34))
38797
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    77
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    78
    def testtimedcmcleanexit(self):
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    79
        # timestamps 1, 4, elapsed time of 4 - 1 = 3
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    80
        with mocktimer([1, 3], _start_default):
39258
331ab85e910b cleanup: make all uses of timedcm specify what they're timing
Augie Fackler <augie@google.com>
parents: 38812
diff changeset
    81
            with util.timedcm('pass') as stats:
38797
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    82
                # actual context doesn't matter
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    83
                pass
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    84
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    85
        self.assertEqual(stats.start, 1)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    86
        self.assertEqual(stats.elapsed, 3)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    87
        self.assertEqual(stats.level, 1)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    88
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    89
    def testtimedcmnested(self):
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    90
        # timestamps 1, 3, 6, 10, elapsed times of 6 - 3 = 3 and 10 - 1 = 9
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    91
        with mocktimer([1, 2, 3, 4], _start_default):
39258
331ab85e910b cleanup: make all uses of timedcm specify what they're timing
Augie Fackler <augie@google.com>
parents: 38812
diff changeset
    92
            with util.timedcm('outer') as outer_stats:
331ab85e910b cleanup: make all uses of timedcm specify what they're timing
Augie Fackler <augie@google.com>
parents: 38812
diff changeset
    93
                with util.timedcm('inner') as inner_stats:
38797
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    94
                    # actual context doesn't matter
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    95
                    pass
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    96
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    97
        self.assertEqual(outer_stats.start, 1)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    98
        self.assertEqual(outer_stats.elapsed, 9)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
    99
        self.assertEqual(outer_stats.level, 1)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   100
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   101
        self.assertEqual(inner_stats.start, 3)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   102
        self.assertEqual(inner_stats.elapsed, 3)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   103
        self.assertEqual(inner_stats.level, 2)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   104
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   105
    def testtimedcmexception(self):
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   106
        # timestamps 1, 4, elapsed time of 4 - 1 = 3
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   107
        with mocktimer([1, 3], _start_default):
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   108
            try:
39258
331ab85e910b cleanup: make all uses of timedcm specify what they're timing
Augie Fackler <augie@google.com>
parents: 38812
diff changeset
   109
                with util.timedcm('exceptional') as stats:
38797
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   110
                    raise ValueError()
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   111
            except ValueError:
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   112
                pass
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   113
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   114
        self.assertEqual(stats.start, 1)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   115
        self.assertEqual(stats.elapsed, 3)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   116
        self.assertEqual(stats.level, 1)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   117
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   118
    def testtimeddecorator(self):
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   119
        @util.timed
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   120
        def testfunc(callcount=1):
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   121
            callcount -= 1
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   122
            if callcount:
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   123
                testfunc(callcount)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   124
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   125
        # timestamps 1, 2, 3, 4, elapsed time of 3 - 2 = 1 and 4 - 1 = 3
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   126
        with mocktimer(1, _start_default):
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   127
            with capturestderr() as out:
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   128
                testfunc(2)
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   129
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   130
        self.assertEqual(out.getvalue(), (
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   131
            b'    testfunc: 1.000 s\n'
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   132
            b'  testfunc: 3.000 s\n'
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   133
        ))
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   134
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   135
if __name__ == '__main__':
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   136
    import silenttestrunner
8751d1e2a7ff util: create a context manager to handle timing
Martijn Pieters <mj@zopatista.com>
parents:
diff changeset
   137
    silenttestrunner.main(__name__)