Merge "Remove race due to 1907084"
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index c7004dd..c1981f9 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -126,16 +126,16 @@
.. code-block:: python
- class BaseTestCase1(api_version_utils.BaseMicroversionTest):
+ class BaseTestCase1(api_version_utils.BaseMicroversionTest):
- [..]
- @classmethod
- def skip_checks(cls):
- super(BaseTestCase1, cls).skip_checks()
- api_version_utils.check_skip_with_microversion(cls.min_microversion,
- cls.max_microversion,
- CONF.compute.min_microversion,
- CONF.compute.max_microversion)
+ [..]
+ @classmethod
+ def skip_checks(cls):
+ super(BaseTestCase1, cls).skip_checks()
+ api_version_utils.check_skip_with_microversion(cls.min_microversion,
+ cls.max_microversion,
+ CONF.compute.min_microversion,
+ CONF.compute.max_microversion)
Skip logic can be added in tests base class or any specific test class depends on
tests class structure.
diff --git a/doc/source/plugins/plugin.rst b/doc/source/plugins/plugin.rst
index ab1b0b1..6726def 100644
--- a/doc/source/plugins/plugin.rst
+++ b/doc/source/plugins/plugin.rst
@@ -268,12 +268,12 @@
class MyAPIClient(rest_client.RestClient):
- def __init__(self, auth_provider, service, region,
- my_arg, my_arg2=True, **kwargs):
- super(MyAPIClient, self).__init__(
- auth_provider, service, region, **kwargs)
- self.my_arg = my_arg
- self.my_args2 = my_arg
+ def __init__(self, auth_provider, service, region,
+ my_arg, my_arg2=True, **kwargs):
+ super(MyAPIClient, self).__init__(
+ auth_provider, service, region, **kwargs)
+ self.my_arg = my_arg
+ self.my_args2 = my_arg
Finally the service client should be structured in a python module, so that all
service client classes are importable from it. Each major API version should
diff --git a/doc/source/write_tests.rst b/doc/source/write_tests.rst
index 0a29b7b..34df089 100644
--- a/doc/source/write_tests.rst
+++ b/doc/source/write_tests.rst
@@ -76,54 +76,54 @@
class TestExampleCase(test.BaseTestCase):
- @classmethod
- def skip_checks(cls):
- """This section is used to evaluate config early and skip all test
- methods based on these checks
- """
- super(TestExampleCase, cls).skip_checks()
- if not CONF.section.foo
- cls.skip('A helpful message')
+ @classmethod
+ def skip_checks(cls):
+ """This section is used to evaluate config early and skip all test
+ methods based on these checks
+ """
+ super(TestExampleCase, cls).skip_checks()
+ if not CONF.section.foo
+ cls.skip('A helpful message')
- @classmethod
- def setup_credentials(cls):
- """This section is used to do any manual credential allocation and also
- in the case of dynamic credentials to override the default network
- resource creation/auto allocation
- """
- # This call is used to tell the credential allocator to not create any
- # network resources for this test case. It also enables selective
- # creation of other neutron resources. NOTE: it must go before the
- # super call
- cls.set_network_resources()
- super(TestExampleCase, cls).setup_credentials()
+ @classmethod
+ def setup_credentials(cls):
+ """This section is used to do any manual credential allocation and also
+ in the case of dynamic credentials to override the default network
+ resource creation/auto allocation
+ """
+ # This call is used to tell the credential allocator to not create any
+ # network resources for this test case. It also enables selective
+ # creation of other neutron resources. NOTE: it must go before the
+ # super call
+ cls.set_network_resources()
+ super(TestExampleCase, cls).setup_credentials()
- @classmethod
- def setup_clients(cls):
- """This section is used to setup client aliases from the manager object
- or to initialize any additional clients. Except in a few very
- specific situations you should not need to use this.
- """
- super(TestExampleCase, cls).setup_clients()
- cls.servers_client = cls.os_primary.servers_client
+ @classmethod
+ def setup_clients(cls):
+ """This section is used to setup client aliases from the manager object
+ or to initialize any additional clients. Except in a few very
+ specific situations you should not need to use this.
+ """
+ super(TestExampleCase, cls).setup_clients()
+ cls.servers_client = cls.os_primary.servers_client
- @classmethod
- def resource_setup(cls):
- """This section is used to create any resources or objects which are
- going to be used and shared by **all** test methods in the
- TestCase. Note then anything created in this section must also be
- destroyed in the corresponding resource_cleanup() method (which will
- be run during tearDownClass())
- """
- super(TestExampleCase, cls).resource_setup()
- cls.shared_server = cls.servers_client.create_server(...)
- cls.addClassResourceCleanup(waiters.wait_for_server_termination,
- cls.servers_client,
- cls.shared_server['id'])
- cls.addClassResourceCleanup(
- test_utils.call_and_ignore_notfound_exc(
- cls.servers_client.delete_server,
- cls.shared_server['id']))
+ @classmethod
+ def resource_setup(cls):
+ """This section is used to create any resources or objects which are
+ going to be used and shared by **all** test methods in the
+ TestCase. Note then anything created in this section must also be
+ destroyed in the corresponding resource_cleanup() method (which will
+ be run during tearDownClass())
+ """
+ super(TestExampleCase, cls).resource_setup()
+ cls.shared_server = cls.servers_client.create_server(...)
+ cls.addClassResourceCleanup(waiters.wait_for_server_termination,
+ cls.servers_client,
+ cls.shared_server['id'])
+ cls.addClassResourceCleanup(
+ test_utils.call_and_ignore_notfound_exc(
+ cls.servers_client.delete_server,
+ cls.shared_server['id']))
.. _credentials:
@@ -150,9 +150,9 @@
credentials = ['primary', 'admin']
- @classmethod
- def skip_checks(cls):
- ...
+ @classmethod
+ def skip_checks(cls):
+ ...
In this example the ``TestExampleAdmin`` TestCase will allocate 2 sets of
credentials, one regular user and one admin user. The corresponding manager
@@ -225,10 +225,10 @@
class TestExampleCase(test.BaseTestCase):
- @classmethod
- def setup_credentials(cls):
- cls.set_network_resources(network=True, subnet=True, router=False)
- super(TestExampleCase, cls).setup_credentials()
+ @classmethod
+ def setup_credentials(cls):
+ cls.set_network_resources(network=True, subnet=True, router=False)
+ super(TestExampleCase, cls).setup_credentials()
There are 2 quirks with the usage here. First for the set_network_resources
function to work properly it **must be called before super()**. This is so
@@ -242,10 +242,10 @@
class TestExampleCase(test.BaseTestCase):
- @classmethod
- def setup_credentials(cls):
- cls.set_network_resources()
- super(TestExampleCase, cls).setup_credentials()
+ @classmethod
+ def setup_credentials(cls):
+ cls.set_network_resources()
+ super(TestExampleCase, cls).setup_credentials()
This will not allocate any networking resources. This is because by default all
the arguments default to False.
@@ -282,8 +282,8 @@
class TestExampleCase(test.BaseTestCase):
- def test_example_create_server(self):
- self.os_primary.servers_client.create_server(...)
+ def test_example_create_server(self):
+ self.os_primary.servers_client.create_server(...)
is all you need to do. As described previously, in the above example the
``self.os_primary`` is created automatically because the base test class sets the
@@ -305,8 +305,8 @@
class TestExampleCase(test.BaseTestCase):
- def test_example_create_server(self):
- credentials = self.os_primary.credentials
+ def test_example_create_server(self):
+ credentials = self.os_primary.credentials
The credentials object provides access to all of the credential information you
would need to make API requests. For example, building off the previous
@@ -316,9 +316,9 @@
class TestExampleCase(test.BaseTestCase):
- def test_example_create_server(self):
- credentials = self.os_primary.credentials
- username = credentials.username
- user_id = credentials.user_id
- password = credentials.password
- tenant_id = credentials.tenant_id
+ def test_example_create_server(self):
+ credentials = self.os_primary.credentials
+ username = credentials.username
+ user_id = credentials.user_id
+ password = credentials.password
+ tenant_id = credentials.tenant_id
diff --git a/releasenotes/notes/associate-disassociate-floating_ip-0b6cfebeef1304b0.yaml b/releasenotes/notes/associate-disassociate-floating_ip-0b6cfebeef1304b0.yaml
new file mode 100644
index 0000000..8e42e85
--- /dev/null
+++ b/releasenotes/notes/associate-disassociate-floating_ip-0b6cfebeef1304b0.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Added associate_floating_ip() and dissociate_floating_ip() methods
+ to the scenario manager.
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 28299a4..9e25901 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -402,7 +402,8 @@
# Validate that the list was fetched sorted accordingly
msg = 'No images were found that met the filter criteria.'
self.assertNotEmpty(images_list, msg)
- sorted_list = [image['size'] for image in images_list]
+ sorted_list = [image['size'] for image in images_list
+ if image['size'] is not None]
msg = 'The list of images was not sorted correctly.'
self.assertEqual(sorted(sorted_list, reverse=desc), sorted_list, msg)
diff --git a/tempest/config.py b/tempest/config.py
index 0d49b51..382b80f 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -761,11 +761,13 @@
deprecated_reason="This config option is no longer "
"used anywhere, so it can be removed."),
cfg.StrOpt('port_vnic_type',
- choices=[None, 'normal', 'direct', 'macvtap'],
+ choices=[None, 'normal', 'direct', 'macvtap', 'direct-physical',
+ 'baremetal', 'virtio-forwarder'],
help="vnic_type to use when launching instances"
" with pre-configured ports."
" Supported ports are:"
- " ['normal','direct','macvtap']"),
+ " ['normal', 'direct', 'macvtap', 'direct-physical', "
+ "'baremetal', 'virtio-forwarder']"),
cfg.Opt('port_profile',
type=ProfileType,
default={},
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 5ae72b2..2a41d13 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -201,6 +201,14 @@
direct: an SR-IOV port that is directly attached to a VM
macvtap: an SR-IOV port that is attached to a VM via a macvtap
device.
+ direct-physical: an SR-IOV port that is directly attached to a
+ VM using physical instead of virtual
+ functions.
+ baremetal: a baremetal port directly attached to a baremetal
+ node.
+ virtio-forwarder: an SR-IOV port that is indirectly attached
+ to a VM using a low-latency vhost-user
+ forwarding process.
Defaults to ``CONF.network.port_vnic_type``.
* *port_profile* (``dict``) --
This attribute is a dictionary that can be used (with admin
@@ -861,15 +869,25 @@
return timestamp
def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
- private_key=None, server=None):
+ private_key=None, server=None, username=None):
"""Returns timestamp
This wrapper utility does ssh and returns the timestamp.
+
+ :param ip_address: The floating IP or fixed IP of the remote server
+ :param dev_name: Name of the device that stores the timestamp
+ :param mount_path: Path which should be used as mount point for
+ dev_name
+ :param private_key: The SSH private key to use for authentication
+ :param server: Server dict, used for debugging purposes
+ :param username: Name of the Linux account on the remote server
"""
ssh_client = self.get_remote_client(ip_address,
private_key=private_key,
- server=server)
+ server=server,
+ username=username)
+
if dev_name is not None:
ssh_client.mount(dev_name, mount_path)
timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
@@ -1165,6 +1183,32 @@
floating_ip['id'])
return floating_ip
+ def associate_floating_ip(self, floating_ip, server):
+ """Associate floating ip
+
+ This wrapper utility attaches the floating_ip for
+ the respective port_id of server
+ """
+ port_id, _ = self._get_server_port_id_and_ip4(server)
+ kwargs = dict(port_id=port_id)
+ floating_ip = self.floating_ips_client.update_floatingip(
+ floating_ip['id'], **kwargs)['floatingip']
+ self.assertEqual(port_id, floating_ip['port_id'])
+ return floating_ip
+
+ def disassociate_floating_ip(self, floating_ip):
+ """Disassociates floating ip
+
+ This wrapper utility disassociates given floating ip.
+ :param floating_ip: a dict which is a return value of
+ floating_ips_client.create_floatingip method
+ """
+ kwargs = dict(port_id=None)
+ floating_ip = self.floating_ips_client.update_floatingip(
+ floating_ip['id'], **kwargs)['floatingip']
+ self.assertIsNone(floating_ip['port_id'])
+ return floating_ip
+
def check_floating_ip_status(self, floating_ip, status):
"""Verifies floatingip reaches the given status