From b76f841ab41ce2965e6867a04177beb0affd0c10 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Thu, 26 Jul 2018 15:21:45 +0100 Subject: Enable "wait_until_true" when used ouf the main thread "util.wait_until_true" uses "util.Timer" to create an active wait for a condition. "Timer" class uses "signal" to create a watchdog to track the time lapsed. When used out of the main thread, "Timer" raises the following error: ValueError: signal only works in main thread To make "util.wait_until_true" usable always, a new waitting method is implemented. JIRA: YARDSTICK-1358 Change-Id: Ifb5ba0b17b5beca0af5ceab4f6431d58b7928762 Signed-off-by: Rodolfo Alonso Hernandez --- yardstick/common/utils.py | 25 +++++++++++++++++++++---- yardstick/tests/unit/common/test_utils.py | 21 ++++++++++++++++++--- 2 files changed, 39 insertions(+), 7 deletions(-) (limited to 'yardstick') diff --git a/yardstick/common/utils.py b/yardstick/common/utils.py index 83ddbd470..c74dd675e 100644 --- a/yardstick/common/utils.py +++ b/yardstick/common/utils.py @@ -28,6 +28,7 @@ import socket import subprocess import sys import time +import threading import six from flask import jsonify @@ -475,6 +476,9 @@ class Timer(object): def __del__(self): # pragma: no cover signal.alarm(0) + def delta_time_sec(self): + return (datetime.datetime.now() - self.start).total_seconds() + def read_meminfo(ssh_client): """Read "/proc/meminfo" file and parse all keys and values""" @@ -521,17 +525,30 @@ def open_relative_file(path, task_path): def wait_until_true(predicate, timeout=60, sleep=1, exception=None): """Wait until callable predicate is evaluated as True + When in a thread different from the main one, Timer(timeout) will fail + because signal is not handled. In this case + :param predicate: (func) callable deciding whether waiting should continue :param timeout: (int) timeout in seconds how long should function wait :param sleep: (int) polling interval for results in seconds :param exception: exception instance to raise on timeout. If None is passed (default) then WaitTimeout exception is raised. """ - try: - with Timer(timeout=timeout): - while not predicate(): + if isinstance(threading.current_thread(), threading._MainThread): + try: + with Timer(timeout=timeout): + while not predicate(): + time.sleep(sleep) + except exceptions.TimerTimeout: + if exception and issubclass(exception, Exception): + raise exception # pylint: disable=raising-bad-type + raise exceptions.WaitTimeout + else: + with Timer() as timer: + while timer.delta_time_sec() < timeout: + if predicate(): + return time.sleep(sleep) - except exceptions.TimerTimeout: if exception and issubclass(exception, Exception): raise exception # pylint: disable=raising-bad-type raise exceptions.WaitTimeout diff --git a/yardstick/tests/unit/common/test_utils.py b/yardstick/tests/unit/common/test_utils.py index bf0b5181a..7c58a8243 100644 --- a/yardstick/tests/unit/common/test_utils.py +++ b/yardstick/tests/unit/common/test_utils.py @@ -12,12 +12,14 @@ import errno import importlib import ipaddress from itertools import product, chain -import mock import os -import six -from six.moves import configparser import socket import time +import threading + +import mock +import six +from six.moves import configparser import unittest import yardstick @@ -1277,6 +1279,10 @@ class TimerTestCase(ut_base.BaseUnitTestCase): time.sleep(1.1) self.assertEqual(2, len(iterations)) + def test_delta_time_sec(self): + with utils.Timer() as timer: + self.assertIsInstance(timer.delta_time_sec(), float) + class WaitUntilTrueTestCase(ut_base.BaseUnitTestCase): @@ -1298,6 +1304,15 @@ class WaitUntilTrueTestCase(ut_base.BaseUnitTestCase): utils.wait_until_true(lambda: False, timeout=1, sleep=1, exception=MyTimeoutException)) + def _run_thread(self): + with self.assertRaises(exceptions.WaitTimeout): + utils.wait_until_true(lambda: False, timeout=1, sleep=1) + + def test_timeout_no_main_thread(self): + new_thread = threading.Thread(target=self._run_thread) + new_thread.start() + new_thread.join(timeout=3) + class SendSocketCommandTestCase(unittest.TestCase): -- cgit 1.2.3-korg