File: test_utils.py

package info (click to toggle)
python-pika 1.3.2-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,088 kB
  • sloc: python: 20,890; makefile: 134
file content (74 lines) | stat: -rw-r--r-- 2,615 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
"""Acceptance test utils"""

import functools
import logging
import time
import traceback
import pika.compat


def retry_assertion(timeout_sec, retry_interval_sec=0.1):
    """Creates a decorator that retries the decorated function or
    method only upon `AssertionError` exception at the given retry interval
    not to exceed the overall given timeout.

    :param float timeout_sec: overall timeout in seconds
    :param float retry_interval_sec: amount of time to sleep
        between retries in seconds.

    :returns: decorator that implements the following behavior

    1. This decorator guarantees to call the decorated function or method at
    least once.
    2. It passes through all exceptions besides `AssertionError`, preserving the
    original exception and its traceback.
    3. If no exception, it returns the return value from the decorated function/method.
    4. It sleeps `time.sleep(retry_interval_sec)` between retries.
    5. It checks for expiry of the overall timeout before sleeping.
    6. If the overall timeout is exceeded, it re-raises the latest `AssertionError`,
    preserving its original traceback
    """

    def retry_assertion_decorator(func):
        """Decorator"""

        @functools.wraps(func)
        def retry_assertion_wrap(*args, **kwargs):
            """The wrapper"""

            num_attempts = 0
            start_time = pika.compat.time_now()

            while True:
                num_attempts += 1

                try:
                    result = func(*args, **kwargs)
                except AssertionError:

                    now = pika.compat.time_now()
                    # Compensate for time adjustment
                    if now < start_time:
                        start_time = now

                    if (now - start_time) > timeout_sec:
                        logging.exception(
                            'Exceeded retry timeout of %s sec in %s attempts '
                            'with func %r. Caller\'s stack:\n%s',
                            timeout_sec, num_attempts, func,
                            ''.join(traceback.format_stack()))
                        raise

                    logging.debug('Attempt %s failed; retrying %r in %s sec.',
                                  num_attempts, func, retry_interval_sec)

                    time.sleep(retry_interval_sec)
                else:
                    logging.debug('%r succeeded at attempt %s',
                                  func, num_attempts)
                    return result

        return retry_assertion_wrap

    return retry_assertion_decorator