Move `call_until_true` to tempest/lib
This `call_until_true()` is handy and could be used in Tempest plugins. Let's move it to tempest/lib. Also add some unit tests. Change-Id: Ie379030baa336239e6027c8f3cdbeb74c561f66b
This commit is contained in:
parent
0ef4c8cf75
commit
35a6375fd1
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
deprecations:
|
||||
- The ``call_until_true`` function is moved from the ``tempest.test`` module
|
||||
to the ``tempest.lib.common.utils.test_utils`` module. Backward
|
||||
compatibilty is preserved until Ocata.
|
|
@ -22,3 +22,4 @@ stevedore>=1.16.0 # Apache-2.0
|
|||
PrettyTable<0.8,>=0.7 # BSD
|
||||
os-testr>=0.7.0 # Apache-2.0
|
||||
urllib3>=1.15.1 # MIT
|
||||
debtcollector>=1.2.0 # Apache-2.0
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
import datetime
|
||||
|
||||
from tempest.api.compute import base
|
||||
from tempest.lib.common.utils import test_utils
|
||||
from tempest.lib import exceptions as e
|
||||
from tempest import test
|
||||
|
||||
|
@ -59,8 +60,8 @@ class TenantUsagesTestJSON(base.BaseV2ComputeAdminTest):
|
|||
return True
|
||||
except e.InvalidHTTPResponseBody:
|
||||
return False
|
||||
self.assertEqual(test.call_until_true(is_valid, duration, 1), True,
|
||||
"%s not return valid response in %s secs" % (
|
||||
self.assertEqual(test_utils.call_until_true(is_valid, duration, 1),
|
||||
True, "%s not return valid response in %s secs" % (
|
||||
func.__name__, duration))
|
||||
return self.resp
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# under the License.
|
||||
import inspect
|
||||
import re
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
|
@ -83,3 +84,24 @@ def call_and_ignore_notfound_exc(func, *args, **kwargs):
|
|||
return func(*args, **kwargs)
|
||||
except exceptions.NotFound:
|
||||
pass
|
||||
|
||||
|
||||
def call_until_true(func, duration, sleep_for):
|
||||
"""Call the given function until it returns True (and return True)
|
||||
|
||||
or until the specified duration (in seconds) elapses (and return False).
|
||||
|
||||
:param func: A zero argument callable that returns True on success.
|
||||
:param duration: The number of seconds for which to attempt a
|
||||
successful call of the function.
|
||||
:param sleep_for: The number of seconds to sleep after an unsuccessful
|
||||
invocation of the function.
|
||||
"""
|
||||
now = time.time()
|
||||
timeout = now + duration
|
||||
while now < timeout:
|
||||
if func():
|
||||
return True
|
||||
time.sleep(sleep_for)
|
||||
now = time.time()
|
||||
return False
|
||||
|
|
|
@ -513,7 +513,7 @@ class ScenarioTest(tempest.test.BaseTestCase):
|
|||
'should_succeed':
|
||||
'reachable' if should_succeed else 'unreachable'
|
||||
})
|
||||
result = tempest.test.call_until_true(ping, timeout, 1)
|
||||
result = test_utils.call_until_true(ping, timeout, 1)
|
||||
LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
|
||||
'ping result is %(result)s' % {
|
||||
'caller': caller, 'ip': ip_address, 'timeout': timeout,
|
||||
|
@ -857,9 +857,9 @@ class NetworkScenarioTest(ScenarioTest):
|
|||
show_floatingip(floatingip_id)['floatingip'])
|
||||
return status == result['status']
|
||||
|
||||
tempest.test.call_until_true(refresh,
|
||||
CONF.network.build_timeout,
|
||||
CONF.network.build_interval)
|
||||
test_utils.call_until_true(refresh,
|
||||
CONF.network.build_timeout,
|
||||
CONF.network.build_interval)
|
||||
floating_ip = self.floating_ips_client.show_floatingip(
|
||||
floatingip_id)['floatingip']
|
||||
self.assertEqual(status, floating_ip['status'],
|
||||
|
@ -914,9 +914,9 @@ class NetworkScenarioTest(ScenarioTest):
|
|||
return not should_succeed
|
||||
return should_succeed
|
||||
|
||||
return tempest.test.call_until_true(ping_remote,
|
||||
CONF.validation.ping_timeout,
|
||||
1)
|
||||
return test_utils.call_until_true(ping_remote,
|
||||
CONF.validation.ping_timeout,
|
||||
1)
|
||||
|
||||
def _create_security_group(self, security_group_rules_client=None,
|
||||
tenant_id=None,
|
||||
|
@ -1249,7 +1249,7 @@ class BaremetalScenarioTest(ScenarioTest):
|
|||
return True
|
||||
return False
|
||||
|
||||
if not tempest.test.call_until_true(
|
||||
if not test_utils.call_until_true(
|
||||
check_state, timeout, interval):
|
||||
msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
|
||||
(node_id, state_attr, target_states))
|
||||
|
@ -1273,7 +1273,7 @@ class BaremetalScenarioTest(ScenarioTest):
|
|||
self.get_node, instance_id=instance_id)
|
||||
return node is not None
|
||||
|
||||
if not tempest.test.call_until_true(
|
||||
if not test_utils.call_until_true(
|
||||
_get_node, CONF.baremetal.association_timeout, 1):
|
||||
msg = ('Timed out waiting to get Ironic node by instance id %s'
|
||||
% instance_id)
|
||||
|
|
|
@ -17,6 +17,7 @@ from tempest.common import custom_matchers
|
|||
from tempest.common import waiters
|
||||
from tempest import config
|
||||
from tempest import exceptions
|
||||
from tempest.lib.common.utils import test_utils
|
||||
from tempest.scenario import manager
|
||||
from tempest import test
|
||||
|
||||
|
@ -88,9 +89,9 @@ class TestMinimumBasicScenario(manager.ScenarioTest):
|
|||
['server'])
|
||||
return {'name': secgroup['name']} in body['security_groups']
|
||||
|
||||
if not test.call_until_true(wait_for_secgroup_add,
|
||||
CONF.compute.build_timeout,
|
||||
CONF.compute.build_interval):
|
||||
if not test_utils.call_until_true(wait_for_secgroup_add,
|
||||
CONF.compute.build_timeout,
|
||||
CONF.compute.build_interval):
|
||||
msg = ('Timed out waiting for adding security group %s to server '
|
||||
'%s' % (secgroup['id'], server['id']))
|
||||
raise exceptions.TimeoutException(msg)
|
||||
|
|
|
@ -263,8 +263,9 @@ class TestNetworkBasicOps(manager.NetworkScenarioTest):
|
|||
if port['id'] != old_port['id']]
|
||||
return len(self.new_port_list) == 1
|
||||
|
||||
if not test.call_until_true(check_ports, CONF.network.build_timeout,
|
||||
CONF.network.build_interval):
|
||||
if not test_utils.call_until_true(
|
||||
check_ports, CONF.network.build_timeout,
|
||||
CONF.network.build_interval):
|
||||
raise exceptions.TimeoutException(
|
||||
"No new port attached to the server in time (%s sec)! "
|
||||
"Old port: %s. Number of new ports: %d" % (
|
||||
|
@ -277,8 +278,9 @@ class TestNetworkBasicOps(manager.NetworkScenarioTest):
|
|||
self.diff_list = [n for n in new_nic_list if n not in old_nic_list]
|
||||
return len(self.diff_list) == 1
|
||||
|
||||
if not test.call_until_true(check_new_nic, CONF.network.build_timeout,
|
||||
CONF.network.build_interval):
|
||||
if not test_utils.call_until_true(
|
||||
check_new_nic, CONF.network.build_timeout,
|
||||
CONF.network.build_interval):
|
||||
raise exceptions.TimeoutException("Interface not visible on the "
|
||||
"guest after %s sec"
|
||||
% CONF.network.build_timeout)
|
||||
|
@ -593,9 +595,9 @@ class TestNetworkBasicOps(manager.NetworkScenarioTest):
|
|||
return False
|
||||
return True
|
||||
|
||||
self.assertTrue(test.call_until_true(check_new_dns_server,
|
||||
renew_timeout,
|
||||
renew_delay),
|
||||
self.assertTrue(test_utils.call_until_true(check_new_dns_server,
|
||||
renew_timeout,
|
||||
renew_delay),
|
||||
msg="DHCP renewal failed to fetch "
|
||||
"new DNS nameservers")
|
||||
|
||||
|
|
|
@ -187,10 +187,10 @@ class TestGettingAddress(manager.NetworkScenarioTest):
|
|||
srv2_v6_addr_assigned = functools.partial(
|
||||
guest_has_address, sshv4_2, ips_from_api_2['6'][i])
|
||||
|
||||
self.assertTrue(test.call_until_true(srv1_v6_addr_assigned,
|
||||
self.assertTrue(test_utils.call_until_true(srv1_v6_addr_assigned,
|
||||
CONF.validation.ping_timeout, 1))
|
||||
|
||||
self.assertTrue(test.call_until_true(srv2_v6_addr_assigned,
|
||||
self.assertTrue(test_utils.call_until_true(srv2_v6_addr_assigned,
|
||||
CONF.validation.ping_timeout, 1))
|
||||
|
||||
self._check_connectivity(sshv4_1, ips_from_api_2['4'])
|
||||
|
|
|
@ -18,6 +18,7 @@ import re
|
|||
|
||||
from tempest import config
|
||||
from tempest import exceptions
|
||||
from tempest.lib.common.utils import test_utils
|
||||
from tempest.scenario import manager
|
||||
from tempest import test
|
||||
|
||||
|
@ -70,9 +71,9 @@ class TestServerBasicOps(manager.ScenarioTest):
|
|||
self.assertEqual(self.fip, result, msg)
|
||||
return 'Verification is successful!'
|
||||
|
||||
if not test.call_until_true(exec_cmd_and_verify_output,
|
||||
CONF.compute.build_timeout,
|
||||
CONF.compute.build_interval):
|
||||
if not test_utils.call_until_true(exec_cmd_and_verify_output,
|
||||
CONF.compute.build_timeout,
|
||||
CONF.compute.build_interval):
|
||||
raise exceptions.TimeoutException('Timed out while waiting to '
|
||||
'verify metadata on server. '
|
||||
'%s is empty.' % md_url)
|
||||
|
|
|
@ -22,6 +22,7 @@ from tempest.common.utils import data_utils
|
|||
from tempest.common import waiters
|
||||
from tempest import config
|
||||
from tempest import exceptions
|
||||
from tempest.lib.common.utils import test_utils
|
||||
from tempest.lib import decorators
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
from tempest.scenario import manager
|
||||
|
@ -89,9 +90,9 @@ class TestStampPattern(manager.ScenarioTest):
|
|||
LOG.debug("Partitions:%s" % part)
|
||||
return CONF.compute.volume_device_name in part
|
||||
|
||||
if not test.call_until_true(_func,
|
||||
CONF.compute.build_timeout,
|
||||
CONF.compute.build_interval):
|
||||
if not test_utils.call_until_true(_func,
|
||||
CONF.compute.build_timeout,
|
||||
CONF.compute.build_interval):
|
||||
raise exceptions.TimeoutException
|
||||
|
||||
@decorators.skip_because(bug="1205344")
|
||||
|
|
|
@ -16,8 +16,8 @@ import subprocess
|
|||
from tempest.common.utils import data_utils
|
||||
from tempest.common import waiters
|
||||
from tempest import config
|
||||
from tempest.lib.common.utils import test_utils
|
||||
import tempest.stress.stressaction as stressaction
|
||||
import tempest.test
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
@ -52,8 +52,8 @@ class FloatingStress(stressaction.StressAction):
|
|||
def check_port_ssh(self):
|
||||
def func():
|
||||
return self.tcp_connect_scan(self.floating['ip'], 22)
|
||||
if not tempest.test.call_until_true(func, self.check_timeout,
|
||||
self.check_interval):
|
||||
if not test_utils.call_until_true(func, self.check_timeout,
|
||||
self.check_interval):
|
||||
raise RuntimeError("Cannot connect to the ssh port.")
|
||||
|
||||
def check_icmp_echo(self):
|
||||
|
@ -62,8 +62,8 @@ class FloatingStress(stressaction.StressAction):
|
|||
|
||||
def func():
|
||||
return self.ping_ip_address(self.floating['ip'])
|
||||
if not tempest.test.call_until_true(func, self.check_timeout,
|
||||
self.check_interval):
|
||||
if not test_utils.call_until_true(func, self.check_timeout,
|
||||
self.check_interval):
|
||||
raise RuntimeError("%s(%s): Cannot ping the machine.",
|
||||
self.server_id, self.floating['ip'])
|
||||
self.logger.info("%s(%s): pong :)",
|
||||
|
@ -153,8 +153,8 @@ class FloatingStress(stressaction.StressAction):
|
|||
['floating_ip'])
|
||||
return floating['instance_id'] is None
|
||||
|
||||
if not tempest.test.call_until_true(func, self.check_timeout,
|
||||
self.check_interval):
|
||||
if not test_utils.call_until_true(func, self.check_timeout,
|
||||
self.check_interval):
|
||||
raise RuntimeError("IP disassociate timeout!")
|
||||
|
||||
def run_core(self):
|
||||
|
|
|
@ -16,8 +16,8 @@ from tempest.common.utils import data_utils
|
|||
from tempest.common.utils.linux import remote_client
|
||||
from tempest.common import waiters
|
||||
from tempest import config
|
||||
from tempest.lib.common.utils import test_utils
|
||||
import tempest.stress.stressaction as stressaction
|
||||
import tempest.test
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
@ -105,8 +105,8 @@ class VolumeVerifyStress(stressaction.StressAction):
|
|||
['floating_ip'])
|
||||
return floating['instance_id'] is None
|
||||
|
||||
if not tempest.test.call_until_true(func, CONF.compute.build_timeout,
|
||||
CONF.compute.build_interval):
|
||||
if not test_utils.call_until_true(func, CONF.compute.build_timeout,
|
||||
CONF.compute.build_interval):
|
||||
raise RuntimeError("IP disassociate timeout!")
|
||||
|
||||
def new_server_ops(self):
|
||||
|
@ -179,9 +179,9 @@ class VolumeVerifyStress(stressaction.StressAction):
|
|||
if self.part_line_re.match(part_line):
|
||||
matching += 1
|
||||
return matching == num_match
|
||||
if tempest.test.call_until_true(_part_state,
|
||||
CONF.compute.build_timeout,
|
||||
CONF.compute.build_interval):
|
||||
if test_utils.call_until_true(_part_state,
|
||||
CONF.compute.build_timeout,
|
||||
CONF.compute.build_interval):
|
||||
return
|
||||
else:
|
||||
raise RuntimeError("Unexpected partitions: %s",
|
||||
|
|
|
@ -18,8 +18,8 @@ import functools
|
|||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
|
||||
import debtcollector.moves
|
||||
import fixtures
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils as json
|
||||
|
@ -38,6 +38,7 @@ import tempest.common.validation_resources as vresources
|
|||
from tempest import config
|
||||
from tempest import exceptions
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib.common.utils import test_utils
|
||||
from tempest.lib import decorators
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
|
||||
|
@ -866,22 +867,6 @@ def SimpleNegativeAutoTest(klass):
|
|||
return klass
|
||||
|
||||
|
||||
def call_until_true(func, duration, sleep_for):
|
||||
"""Call the given function until it returns True (and return True)
|
||||
|
||||
or until the specified duration (in seconds) elapses (and return False).
|
||||
|
||||
:param func: A zero argument callable that returns True on success.
|
||||
:param duration: The number of seconds for which to attempt a
|
||||
successful call of the function.
|
||||
:param sleep_for: The number of seconds to sleep after an unsuccessful
|
||||
invocation of the function.
|
||||
"""
|
||||
now = time.time()
|
||||
timeout = now + duration
|
||||
while now < timeout:
|
||||
if func():
|
||||
return True
|
||||
time.sleep(sleep_for)
|
||||
now = time.time()
|
||||
return False
|
||||
call_until_true = debtcollector.moves.moved_function(
|
||||
test_utils.call_until_true, 'call_until_true', __name__,
|
||||
version='Newton', removal_version='Ocata')
|
||||
|
|
|
@ -17,6 +17,7 @@ import mock
|
|||
from tempest.lib.common.utils import test_utils
|
||||
from tempest.lib import exceptions
|
||||
from tempest.tests import base
|
||||
from tempest.tests import utils
|
||||
|
||||
|
||||
class TestTestUtils(base.TestCase):
|
||||
|
@ -76,3 +77,27 @@ class TestTestUtils(base.TestCase):
|
|||
self.assertEqual(
|
||||
42, test_utils.call_and_ignore_notfound_exc(m, *args, **kwargs))
|
||||
m.assert_called_once_with(*args, **kwargs)
|
||||
|
||||
@mock.patch('time.sleep')
|
||||
@mock.patch('time.time')
|
||||
def test_call_until_true_when_f_never_returns_true(self, m_time, m_sleep):
|
||||
timeout = 42 # The value doesn't matter as we mock time.time()
|
||||
sleep = 60 # The value doesn't matter as we mock time.sleep()
|
||||
m_time.side_effect = utils.generate_timeout_series(timeout)
|
||||
self.assertEqual(
|
||||
False, test_utils.call_until_true(lambda: False, timeout, sleep)
|
||||
)
|
||||
m_sleep.call_args_list = [mock.call(sleep)] * 2
|
||||
m_time.call_args_list = [mock.call()] * 2
|
||||
|
||||
@mock.patch('time.sleep')
|
||||
@mock.patch('time.time')
|
||||
def test_call_until_true_when_f_returns_true(self, m_time, m_sleep):
|
||||
timeout = 42 # The value doesn't matter as we mock time.time()
|
||||
sleep = 60 # The value doesn't matter as we mock time.sleep()
|
||||
m_time.return_value = 0
|
||||
self.assertEqual(
|
||||
True, test_utils.call_until_true(lambda: True, timeout, sleep)
|
||||
)
|
||||
self.assertEqual(0, m_sleep.call_count)
|
||||
self.assertEqual(1, m_time.call_count)
|
||||
|
|
Loading…
Reference in New Issue