diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py index 71599bd980..45a7b8a598 100644 --- a/tempest/common/waiters.py +++ b/tempest/common/waiters.py @@ -604,6 +604,22 @@ def wait_for_ping(server_ip, timeout=30, interval=1): raise lib_exc.TimeoutException() +def wait_for_port_status(client, port_id, status): + """Wait for a port reach a certain status : ["BUILD" | "DOWN" | "ACTIVE"] + :param client: The network client to use when querying the port's + status + :param status: A string to compare the current port status-to. + :param port_id: The uuid of the port we would like queried for status. + """ + start_time = time.time() + while (time.time() - start_time <= client.build_timeout): + result = client.show_port(port_id) + if result['port']['status'].lower() == status.lower(): + return result + time.sleep(client.build_interval) + raise lib_exc.TimeoutException + + def wait_for_ssh(ssh_client, timeout=30): """Waits for SSH connection to become usable""" start_time = int(time.time()) diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py index 2843498c65..bf3f62fa70 100644 --- a/tempest/scenario/manager.py +++ b/tempest/scenario/manager.py @@ -145,6 +145,7 @@ class ScenarioTest(tempest.test.BaseTestCase): - 'binding:vnic_type' - defaults to CONF.network.port_vnic_type - 'binding:profile' - defaults to CONF.network.port_profile """ + if not client: client = self.ports_client name = data_utils.rand_name( @@ -158,10 +159,12 @@ class ScenarioTest(tempest.test.BaseTestCase): network_id=network_id, **kwargs) self.assertIsNotNone(result, 'Unable to allocate port') - port = result['port'] + port_id = result['port']['id'] self.addCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_port, port['id']) - return port + client.delete_port, port_id) + port = waiters.wait_for_port_status( + client=client, port_id=port_id, status="DOWN") + return port["port"] def create_keypair(self, client=None, **kwargs): """Creates keypair diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py index 71088a4223..2695048b04 100755 --- a/tempest/tests/common/test_waiters.py +++ b/tempest/tests/common/test_waiters.py @@ -21,6 +21,7 @@ from tempest.common import waiters from tempest import exceptions from tempest.lib import exceptions as lib_exc from tempest.lib.services.compute import servers_client +from tempest.lib.services.network import ports_client from tempest.lib.services.volume.v2 import volumes_client from tempest.tests import base import tempest.tests.utils as utils @@ -612,6 +613,48 @@ class TestVolumeWaiters(base.TestCase): ) +class TestPortCreationWaiter(base.TestCase): + def test_wait_for_port_status(self): + """Test that the waiter replies with the port before the timeout""" + + def client_response(self): + """Mock client response, replies with the final status after + 2 calls + """ + if mock_client.call_count >= 2: + return mock_port + else: + mock_client.call_count += 1 + return mock_port_build + + mock_port = {'port': {'id': '1234', 'status': "DOWN"}} + mock_port_build = {'port': {'id': '1234', 'status': "BUILD"}} + mock_client = mock.Mock( + spec=ports_client.PortsClient, + build_timeout=30, build_interval=1, + show_port=client_response) + fake_port_id = "1234" + fake_status = "DOWN" + self.assertEqual(mock_port, waiters.wait_for_port_status( + mock_client, fake_port_id, fake_status)) + + def test_wait_for_port_status_timeout(self): + """Negative test - checking that a timeout + presented by a small 'fake_timeout' and a static status of + 'BUILD' in the mock will raise a timeout exception + """ + mock_port = {'port': {'id': '1234', 'status': "BUILD"}} + mock_client = mock.Mock( + spec=ports_client.PortsClient, + build_timeout=2, build_interval=1, + show_port=lambda id: mock_port) + fake_port_id = "1234" + fake_status = "ACTIVE" + self.assertRaises(lib_exc.TimeoutException, + waiters.wait_for_port_status, mock_client, + fake_port_id, fake_status) + + class TestServerFloatingIPWaiters(base.TestCase): def test_wait_for_server_floating_ip_associate_timeout(self):