From 75588a4333aef6a3830cd120136a664418d336e9 Mon Sep 17 00:00:00 2001 From: Jhon Honce Date: Mon, 20 Aug 2018 08:40:42 -0700 Subject: Add retry decorator for flakey tests * Update doc strings Signed-off-by: Jhon Honce Closes: #1302 Approved by: baude --- contrib/python/podman/test/podman_testcase.py | 4 +++ contrib/python/podman/test/retry_decorator.py | 43 +++++++++++++++++++++++++++ contrib/python/podman/test/test_containers.py | 3 ++ 3 files changed, 50 insertions(+) create mode 100644 contrib/python/podman/test/retry_decorator.py (limited to 'contrib/python') diff --git a/contrib/python/podman/test/podman_testcase.py b/contrib/python/podman/test/podman_testcase.py index 731fa26fc..da73c1024 100644 --- a/contrib/python/podman/test/podman_testcase.py +++ b/contrib/python/podman/test/podman_testcase.py @@ -1,3 +1,4 @@ +"""Base for podman tests.""" import contextlib import functools import itertools @@ -16,6 +17,7 @@ class PodmanTestCase(unittest.TestCase): @classmethod def setUpClass(cls): + """Fixture to setup podman test case.""" if hasattr(PodmanTestCase, 'alpine_process'): PodmanTestCase.tearDownClass() @@ -91,6 +93,7 @@ class PodmanTestCase(unittest.TestCase): @classmethod def tearDownClass(cls): + """Fixture to clean up after podman unittest.""" try: PodmanTestCase.alpine_process.kill() assert 0 == PodmanTestCase.alpine_process.wait(500) @@ -104,5 +107,6 @@ class PodmanTestCase(unittest.TestCase): @contextlib.contextmanager def assertRaisesNotImplemented(self): + """Sugar for unimplemented varlink methods.""" with self.assertRaisesRegex(VarlinkError, MethodNotImplemented): yield diff --git a/contrib/python/podman/test/retry_decorator.py b/contrib/python/podman/test/retry_decorator.py new file mode 100644 index 000000000..31e06f382 --- /dev/null +++ b/contrib/python/podman/test/retry_decorator.py @@ -0,0 +1,43 @@ +"""Decorator to retry failed method.""" +import functools +import time + + +def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, print_=None): + """Retry calling the decorated function using an exponential backoff. + + Specialized for our unittests + from: + http://www.saltycrane.com/blog/2009/11/trying-out-retry-decorator-python/ + original from: http://wiki.python.org/moin/PythonDecoratorLibrary#Retry + + :param ExceptionToCheck: the exception to check. may be a tuple of + exceptions to check + :type ExceptionToCheck: Exception or tuple + :param tries: number of times to try (not retry) before giving up + :type tries: int + :param delay: initial delay between retries in seconds + :type delay: int + :param backoff: backoff multiplier e.g. value of 2 will double the delay + each retry + :type backoff: int + """ + def deco_retry(f): + @functools.wraps(f) + def f_retry(*args, **kwargs): + mtries, mdelay = tries, delay + while mtries > 1: + try: + return f(*args, **kwargs) + except ExceptionToCheck as e: + if print_: + print_('{}, Retrying in {} seconds...'.format( + str(e), mdelay)) + time.sleep(mdelay) + mtries -= 1 + mdelay *= backoff + return f(*args, **kwargs) + + return f_retry # true decorator + + return deco_retry diff --git a/contrib/python/podman/test/test_containers.py b/contrib/python/podman/test/test_containers.py index f84b88f4c..167aae68b 100644 --- a/contrib/python/podman/test/test_containers.py +++ b/contrib/python/podman/test/test_containers.py @@ -2,6 +2,7 @@ import os import signal import unittest from test.podman_testcase import PodmanTestCase +from test.retry_decorator import retry import podman @@ -217,6 +218,8 @@ class TestContainers(PodmanTestCase): self.assertTrue(ctnr.running) self.assertTrue(ctnr.status, 'running') + # creating cgoups can be flakey + @retry(podman.libs.errors.ErrorOccurred, tries=16, delay=2, print_=print) def test_stats(self): self.assertTrue(self.alpine_ctnr.running) -- cgit v1.2.3-54-g00ecf