Merge "Change Cinder api_v3 config True on default"
diff --git a/HACKING.rst b/HACKING.rst
index c0a857c..dbb758b 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -22,6 +22,7 @@
- [T112] Check that tempest.lib should not import local tempest code
- [T113] Check that tests use data_utils.rand_uuid() instead of uuid.uuid4()
- [T114] Check that tempest.lib does not use tempest config
+- [T115] Check that admin tests should exist under admin path
- [N322] Method's default argument shouldn't be mutable
Test Data/Configuration
@@ -232,9 +233,9 @@
and xml version of the same test class there could still be a race between
methods.
-- The rand_name() function from tempest.common.utils.data_utils should be used
- anywhere a resource is created with a name. Static naming should be avoided
- to prevent resource conflicts.
+- The rand_name() function from tempest.lib.common.utils.data_utils should be
+ used anywhere a resource is created with a name. Static naming should be
+ avoided to prevent resource conflicts.
- If the execution of a set of tests is required to be serialized then locking
can be used to perform this. See AggregatesAdminTest in
diff --git a/doc/source/conf.py b/doc/source/conf.py
index cbfcc09..b9e22b5 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -27,6 +27,8 @@
import subprocess
import warnings
+import openstackdocstheme
+
# Build the plugin registry
def build_plugin_registry(app):
root_dir = os.path.dirname(
@@ -117,7 +119,7 @@
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'nature'
+html_theme = 'openstackdocs'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@@ -125,7 +127,7 @@
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-#html_theme_path = []
+html_theme_path = [openstackdocstheme.get_html_theme_path()]
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
@@ -153,8 +155,7 @@
git_cmd = ["git", "log", "--pretty=format:'%ad, commit %h'", "--date=local",
"-n1"]
try:
- html_last_updated_fmt = str(
- subprocess.Popen(git_cmd, stdout=subprocess.PIPE).communicate()[0])
+ html_last_updated_fmt = subprocess.check_output(git_cmd).decode('utf-8')
except Exception:
warnings.warn('Cannot get last updated time from git repository. '
'Not setting "html_last_updated_fmt".')
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index 2314222..4accd94 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -52,8 +52,7 @@
#. ``uri_v3``
The ``auth_version`` option is used to tell Tempest whether it should be using
-keystone's v2 or v3 api for communicating with keystone. (except for the
-identity api tests which will test a specific version) The two uri options are
+keystone's v2 or v3 api for communicating with keystone. The two uri options are
used to tell Tempest the url of the keystone endpoint. The ``uri`` option is
used for keystone v2 request and ``uri_v3`` is used for keystone v3. You want to
ensure that which ever version you set for ``auth_version`` has its uri option
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 1264ecc..f562850 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -2,18 +2,16 @@
Tempest Testing Project
=======================
---------
Overview
---------
+========
.. toctree::
:maxdepth: 2
overview
-------------
Field Guides
-------------
+============
Tempest contains tests of many different types, the field guides
attempt to explain these in a way that makes it easy to understand
where your test contributions should go.
@@ -26,11 +24,9 @@
field_guide/scenario
field_guide/unit_tests
-=========
-For users
-=========
+Users Guide
+===========
----------------------------
Tempest Configuration Guide
---------------------------
@@ -40,7 +36,6 @@
configuration
sampleconf
----------------------
Command Documentation
---------------------
@@ -53,11 +48,9 @@
workspace
run
-==============
-For developers
-==============
+Developers Guide
+================
------------
Development
-----------
@@ -70,7 +63,6 @@
test_removal
write_tests
--------
Plugins
-------
@@ -80,7 +72,6 @@
plugin
plugin-registry
--------
Library
-------
@@ -89,7 +80,6 @@
library
-==================
Indices and tables
==================
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index b516055..d6d90ba 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -326,6 +326,14 @@
.. _2.42: http://docs.openstack.org/developer/nova/api_microversion_history.html#maximum-in-ocata
+ * `2.47`_
+
+ .. _2.47: http://docs.openstack.org/developer/nova/api_microversion_history.html#id42
+
+ * `2.48`_
+
+ .. _2.48: http://docs.openstack.org/developer/nova/api_microversion_history.html#id43
+
* Volume
* `3.3`_
diff --git a/doc/source/write_tests.rst b/doc/source/write_tests.rst
index 2363fa6..4e3bfa2 100644
--- a/doc/source/write_tests.rst
+++ b/doc/source/write_tests.rst
@@ -178,16 +178,16 @@
+-------------------+---------------------+
| Credentials Entry | Manager Variable |
+===================+=====================+
-| primary | cls.os |
+| primary | cls.os_primary |
+-------------------+---------------------+
-| admin | cls.os_adm |
+| admin | cls.os_admin |
+-------------------+---------------------+
| alt | cls.os_alt |
+-------------------+---------------------+
| [$label, $role] | cls.os_roles_$label |
+-------------------+---------------------+
-By default cls.os is available since it is allocated in the base tempest test
+By default cls.os_primary is available since it is allocated in the base tempest test
class (located in tempest/test.py). If your TestCase inherits from a different
direct parent class (it'll still inherit from the BaseTestCase, just not
directly) be sure to check if that class overrides allocated credentials.
@@ -270,13 +270,13 @@
class TestExampleCase(test.BaseTestCase):
def test_example_create_server(self):
- self.os.servers_client.create_server(...)
+ self.os_primary.servers_client.create_server(...)
-is all you need to do. As described previously, in the above example the ``self.os``
-is created automatically because the base test class sets the ``credentials``
-attribute to allocate a primary credential set and initializes the client
-manager as ``self.os``. This same access pattern can be used for all of the
-clients in Tempest.
+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
+``credentials`` attribute to allocate a primary credential set and initializes
+the client manager as ``self.os_primary``. This same access pattern can be used
+for all of the clients in Tempest.
Credentials Objects
-------------------
@@ -293,7 +293,7 @@
class TestExampleCase(test.BaseTestCase):
def test_example_create_server(self):
- credentials = self.os.credentials
+ 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
@@ -304,7 +304,7 @@
class TestExampleCase(test.BaseTestCase):
def test_example_create_server(self):
- credentials = self.os.credentials
+ credentials = self.os_primary.credentials
username = credentials.username
user_id = credentials.user_id
password = credentials.password
diff --git a/releasenotes/notes/add-floating-ip-config-option-e5774bf77702ce9f.yaml b/releasenotes/notes/add-floating-ip-config-option-e5774bf77702ce9f.yaml
new file mode 100644
index 0000000..8221d78
--- /dev/null
+++ b/releasenotes/notes/add-floating-ip-config-option-e5774bf77702ce9f.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - A new config option in the network-feature-enabled section, floating_ips,
+ to specify whether floating ips are available in the cloud under test. By
+ default this is set to True.
diff --git a/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-endpoint-groups-3518a90bbb731d0f.yaml b/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-endpoint-groups-3518a90bbb731d0f.yaml
new file mode 100644
index 0000000..1dc33aa
--- /dev/null
+++ b/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-endpoint-groups-3518a90bbb731d0f.yaml
@@ -0,0 +1,7 @@
+---
+features:
+ - |
+ Defines the identity v3 OS-EP-FILTER EndPoint Groups API client.
+ This client manages Create, Get, Update, Check, List, and Delete
+ of EndPoint Group.
+
diff --git a/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml b/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml
new file mode 100644
index 0000000..bc7bcc8
--- /dev/null
+++ b/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml
@@ -0,0 +1,7 @@
+---
+features:
+ - |
+ A new config option 'manage_snapshot_ref' is added in the volume section,
+ to specify snapshot ref parameter for different storage backend drivers
+ when managing an existing snapshot. By default it is set to fit the LVM
+ driver.
diff --git a/releasenotes/notes/add-server-diagnostics-validation-schema-b5a3c55b45aa718a.yaml b/releasenotes/notes/add-server-diagnostics-validation-schema-b5a3c55b45aa718a.yaml
new file mode 100644
index 0000000..e0ac87c
--- /dev/null
+++ b/releasenotes/notes/add-server-diagnostics-validation-schema-b5a3c55b45aa718a.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - |
+ Add validation schema for Nova server diagnostics API
\ No newline at end of file
diff --git a/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml b/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml
new file mode 100644
index 0000000..0de1803
--- /dev/null
+++ b/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml
@@ -0,0 +1,5 @@
+---
+features:
+ - |
+ Add show host API to the volume v2 hosts_client library.
+ This feature enables the possibility to show details for a host.
diff --git a/releasenotes/notes/add-show-volume-summary-api-to-v3-volumes-client-96e7b01abdb5c9c3.yaml b/releasenotes/notes/add-show-volume-summary-api-to-v3-volumes-client-96e7b01abdb5c9c3.yaml
new file mode 100644
index 0000000..361e387
--- /dev/null
+++ b/releasenotes/notes/add-show-volume-summary-api-to-v3-volumes-client-96e7b01abdb5c9c3.yaml
@@ -0,0 +1,10 @@
+---
+features:
+ - |
+ Define v3 volumes_client for the volume service as a library interface,
+ allowing other projects to use this module as a stable library without
+ maintenance changes.
+ Add show volume summary API to v3 volumes_client library, min_microversion
+ of this API is 3.12.
+
+ * volumes_client(v3)
diff --git a/releasenotes/notes/add-volume-backup-force-delete-af0156651a0cbf7f.yaml b/releasenotes/notes/add-volume-backup-force-delete-af0156651a0cbf7f.yaml
deleted file mode 100644
index 71bbfcb..0000000
--- a/releasenotes/notes/add-volume-backup-force-delete-af0156651a0cbf7f.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
----
-features:
- - |
- As in the [doc]:
- https://developer.openstack.org/api-ref/block-storage/v3/
- #force-delete-a-backup.
-
- * Force-deletes a backup(v2)
-
diff --git a/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml b/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml
index dc4ed27..1ae251c 100644
--- a/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml
+++ b/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml
@@ -6,5 +6,5 @@
compute_images_client and Glance v1 APIs are removed in volume tests.
upgrade:
- |
- Swith to use Glance v2 APIs in volume tests, by adding the Glance v2 client
- images_client.
+ Switch to use Glance v2 APIs in volume tests, by adding the Glance v2
+ client images_client.
diff --git a/releasenotes/notes/deprecate-default-value-for-v3_endpoint_type-fb9e47c5ba1c719d.yaml b/releasenotes/notes/deprecate-default-value-for-v3_endpoint_type-fb9e47c5ba1c719d.yaml
new file mode 100644
index 0000000..c88522e
--- /dev/null
+++ b/releasenotes/notes/deprecate-default-value-for-v3_endpoint_type-fb9e47c5ba1c719d.yaml
@@ -0,0 +1,6 @@
+---
+deprecations:
+ - |
+ Deprecate default value for configuration parameter v3_endpoint_type
+ of identity section in OpenStack Pike and modify the default value to
+ publicURL in OpenStack Q release.
diff --git a/releasenotes/notes/identity-token-client-8aaef74b1d61090a.yaml b/releasenotes/notes/identity-token-client-8aaef74b1d61090a.yaml
new file mode 100644
index 0000000..d94de3e
--- /dev/null
+++ b/releasenotes/notes/identity-token-client-8aaef74b1d61090a.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Add additional API endpoints to the identity v2 client token API:
+ - list_endpoints_for_token
+ - check_token_existence
diff --git a/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml b/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml
new file mode 100644
index 0000000..9af57b1
--- /dev/null
+++ b/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml
@@ -0,0 +1,8 @@
+---
+features:
+ - |
+ Define v2.0 ``tags_client`` for the network service as a library
+ interface, allowing other projects to use this module as a stable
+ library without maintenance changes.
+
+ * tags_client(v2.0)
diff --git a/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml b/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml
new file mode 100644
index 0000000..afb6006
--- /dev/null
+++ b/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+ - |
+ When receiving nullable list as a response body, tempest.lib
+ rest_client module raised an exception without valid json
+ deserialization. A new release fixes this bug.
diff --git a/releasenotes/notes/remove-heat-tests-9efb42cac3e0b306.yaml b/releasenotes/notes/remove-heat-tests-9efb42cac3e0b306.yaml
new file mode 100644
index 0000000..4d0f3ce
--- /dev/null
+++ b/releasenotes/notes/remove-heat-tests-9efb42cac3e0b306.yaml
@@ -0,0 +1,4 @@
+---
+upgrade:
+ - The Heat API tests have been removed from tempest, they were unmaintained.
+ The future direction of api test for heat is their in-tree Gabbi tests
diff --git a/releasenotes/notes/use-cinder-v3-client-for-verify_tempest_config-2bf3d817b0070064.yaml b/releasenotes/notes/use-cinder-v3-client-for-verify_tempest_config-2bf3d817b0070064.yaml
new file mode 100644
index 0000000..1c8fa77
--- /dev/null
+++ b/releasenotes/notes/use-cinder-v3-client-for-verify_tempest_config-2bf3d817b0070064.yaml
@@ -0,0 +1,6 @@
+---
+upgrade:
+ - verify_tempest_config command starts using extension_client of
+ cinder v2 API only, because cinder v3 API is current and v2 and
+ v1 are deprecated and v3 extension API is the same as v2. Then
+ we can reuse the v2 client for v3 API also.
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index 97e3a4d..d240467 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -111,7 +111,7 @@
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'default'
+html_theme = 'openstackdocs'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
@@ -119,7 +119,9 @@
# html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
-# html_theme_path = []
+import openstackdocstheme
+
+html_theme_path = [openstackdocstheme.get_html_theme_path()]
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index adec7a7..d2be814 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -1,5 +1,5 @@
===========================
- tempest Release Notes
+ Tempest Release Notes
===========================
.. toctree::
diff --git a/requirements.txt b/requirements.txt
index 26e1f02..259a4cf 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,7 +9,7 @@
netaddr!=0.7.16,>=0.7.13 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
oslo.concurrency>=3.8.0 # Apache-2.0
-oslo.config>=3.22.0 # Apache-2.0
+oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0
oslo.log>=3.22.0 # Apache-2.0
oslo.serialization>=1.10.0 # Apache-2.0
oslo.utils>=3.20.0 # Apache-2.0
@@ -20,6 +20,6 @@
stevedore>=1.20.0 # Apache-2.0
PrettyTable<0.8,>=0.7.1 # BSD
os-testr>=0.8.0 # Apache-2.0
-urllib3>=1.15.1 # MIT
+urllib3>=1.21.1 # MIT
debtcollector>=1.2.0 # Apache-2.0
unittest2 # BSD
diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py
index 31976ec..69cbfb5 100644
--- a/tempest/api/compute/admin/test_agents.py
+++ b/tempest/api/compute/admin/test_agents.py
@@ -86,8 +86,7 @@
body = self.client.create_agent(**self.params_agent)['agent']
self.addCleanup(self.client.delete_agent, body['agent_id'])
agents = self.client.list_agents()['agents']
- self.assertGreater(len(agents), 0,
- 'Cannot get any agents.(%s)' % agents)
+ self.assertNotEmpty(agents, 'Cannot get any agents.(%s)' % agents)
self.assertIn(body['agent_id'], map(lambda x: x['agent_id'], agents))
@decorators.idempotent_id('eabadde4-3cd7-4ec4-a4b5-5a936d2d4408')
@@ -105,8 +104,7 @@
agent_id_xen = agent_xen['agent_id']
agents = (self.client.list_agents(hypervisor=agent_xen['hypervisor'])
['agents'])
- self.assertGreater(len(agents), 0,
- 'Cannot get any agents.(%s)' % agents)
+ self.assertNotEmpty(agents, 'Cannot get any agents.(%s)' % agents)
self.assertIn(agent_id_xen, map(lambda x: x['agent_id'], agents))
self.assertNotIn(body['agent_id'], map(lambda x: x['agent_id'],
agents))
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 79d03f4..902ea9a 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -59,15 +59,20 @@
msg += " for hypervisor_type %s" % CONF.compute.hypervisor_type
raise testtools.TestCase.failureException(msg)
+ def _create_test_aggregate(self, **kwargs):
+ if 'name' not in kwargs:
+ kwargs['name'] = data_utils.rand_name(self.aggregate_name_prefix)
+ aggregate = self.client.create_aggregate(**kwargs)['aggregate']
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.client.delete_aggregate, aggregate['id'])
+ self.assertEqual(kwargs['name'], aggregate['name'])
+
+ return aggregate
+
@decorators.idempotent_id('0d148aa3-d54c-4317-aa8d-42040a475e20')
def test_aggregate_create_delete(self):
# Create and delete an aggregate.
- aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- aggregate = (self.client.create_aggregate(name=aggregate_name)
- ['aggregate'])
- self.addCleanup(test_utils.call_and_ignore_notfound_exc,
- self.client.delete_aggregate, aggregate['id'])
- self.assertEqual(aggregate_name, aggregate['name'])
+ aggregate = self._create_test_aggregate()
self.assertIsNone(aggregate['availability_zone'])
self.client.delete_aggregate(aggregate['id'])
@@ -76,13 +81,8 @@
@decorators.idempotent_id('5873a6f8-671a-43ff-8838-7ce430bb6d0b')
def test_aggregate_create_delete_with_az(self):
# Create and delete an aggregate.
- aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
az_name = data_utils.rand_name(self.az_name_prefix)
- aggregate = self.client.create_aggregate(
- name=aggregate_name, availability_zone=az_name)['aggregate']
- self.addCleanup(test_utils.call_and_ignore_notfound_exc,
- self.client.delete_aggregate, aggregate['id'])
- self.assertEqual(aggregate_name, aggregate['name'])
+ aggregate = self._create_test_aggregate(availability_zone=az_name)
self.assertEqual(az_name, aggregate['availability_zone'])
self.client.delete_aggregate(aggregate['id'])
@@ -91,11 +91,7 @@
@decorators.idempotent_id('68089c38-04b1-4758-bdf0-cf0daec4defd')
def test_aggregate_create_verify_entry_in_list(self):
# Create an aggregate and ensure it is listed.
- aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- aggregate = (self.client.create_aggregate(name=aggregate_name)
- ['aggregate'])
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-
+ aggregate = self._create_test_aggregate()
aggregates = self.client.list_aggregates()['aggregates']
self.assertIn((aggregate['id'], aggregate['availability_zone']),
map(lambda x: (x['id'], x['availability_zone']),
@@ -104,11 +100,7 @@
@decorators.idempotent_id('36ec92ca-7a73-43bc-b920-7531809e8540')
def test_aggregate_create_update_metadata_get_details(self):
# Create an aggregate and ensure its details are returned.
- aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- aggregate = (self.client.create_aggregate(name=aggregate_name)
- ['aggregate'])
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-
+ aggregate = self._create_test_aggregate()
body = self.client.show_aggregate(aggregate['id'])['aggregate']
self.assertEqual(aggregate['name'], body['name'])
self.assertEqual(aggregate['availability_zone'],
@@ -129,11 +121,9 @@
# Update an aggregate and ensure properties are updated correctly
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
az_name = data_utils.rand_name(self.az_name_prefix)
- aggregate = self.client.create_aggregate(
- name=aggregate_name, availability_zone=az_name)['aggregate']
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+ aggregate = self._create_test_aggregate(
+ name=aggregate_name, availability_zone=az_name)
- self.assertEqual(aggregate_name, aggregate['name'])
self.assertEqual(az_name, aggregate['availability_zone'])
self.assertIsNotNone(aggregate['id'])
@@ -159,9 +149,7 @@
# Add a host to the given aggregate and remove.
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- aggregate = (self.client.create_aggregate(name=aggregate_name)
- ['aggregate'])
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+ aggregate = self._create_test_aggregate(name=aggregate_name)
body = (self.client.add_host(aggregate['id'], host=self.host)
['aggregate'])
@@ -182,9 +170,8 @@
# Add a host to the given aggregate and list.
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- aggregate = (self.client.create_aggregate(name=aggregate_name)
- ['aggregate'])
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+ aggregate = self._create_test_aggregate(name=aggregate_name)
+
self.client.add_host(aggregate['id'], host=self.host)
self.addCleanup(self.client.remove_host, aggregate['id'],
host=self.host)
@@ -202,9 +189,8 @@
# Add a host to the given aggregate and get details.
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- aggregate = (self.client.create_aggregate(name=aggregate_name)
- ['aggregate'])
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+ aggregate = self._create_test_aggregate(name=aggregate_name)
+
self.client.add_host(aggregate['id'], host=self.host)
self.addCleanup(self.client.remove_host, aggregate['id'],
host=self.host)
@@ -218,11 +204,9 @@
def test_aggregate_add_host_create_server_with_az(self):
# Add a host to the given aggregate and create a server.
self.useFixture(fixtures.LockFixture('availability_zone'))
- aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
az_name = data_utils.rand_name(self.az_name_prefix)
- aggregate = self.client.create_aggregate(
- name=aggregate_name, availability_zone=az_name)['aggregate']
- self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+ aggregate = self._create_test_aggregate(availability_zone=az_name)
+
self.client.add_host(aggregate['id'], host=self.host)
self.addCleanup(self.client.remove_host, aggregate['id'],
host=self.host)
diff --git a/tempest/api/compute/admin/test_auto_allocate_network.py b/tempest/api/compute/admin/test_auto_allocate_network.py
index c4db5e3..ba8a214 100644
--- a/tempest/api/compute/admin/test_auto_allocate_network.py
+++ b/tempest/api/compute/admin/test_auto_allocate_network.py
@@ -151,7 +151,7 @@
"""Tests that no networking is allocated for the server."""
# create the server with no networking
server, _ = compute.create_test_server(
- self.os, networks='none', wait_until='ACTIVE')
+ self.os_primary, networks='none', wait_until='ACTIVE')
self.addCleanup(self.delete_server, server['id'])
# get the server ips
addresses = self.servers_client.list_addresses(
@@ -176,7 +176,7 @@
# - Third request sees net1 and net2 for the tenant and fails with a
# NetworkAmbiguous 400 error.
_, servers = compute.create_test_server(
- self.os, networks='auto', wait_until='ACTIVE',
+ self.os_primary, networks='auto', wait_until='ACTIVE',
min_count=3)
server_nets = set()
for server in servers:
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index 50dec28..bbd39b6 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -29,10 +29,10 @@
def test_get_availability_zone_list(self):
# List of availability zone
availability_zone = self.client.list_availability_zones()
- self.assertGreater(len(availability_zone['availabilityZoneInfo']), 0)
+ self.assertNotEmpty(availability_zone['availabilityZoneInfo'])
@decorators.idempotent_id('ef726c58-530f-44c2-968c-c7bed22d5b8c')
def test_get_availability_zone_list_detail(self):
# List of availability zones and available services
availability_zone = self.client.list_availability_zones(detail=True)
- self.assertGreater(len(availability_zone['availabilityZoneInfo']), 0)
+ self.assertNotEmpty(availability_zone['availabilityZoneInfo'])
diff --git a/tempest/api/compute/admin/test_delete_server.py b/tempest/api/compute/admin/test_delete_server.py
index 2569161..83444b9 100644
--- a/tempest/api/compute/admin/test_delete_server.py
+++ b/tempest/api/compute/admin/test_delete_server.py
@@ -29,7 +29,7 @@
def setup_clients(cls):
super(DeleteServersAdminTestJSON, cls).setup_clients()
cls.non_admin_client = cls.servers_client
- cls.admin_client = cls.os_adm.servers_client
+ cls.admin_client = cls.os_admin.servers_client
@decorators.idempotent_id('99774678-e072-49d1-9d2a-49a59bc56063')
def test_delete_server_while_in_error_state(self):
diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index 5a38acc..2c236ec 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -50,7 +50,7 @@
flavor_access = (self.admin_flavors_client.list_flavor_access(
flavor['id'])['flavor_access'])
- self.assertEqual(len(flavor_access), 0, str(flavor_access))
+ self.assertEmpty(flavor_access)
@decorators.idempotent_id('59e622f6-bdf6-45e3-8ba8-fedad905a6b4')
def test_flavor_access_add_remove(self):
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index 4d7abb6..747cb42 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -83,8 +83,8 @@
# GET extra specs and verify the value of the key2
# is the same as before
- get_body = (self.admin_flavors_client.list_flavor_extra_specs(
- self.flavor['id'])['extra_specs'])
+ get_body = self.admin_flavors_client.list_flavor_extra_specs(
+ self.flavor['id'])['extra_specs']
self.assertEqual(get_body, {"key1": "value", "key2": "value2"})
# UNSET extra specs that were set in this test
@@ -92,6 +92,9 @@
"key1")
self.admin_flavors_client.unset_flavor_extra_spec(self.flavor['id'],
"key2")
+ get_body = self.admin_flavors_client.list_flavor_extra_specs(
+ self.flavor['id'])['extra_specs']
+ self.assertEmpty(get_body)
@decorators.idempotent_id('a99dad88-ae1c-4fba-aeb4-32f898218bd0')
def test_flavor_non_admin_get_all_keys(self):
diff --git a/tempest/api/compute/admin/test_floating_ips_bulk.py b/tempest/api/compute/admin/test_floating_ips_bulk.py
index 056b4bd..496f119 100644
--- a/tempest/api/compute/admin/test_floating_ips_bulk.py
+++ b/tempest/api/compute/admin/test_floating_ips_bulk.py
@@ -73,7 +73,7 @@
self.client.delete_floating_ips_bulk, self.ip_range)
self.assertEqual(self.ip_range, body['ip_range'])
ips_list = self.client.list_floating_ips_bulk()['floating_ip_info']
- self.assertNotEqual(0, len(ips_list))
+ self.assertNotEmpty(ips_list)
for ip in netaddr.IPNetwork(self.ip_range).iter_hosts():
self.assertIn(str(ip), map(lambda x: x['address'], ips_list))
body = (self.client.delete_floating_ips_bulk(self.ip_range)
diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py
index 8e2f6ed..0e1e7ed 100644
--- a/tempest/api/compute/admin/test_hosts.py
+++ b/tempest/api/compute/admin/test_hosts.py
@@ -36,7 +36,7 @@
hosts = self.client.list_hosts()['hosts']
host = hosts[0]
hosts = self.client.list_hosts(zone=host['zone'])['hosts']
- self.assertGreaterEqual(len(hosts), 1)
+ self.assertNotEmpty(hosts)
self.assertIn(host, hosts)
@decorators.idempotent_id('9af3c171-fbf4-4150-a624-22109733c2a6')
@@ -44,26 +44,26 @@
# If send the request with a blank zone, the request will be successful
# and it will return all the hosts list
hosts = self.client.list_hosts(zone='')['hosts']
- self.assertNotEqual(0, len(hosts))
+ self.assertNotEmpty(hosts)
@decorators.idempotent_id('c6ddbadb-c94e-4500-b12f-8ffc43843ff8')
def test_list_hosts_with_nonexistent_zone(self):
# If send the request with a nonexistent zone, the request will be
# successful and no hosts will be returned
hosts = self.client.list_hosts(zone='xxx')['hosts']
- self.assertEqual(0, len(hosts))
+ self.assertEmpty(hosts)
@decorators.idempotent_id('38adbb12-aee2-4498-8aec-329c72423aa4')
def test_show_host_detail(self):
hosts = self.client.list_hosts()['hosts']
hosts = [host for host in hosts if host['service'] == 'compute']
- self.assertGreaterEqual(len(hosts), 1)
+ self.assertNotEmpty(hosts)
for host in hosts:
hostname = host['host_name']
resources = self.client.show_host(hostname)['host']
- self.assertGreaterEqual(len(resources), 1)
+ self.assertNotEmpty(resources)
host_resource = resources[0]['resource']
self.assertIsNotNone(host_resource)
self.assertIsNotNone(host_resource['cpu'])
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index 4544267..0db802c 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -31,7 +31,7 @@
return hypers
def assertHypervisors(self, hypers):
- self.assertGreater(len(hypers), 0, "No hypervisors found: %s" % hypers)
+ self.assertNotEmpty(hypers, "No hypervisors found: %s" % hypers)
@decorators.idempotent_id('7f0ceacd-c64d-4e96-b8ee-d02943142cc5')
def test_get_hypervisor_list(self):
@@ -52,7 +52,7 @@
self.assertHypervisors(hypers)
details = self.client.show_hypervisor(hypers[0]['id'])['hypervisor']
- self.assertGreater(len(details), 0)
+ self.assertNotEmpty(details)
self.assertEqual(details['hypervisor_hostname'],
hypers[0]['hypervisor_hostname'])
@@ -65,14 +65,14 @@
hostname = hypers[0]['hypervisor_hostname']
hypervisors = (self.client.list_servers_on_hypervisor(hostname)
['hypervisors'])
- self.assertGreater(len(hypervisors), 0)
+ self.assertNotEmpty(hypervisors)
@decorators.idempotent_id('797e4f28-b6e0-454d-a548-80cc77c00816')
def test_get_hypervisor_stats(self):
# Verify the stats of the all hypervisor
stats = (self.client.show_hypervisor_statistics()
['hypervisor_statistics'])
- self.assertGreater(len(stats), 0)
+ self.assertNotEmpty(stats)
@decorators.idempotent_id('91a50d7d-1c2b-4f24-b55a-a1fe20efca70')
def test_get_hypervisor_uptime(self):
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index af87287..431e823 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -47,7 +47,7 @@
@decorators.idempotent_id('51e663d0-6b89-4817-a465-20aca0667d03')
def test_show_hypervisor_with_non_admin_user(self):
hypers = self._list_hypervisors()
- self.assertGreater(len(hypers), 0)
+ self.assertNotEmpty(hypers)
self.assertRaises(
lib_exc.Forbidden,
@@ -58,7 +58,7 @@
@decorators.idempotent_id('2a0a3938-832e-4859-95bf-1c57c236b924')
def test_show_servers_with_non_admin_user(self):
hypers = self._list_hypervisors()
- self.assertGreater(len(hypers), 0)
+ self.assertNotEmpty(hypers)
self.assertRaises(
lib_exc.Forbidden,
@@ -96,7 +96,7 @@
@decorators.idempotent_id('6c3461f9-c04c-4e2a-bebb-71dc9cb47df2')
def test_get_hypervisor_uptime_with_non_admin_user(self):
hypers = self._list_hypervisors()
- self.assertGreater(len(hypers), 0)
+ self.assertNotEmpty(hypers)
self.assertRaises(
lib_exc.Forbidden,
@@ -131,7 +131,7 @@
@decorators.idempotent_id('5b6a6c79-5dc1-4fa5-9c58-9c8085948e74')
def test_search_hypervisor_with_non_admin_user(self):
hypers = self._list_hypervisors()
- self.assertGreater(len(hypers), 0)
+ self.assertNotEmpty(hypers)
self.assertRaises(
lib_exc.Forbidden,
diff --git a/tempest/api/compute/admin/test_networks.py b/tempest/api/compute/admin/test_networks.py
index 0ea0a78..acb0d90 100644
--- a/tempest/api/compute/admin/test_networks.py
+++ b/tempest/api/compute/admin/test_networks.py
@@ -62,4 +62,4 @@
self.assertIn(configured_network, [x['label'] for x in networks])
else:
network_labels = [x['label'] for x in networks]
- self.assertGreaterEqual(len(network_labels), 1)
+ self.assertNotEmpty(network_labels)
diff --git a/tempest/api/compute/admin/test_security_group_default_rules.py b/tempest/api/compute/admin/test_security_group_default_rules.py
index 6c7cde2..f2f3b57 100644
--- a/tempest/api/compute/admin/test_security_group_default_rules.py
+++ b/tempest/api/compute/admin/test_security_group_default_rules.py
@@ -111,7 +111,7 @@
rule['id'])
rules = (self.adm_client.list_security_group_default_rules()
['security_group_default_rules'])
- self.assertNotEqual(0, len(rules))
+ self.assertNotEmpty(rules)
self.assertIn(rule, rules)
@decorators.idempotent_id('15cbb349-86b4-4f71-a048-04b7ef3f150b')
diff --git a/tempest/api/compute/admin/test_server_diagnostics.py b/tempest/api/compute/admin/test_server_diagnostics.py
new file mode 100644
index 0000000..005efdd
--- /dev/null
+++ b/tempest/api/compute/admin/test_server_diagnostics.py
@@ -0,0 +1,76 @@
+# Copyright 2017 Mirantis Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import time
+
+from tempest.api.compute import base
+from tempest.lib import decorators
+
+
+class ServerDiagnosticsTest(base.BaseV2ComputeAdminTest):
+ min_microversion = None
+ max_microversion = '2.47'
+
+ @classmethod
+ def setup_clients(cls):
+ super(ServerDiagnosticsTest, cls).setup_clients()
+ cls.client = cls.os_admin.servers_client
+
+ @decorators.idempotent_id('31ff3486-b8a0-4f56-a6c0-aab460531db3')
+ def test_get_server_diagnostics(self):
+ server_id = self.create_test_server(wait_until='ACTIVE')['id']
+ diagnostics = self.client.show_server_diagnostics(server_id)
+
+ # NOTE(snikitin): Before microversion 2.48 response data from each
+ # hypervisor (libvirt, xen, vmware) was different. None of the fields
+ # were equal. As this test is common for libvirt, xen and vmware CI
+ # jobs we can't check any field in the response because all fields are
+ # different.
+ self.assertNotEmpty(diagnostics)
+
+
+class ServerDiagnosticsV248Test(base.BaseV2ComputeAdminTest):
+ min_microversion = '2.48'
+ max_microversion = 'latest'
+
+ @classmethod
+ def setup_clients(cls):
+ super(ServerDiagnosticsV248Test, cls).setup_clients()
+ cls.client = cls.os_admin.servers_client
+
+ @decorators.idempotent_id('64d0d48c-dff1-11e6-bf01-fe55135034f3')
+ def test_get_server_diagnostics(self):
+ server_id = self.create_test_server(wait_until='ACTIVE')['id']
+ # Response status and filed types will be checked by json schema
+ self.client.show_server_diagnostics(server_id)
+
+ # NOTE(snikitin): This is a special case for Xen hypervisor. In Xen
+ # case we're getting diagnostics stats from the RRDs which are updated
+ # every 5 seconds. It means that diagnostics information may be
+ # incomplete during first 5 seconds of VM life. In such cases methods
+ # which get diagnostics stats from Xen may raise exceptions or
+ # return `NaN` values. Such behavior must be handled correctly.
+ # Response must contain all diagnostics fields (may be with `None`
+ # values) and response status must be 200. Line above checks it by
+ # json schema.
+ time.sleep(10)
+ diagnostics = self.client.show_server_diagnostics(server_id)
+
+ # NOTE(snikitin): After 10 seconds diagnostics fields must contain
+ # not None values. But we will check only "memory_details.maximum"
+ # field because only this field meets all the following conditions:
+ # 1) This field may be unset because of Xen 5 seconds timeout.
+ # 2) This field is present in responses from all three supported
+ # hypervisors (libvirt, xen, vmware).
+ self.assertIsNotNone(diagnostics['memory_details']['maximum'])
diff --git a/tempest/api/compute/admin/test_server_diagnostics_negative.py b/tempest/api/compute/admin/test_server_diagnostics_negative.py
new file mode 100644
index 0000000..d5b6674
--- /dev/null
+++ b/tempest/api/compute/admin/test_server_diagnostics_negative.py
@@ -0,0 +1,40 @@
+# Copyright 2017 Mirantis Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.compute import base
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+
+class ServerDiagnosticsNegativeTest(base.BaseV2ComputeAdminTest):
+ min_microversion = None
+ max_microversion = '2.47'
+
+ @classmethod
+ def setup_clients(cls):
+ super(ServerDiagnosticsNegativeTest, cls).setup_clients()
+ cls.client = cls.servers_client
+
+ @decorators.attr(type=['negative'])
+ @decorators.idempotent_id('e84e2234-60d2-42fa-8b30-e2d3049724ac')
+ def test_get_server_diagnostics_by_non_admin(self):
+ # Non-admin user cannot view server diagnostics according to policy
+ server_id = self.create_test_server(wait_until='ACTIVE')['id']
+ self.assertRaises(lib_exc.Forbidden,
+ self.client.show_server_diagnostics, server_id)
+
+
+class ServerDiagnosticsNegativeV248Test(ServerDiagnosticsNegativeTest):
+ min_microversion = '2.48'
+ max_microversion = 'latest'
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 98bf4bf..0521cca 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -65,7 +65,7 @@
params = {'status': 'invalid_status'}
body = self.client.list_servers(detail=True, **params)
servers = body['servers']
- self.assertEqual([], servers)
+ self.assertEmpty(servers)
@decorators.idempotent_id('51717b38-bdc1-458b-b636-1cf82d99f62f')
def test_list_servers_by_admin(self):
@@ -133,7 +133,7 @@
# self.create_test_server() here as this method creates the server
# in the "primary" (i.e non-admin) tenant.
test_server, _ = compute.create_test_server(
- self.os_adm, wait_until="ACTIVE", name=name, **network_kwargs)
+ self.os_admin, wait_until="ACTIVE", name=name, **network_kwargs)
self.addCleanup(self.client.delete_server, test_server['id'])
server = self.client.show_server(test_server['id'])['server']
self.assertEqual(server['status'], 'ACTIVE')
@@ -164,17 +164,6 @@
server = self.client.show_server(self.s1_id)['server']
self.assertEqual(server['status'], 'ACTIVE')
- @decorators.skip_because(bug="1240043")
- @decorators.idempotent_id('31ff3486-b8a0-4f56-a6c0-aab460531db3')
- def test_get_server_diagnostics_by_admin(self):
- # Retrieve server diagnostics by admin user
- diagnostic = self.client.show_server_diagnostics(self.s1_id)
- basic_attrs = ['rx_packets', 'rx_errors', 'rx_drop',
- 'tx_packets', 'tx_errors', 'tx_drop',
- 'read_req', 'write_req', 'cpu', 'memory']
- for key in basic_attrs:
- self.assertIn(key, str(diagnostic.keys()))
-
@decorators.idempotent_id('682cb127-e5bb-4f53-87ce-cb9003604442')
def test_rebuild_server_in_error_state(self):
# The server in error state should be rebuilt using the provided
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index b0f18d7..9023759 100644
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -108,14 +108,6 @@
self.client.reset_state, '999', state='error')
@decorators.attr(type=['negative'])
- @decorators.idempotent_id('e84e2234-60d2-42fa-8b30-e2d3049724ac')
- def test_get_server_diagnostics_by_non_admin(self):
- # Non-admin user can not view server diagnostics according to policy
- self.assertRaises(lib_exc.Forbidden,
- self.non_adm_client.show_server_diagnostics,
- self.s1_id)
-
- @decorators.attr(type=['negative'])
@decorators.idempotent_id('46a4e1ca-87ae-4d28-987a-1b6b136a0221')
def test_migrate_non_existent_server(self):
# migrate a non existent server
@@ -124,8 +116,8 @@
data_utils.rand_uuid())
@decorators.idempotent_id('b0b17f83-d14e-4fc4-8f31-bcc9f3cfa629')
- @testtools.skipUnless(CONF.compute_feature_enabled.resize,
- 'Resize not available.')
+ @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
+ 'Cold migration not available.')
@testtools.skipUnless(CONF.compute_feature_enabled.suspend,
'Suspend is not available.')
@decorators.attr(type=['negative'])
diff --git a/tempest/api/compute/admin/test_servers_on_multinodes.py b/tempest/api/compute/admin/test_servers_on_multinodes.py
index 6a2e5e9..858998a 100644
--- a/tempest/api/compute/admin/test_servers_on_multinodes.py
+++ b/tempest/api/compute/admin/test_servers_on_multinodes.py
@@ -25,6 +25,12 @@
class ServersOnMultiNodesTest(base.BaseV2ComputeAdminTest):
@classmethod
+ def resource_setup(cls):
+ super(ServersOnMultiNodesTest, cls).resource_setup()
+ cls.server01 = cls.create_test_server(wait_until='ACTIVE')['id']
+ cls.host01 = cls._get_host(cls.server01)
+
+ @classmethod
def skip_checks(cls):
super(ServersOnMultiNodesTest, cls).skip_checks()
@@ -32,8 +38,9 @@
raise cls.skipException(
"Less than 2 compute nodes, skipping multi-nodes test.")
- def _get_host(self, server_id):
- return self.os_admin.servers_client.show_server(
+ @classmethod
+ def _get_host(cls, server_id):
+ return cls.os_admin.servers_client.show_server(
server_id)['server']['OS-EXT-SRV-ATTR:host']
@decorators.idempotent_id('26a9d5df-6890-45f2-abc4-a659290cb130')
@@ -41,40 +48,31 @@
test.is_scheduler_filter_enabled("SameHostFilter"),
'SameHostFilter is not available.')
def test_create_servers_on_same_host(self):
- server01 = self.create_test_server(wait_until='ACTIVE')['id']
-
- hints = {'same_host': server01}
+ hints = {'same_host': self.server01}
server02 = self.create_test_server(scheduler_hints=hints,
wait_until='ACTIVE')['id']
- host01 = self._get_host(server01)
host02 = self._get_host(server02)
- self.assertEqual(host01, host02)
+ self.assertEqual(self.host01, host02)
@decorators.idempotent_id('cc7ca884-6e3e-42a3-a92f-c522fcf25e8e')
@testtools.skipUnless(
test.is_scheduler_filter_enabled("DifferentHostFilter"),
'DifferentHostFilter is not available.')
def test_create_servers_on_different_hosts(self):
- server01 = self.create_test_server(wait_until='ACTIVE')['id']
-
- hints = {'different_host': server01}
+ hints = {'different_host': self.server01}
server02 = self.create_test_server(scheduler_hints=hints,
wait_until='ACTIVE')['id']
- host01 = self._get_host(server01)
host02 = self._get_host(server02)
- self.assertNotEqual(host01, host02)
+ self.assertNotEqual(self.host01, host02)
@decorators.idempotent_id('7869cc84-d661-4e14-9f00-c18cdc89cf57')
@testtools.skipUnless(
test.is_scheduler_filter_enabled("DifferentHostFilter"),
'DifferentHostFilter is not available.')
def test_create_servers_on_different_hosts_with_list_of_servers(self):
- server01 = self.create_test_server(wait_until='ACTIVE')['id']
-
# This scheduler-hint supports list of servers also.
- hints = {'different_host': [server01]}
+ hints = {'different_host': [self.server01]}
server02 = self.create_test_server(scheduler_hints=hints,
wait_until='ACTIVE')['id']
- host01 = self._get_host(server01)
host02 = self._get_host(server02)
- self.assertNotEqual(host01, host02)
+ self.assertNotEqual(self.host01, host02)
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index 1dfc13e..f3eb597 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -29,13 +29,13 @@
@decorators.idempotent_id('5be41ef4-53d1-41cc-8839-5c2a48a1b283')
def test_list_services(self):
services = self.client.list_services()['services']
- self.assertNotEqual(0, len(services))
+ self.assertNotEmpty(services)
@decorators.idempotent_id('f345b1ec-bc6e-4c38-a527-3ca2bc00bef5')
def test_get_service_by_service_binary_name(self):
binary_name = 'nova-compute'
services = self.client.list_services(binary=binary_name)['services']
- self.assertNotEqual(0, len(services))
+ self.assertNotEmpty(services)
for service in services:
self.assertEqual(binary_name, service['binary'])
diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py
index 38bb5ec..201670a 100644
--- a/tempest/api/compute/admin/test_services_negative.py
+++ b/tempest/api/compute/admin/test_services_negative.py
@@ -48,7 +48,7 @@
host_name = services[0]['host']
services = self.client.list_services(host=host_name,
binary='xxx')['services']
- self.assertEqual(0, len(services))
+ self.assertEmpty(services)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('64e7e7fb-69e8-4cb6-a71d-8d5eb0c98655')
@@ -57,4 +57,4 @@
binary_name = services[0]['binary']
services = self.client.list_services(host='xxx',
binary=binary_name)['services']
- self.assertEqual(0, len(services))
+ self.assertEmpty(services)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index a5ee716..429ded5 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -22,6 +22,7 @@
from tempest.common import waiters
from tempest import config
from tempest import exceptions
+from tempest.lib.common import api_version_request
from tempest.lib.common import api_version_utils
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
@@ -123,10 +124,13 @@
@classmethod
def resource_cleanup(cls):
- cls.clear_images()
+ cls.clear_resources('images', cls.images,
+ cls.compute_images_client.delete_image)
cls.clear_servers()
- cls.clear_security_groups()
- cls.clear_server_groups()
+ cls.clear_resources('security groups', cls.security_groups,
+ cls.security_groups_client.delete_security_group)
+ cls.clear_resources('server groups', cls.server_groups,
+ cls.server_groups_client.delete_server_group)
cls.clear_volumes()
super(BaseV2ComputeTest, cls).resource_cleanup()
@@ -172,42 +176,19 @@
raise
@classmethod
- def clear_images(cls):
- LOG.debug('Clearing images: %s', ','.join(cls.images))
- for image_id in cls.images:
+ def clear_resources(cls, resource_name, resources, resource_del_func):
+ LOG.debug('Clearing %s: %s', resource_name,
+ ','.join(map(str, resources)))
+ for res_id in resources:
try:
test_utils.call_and_ignore_notfound_exc(
- cls.compute_images_client.delete_image, image_id)
- except Exception:
- LOG.exception('Exception raised deleting image %s', image_id)
-
- @classmethod
- def clear_security_groups(cls):
- LOG.debug('Clearing security groups: %s', ','.join(
- str(sg['id']) for sg in cls.security_groups))
- for sg in cls.security_groups:
- try:
- test_utils.call_and_ignore_notfound_exc(
- cls.security_groups_client.delete_security_group, sg['id'])
+ resource_del_func, res_id)
except Exception as exc:
- LOG.info('Exception raised deleting security group %s',
- sg['id'])
+ LOG.exception('Exception raised deleting %s: %s',
+ resource_name, res_id)
LOG.exception(exc)
@classmethod
- def clear_server_groups(cls):
- LOG.debug('Clearing server groups: %s', ','.join(cls.server_groups))
- for server_group_id in cls.server_groups:
- try:
- test_utils.call_and_ignore_notfound_exc(
- cls.server_groups_client.delete_server_group,
- server_group_id
- )
- except Exception:
- LOG.exception('Exception raised deleting server-group %s',
- server_group_id)
-
- @classmethod
def create_test_server(cls, validatable=False, volume_backed=False,
**kwargs):
"""Wrapper utility that returns a test server.
@@ -222,9 +203,18 @@
"""
if 'name' not in kwargs:
kwargs['name'] = data_utils.rand_name(cls.__name__ + "-server")
+
+ request_version = api_version_request.APIVersionRequest(
+ cls.request_microversion)
+ v2_37_version = api_version_request.APIVersionRequest('2.37')
+
+ # NOTE(snikitin): since microversion v2.37 'networks' field is required
+ if request_version >= v2_37_version and 'networks' not in kwargs:
+ kwargs['networks'] = 'none'
+
tenant_network = cls.get_tenant_network()
body, servers = compute.create_test_server(
- cls.os,
+ cls.os_primary,
validatable,
validation_resources=cls.validation_resources,
tenant_network=tenant_network,
@@ -243,7 +233,7 @@
description = data_utils.rand_name('description')
body = cls.security_groups_client.create_security_group(
name=name, description=description)['security_group']
- cls.security_groups.append(body)
+ cls.security_groups.append(body['id'])
return body
@@ -370,7 +360,7 @@
@classmethod
def delete_volume(cls, volume_id):
"""Deletes the given volume and waits for it to be gone."""
- cls._delete_volume(cls.volumes_extensions_client, volume_id)
+ cls._delete_volume(cls.volumes_client, volume_id)
@classmethod
def get_server_ip(cls, server):
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index 2769245..faa7b5d 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -30,6 +30,12 @@
floating_ip = None
@classmethod
+ def skip_checks(cls):
+ super(FloatingIPsTestJSON, cls).skip_checks()
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
+
+ @classmethod
def setup_clients(cls):
super(FloatingIPsTestJSON, cls).setup_clients()
cls.client = cls.floating_ips_client
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
index 96983b0..483bd95 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
@@ -28,6 +28,12 @@
class FloatingIPsNegativeTestJSON(base.BaseFloatingIPsTest):
@classmethod
+ def skip_checks(cls):
+ super(FloatingIPsNegativeTestJSON, cls).skip_checks()
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
+
+ @classmethod
def setup_clients(cls):
super(FloatingIPsNegativeTestJSON, cls).setup_clients()
cls.client = cls.floating_ips_client
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index 71f5f13..913b992 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -24,6 +24,12 @@
class FloatingIPDetailsTestJSON(base.BaseV2ComputeTest):
@classmethod
+ def skip_checks(cls):
+ super(FloatingIPDetailsTestJSON, cls).skip_checks()
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
+
+ @classmethod
def setup_clients(cls):
super(FloatingIPDetailsTestJSON, cls).setup_clients()
cls.client = cls.floating_ips_client
@@ -52,7 +58,7 @@
# Positive test:Should return the list of floating IPs
body = self.client.list_floating_ips()['floating_ips']
floating_ips = body
- self.assertNotEqual(0, len(floating_ips),
+ self.assertNotEmpty(floating_ips,
"Expected floating IPs. Got zero.")
for i in range(3):
self.assertIn(self.floating_ip[i], floating_ips)
@@ -84,5 +90,5 @@
def test_list_floating_ip_pools(self):
# Positive test:Should return the list of floating IP Pools
floating_ip_pools = self.pools_client.list_floating_ip_pools()
- self.assertNotEqual(0, len(floating_ip_pools['floating_ip_pools']),
+ self.assertNotEmpty(floating_ip_pools['floating_ip_pools'],
"Expected floating IP Pools. Got zero.")
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
index 9d70bf7..b5bbb8c 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
@@ -26,6 +26,12 @@
class FloatingIPDetailsNegativeTestJSON(base.BaseV2ComputeTest):
@classmethod
+ def skip_checks(cls):
+ super(FloatingIPDetailsNegativeTestJSON, cls).skip_checks()
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
+
+ @classmethod
def setup_clients(cls):
super(FloatingIPDetailsNegativeTestJSON, cls).setup_clients()
cls.client = cls.floating_ips_client
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index db24174..5987d39 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -24,6 +24,11 @@
class ImagesOneServerTestJSON(base.BaseV2ComputeTest):
@classmethod
+ def resource_setup(cls):
+ super(ImagesOneServerTestJSON, cls).resource_setup()
+ cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id']
+
+ @classmethod
def skip_checks(cls):
super(ImagesOneServerTestJSON, cls).skip_checks()
if not CONF.service_available.glance:
@@ -46,12 +51,10 @@
@decorators.idempotent_id('3731d080-d4c5-4872-b41a-64d0d0021314')
def test_create_delete_image(self):
- server_id = self.create_test_server(wait_until='ACTIVE')['id']
-
# Create a new image
name = data_utils.rand_name('image')
meta = {'image_type': 'test'}
- image = self.create_image_from_server(server_id, name=name,
+ image = self.create_image_from_server(self.server_id, name=name,
metadata=meta,
wait_until='ACTIVE')
@@ -76,15 +79,13 @@
@decorators.idempotent_id('3b7c6fe4-dfe7-477c-9243-b06359db51e6')
def test_create_image_specify_multibyte_character_image_name(self):
- server_id = self.create_test_server(wait_until='ACTIVE')['id']
-
# prefix character is:
- # http://www.fileformat.info/info/unicode/char/1F4A9/index.htm
+ # http://unicode.org/cldr/utility/character.jsp?a=20A1
- # We use a string with 3 byte utf-8 character due to bug
- # #1370954 in glance which will 500 if mysql is used as the
- # backend and it attempts to store a 4 byte utf-8 character
+ # We use a string with 3 byte utf-8 character due to nova/glance which
+ # will return 400(Bad Request) if we attempt to send a name which has
+ # 4 byte utf-8 character.
utf8_name = data_utils.rand_name(b'\xe2\x82\xa1'.decode('utf-8'))
- body = self.client.create_image(server_id, name=utf8_name)
+ body = self.client.create_image(self.server_id, name=utf8_name)
image_id = data_utils.parse_image_id(body.response['location'])
self.addCleanup(self.client.delete_image, image_id)
diff --git a/tempest/api/compute/limits/test_absolute_limits.py b/tempest/api/compute/limits/test_absolute_limits.py
index 58352bd..0585fec 100644
--- a/tempest/api/compute/limits/test_absolute_limits.py
+++ b/tempest/api/compute/limits/test_absolute_limits.py
@@ -42,6 +42,6 @@
# check whether all expected elements exist
missing_elements =\
[ele for ele in expected_elements if ele not in absolute_limits]
- self.assertEqual(0, len(missing_elements),
+ self.assertEmpty(missing_elements,
"Failed to find element %s in absolute limits list"
% ', '.join(ele for ele in missing_elements))
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 3378ef8..b568f7d 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -186,4 +186,4 @@
rules = (self.security_groups_client.show_security_group(sg1_id)
['security_group']['rules'])
# The group1 has no rules because group2 has deleted
- self.assertEqual(0, len(rules))
+ self.assertEmpty(rules)
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index e50b29a..65d5042 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -49,7 +49,6 @@
cls.subnets_client = cls.os_primary.subnets_client
cls.ports_client = cls.os_primary.ports_client
- # TODO(mriedem): move this into a common waiters utility module
def wait_for_port_detach(self, port_id):
"""Waits for the port's device_id to be unset.
@@ -264,7 +263,8 @@
# create two servers
_, servers = compute.create_test_server(
- self.os, tenant_network=network, wait_until='ACTIVE', min_count=2)
+ self.os_primary, tenant_network=network,
+ wait_until='ACTIVE', min_count=2)
# add our cleanups for the servers since we bypassed the base class
for server in servers:
self.addCleanup(self.delete_server, server['id'])
diff --git a/tempest/api/compute/servers/test_availability_zone.py b/tempest/api/compute/servers/test_availability_zone.py
index 82e74ed..36828d6 100644
--- a/tempest/api/compute/servers/test_availability_zone.py
+++ b/tempest/api/compute/servers/test_availability_zone.py
@@ -29,4 +29,4 @@
def test_get_availability_zone_list_with_non_admin_user(self):
# List of availability zone with non-administrator user
availability_zone = self.client.list_availability_zones()
- self.assertGreater(len(availability_zone['availabilityZoneInfo']), 0)
+ self.assertNotEmpty(availability_zone['availabilityZoneInfo'])
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 1ad153a..921b7da 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -142,7 +142,7 @@
# Verify only the expected number of servers are returned
params = {'limit': 0}
servers = self.client.list_servers(**params)
- self.assertEqual(0, len(servers['servers']))
+ self.assertEmpty(servers['servers'])
@decorators.idempotent_id('37791bbd-90c0-4de0-831e-5f38cba9c6b3')
def test_list_servers_filter_by_exceed_limit(self):
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index d89f44c..6c9b287 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -34,13 +34,12 @@
# by the test methods in this class. These
# servers are cleaned up automatically in the
# tearDownClass method of the super-class.
- cls.deleted_fixtures = []
- cls.create_test_server(wait_until='ACTIVE', min_count=2)
+ body = cls.create_test_server(wait_until='ACTIVE', min_count=3)
- srv = cls.create_test_server(wait_until='ACTIVE')
- cls.client.delete_server(srv['id'])
- waiters.wait_for_server_termination(cls.client, srv['id'])
- cls.deleted_fixtures.append(srv)
+ # delete one of the created servers
+ cls.deleted_id = body['server']['id']
+ cls.client.delete_server(cls.deleted_id)
+ waiters.wait_for_server_termination(cls.client, cls.deleted_id)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('24a26f1a-1ddc-4eea-b0d7-a90cc874ad8f')
@@ -49,10 +48,9 @@
# List servers and verify server not returned
body = self.client.list_servers()
servers = body['servers']
- deleted_ids = [s['id'] for s in self.deleted_fixtures]
actual = [srv for srv in servers
- if srv['id'] in deleted_ids]
- self.assertEqual([], actual)
+ if srv['id'] == self.deleted_id]
+ self.assertEmpty(actual)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('ff01387d-c7ad-47b4-ae9e-64fa214638fe')
@@ -60,7 +58,7 @@
# Listing servers for a non existing image returns empty list
body = self.client.list_servers(image='non_existing_image')
servers = body['servers']
- self.assertEqual([], servers)
+ self.assertEmpty(servers)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('5913660b-223b-44d4-a651-a0fbfd44ca75')
@@ -68,7 +66,7 @@
# Listing servers by non existing flavor returns empty list
body = self.client.list_servers(flavor='non_existing_flavor')
servers = body['servers']
- self.assertEqual([], servers)
+ self.assertEmpty(servers)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('e2c77c4a-000a-4af3-a0bd-629a328bde7c')
@@ -76,7 +74,7 @@
# Listing servers for a non existent server name returns empty list
body = self.client.list_servers(name='non_existing_server_name')
servers = body['servers']
- self.assertEqual([], servers)
+ self.assertEmpty(servers)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('fcdf192d-0f74-4d89-911f-1ec002b822c4')
@@ -84,13 +82,7 @@
# Return an empty list when invalid status is specified
body = self.client.list_servers(status='non_existing_status')
servers = body['servers']
- self.assertEqual([], servers)
-
- @decorators.idempotent_id('12c80a9f-2dec-480e-882b-98ba15757659')
- def test_list_servers_by_limits(self):
- # List servers by specifying limits
- body = self.client.list_servers(limit=1)
- self.assertEqual(1, len([x for x in body['servers'] if 'id' in x]))
+ self.assertEmpty(servers)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d47c17fb-eebd-4287-8e95-f20a7e627b18')
@@ -130,15 +122,14 @@
# Return an empty list when a date in the future is passed
changes_since = {'changes-since': '2051-01-01T12:34:00Z'}
body = self.client.list_servers(**changes_since)
- self.assertEqual(0, len(body['servers']))
+ self.assertEmpty(body['servers'])
@decorators.attr(type=['negative'])
@decorators.idempotent_id('93055106-2d34-46fe-af68-d9ddbf7ee570')
def test_list_servers_detail_server_is_deleted(self):
# Server details are not listed for a deleted server
- deleted_ids = [s['id'] for s in self.deleted_fixtures]
body = self.client.list_servers(detail=True)
servers = body['servers']
actual = [srv for srv in servers
- if srv['id'] in deleted_ids]
- self.assertEqual([], actual)
+ if srv['id'] == self.deleted_id]
+ self.assertEmpty(actual)
diff --git a/tempest/api/compute/servers/test_multiple_create.py b/tempest/api/compute/servers/test_multiple_create.py
index 7cbb513..059454d 100644
--- a/tempest/api/compute/servers/test_multiple_create.py
+++ b/tempest/api/compute/servers/test_multiple_create.py
@@ -24,7 +24,7 @@
def test_multiple_create(self):
tenant_network = self.get_tenant_network()
body, servers = compute.create_test_server(
- self.os,
+ self.os_primary,
wait_until='ACTIVE',
min_count=2,
tenant_network=tenant_network)
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 8808510..6f072b2 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -168,6 +168,9 @@
@decorators.idempotent_id('aaa6cdf3-55a7-461a-add9-1c8596b9a07c')
def test_rebuild_server(self):
+ # Get the IPs the server has before rebuilding it
+ original_addresses = (self.client.show_server(self.server_id)['server']
+ ['addresses'])
# The server should be rebuilt using the provided image and data
meta = {'rebuild': 'server'}
new_name = data_utils.rand_name(self.__class__.__name__ + '-server')
@@ -197,6 +200,7 @@
rebuilt_image_id = server['image']['id']
self.assertTrue(self.image_ref_alt.endswith(rebuilt_image_id))
self.assertEqual(new_name, server['name'])
+ self.assertEqual(original_addresses, server['addresses'])
if CONF.validation.run_validation:
# Authentication is attempted in the following order of priority:
@@ -527,6 +531,10 @@
self.client.unshelve_server(self.server_id)
waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE')
+ images = self.compute_images_client.list_images(**params)['images']
+ msg = ('After unshelve, shelved image is not deleted.')
+ self.assertEmpty(images, msg)
+
@decorators.idempotent_id('af8eafd4-38a7-4a4b-bdbc-75145a580560')
def test_stop_start_server(self):
self.client.stop_server(self.server_id)
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index 92b1ff1..022ceba 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -48,9 +48,9 @@
# We do not know the exact network configuration, but an instance
# should at least have a single public or private address
- self.assertGreaterEqual(len(addresses), 1)
+ self.assertNotEmpty(addresses)
for network_addresses in addresses.values():
- self.assertGreaterEqual(len(network_addresses), 1)
+ self.assertNotEmpty(network_addresses)
for address in network_addresses:
self.assertTrue(address['addr'])
self.assertTrue(address['version'])
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index 8760af6..b0ef3bc 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -42,81 +42,52 @@
def resource_setup(cls):
super(ServerRescueTestJSON, cls).resource_setup()
- # Floating IP creation
- body = cls.floating_ips_client.create_floating_ip(
- pool=CONF.network.floating_network_name)['floating_ip']
- cls.floating_ip_id = str(body['id']).strip()
- cls.floating_ip = str(body['ip']).strip()
-
- # Security group creation
- cls.sg_name = data_utils.rand_name('sg')
- sg_desc = data_utils.rand_name('sg-desc')
- cls.sg = cls.security_groups_client.create_security_group(
- name=cls.sg_name, description=sg_desc)['security_group']
- cls.sg_id = cls.sg['id']
-
- cls.password = data_utils.rand_password()
- # Server for positive tests
- server = cls.create_test_server(adminPass=cls.password,
+ password = data_utils.rand_password()
+ server = cls.create_test_server(adminPass=password,
wait_until='ACTIVE')
- cls.server_id = server['id']
-
- @classmethod
- def resource_cleanup(cls):
- # Deleting the floating IP which is created in this method
- cls.floating_ips_client.delete_floating_ip(cls.floating_ip_id)
- cls.sg = cls.security_groups_client.delete_security_group(
- cls.sg_id)
- super(ServerRescueTestJSON, cls).resource_cleanup()
-
- def _unrescue(self, server_id):
- self.servers_client.unrescue_server(server_id)
- waiters.wait_for_server_status(self.servers_client, server_id,
- 'ACTIVE')
+ cls.servers_client.rescue_server(server['id'], adminPass=password)
+ waiters.wait_for_server_status(cls.servers_client, server['id'],
+ 'RESCUE')
+ cls.rescued_server_id = server['id']
@decorators.idempotent_id('fd032140-714c-42e4-a8fd-adcd8df06be6')
def test_rescue_unrescue_instance(self):
- self.servers_client.rescue_server(
- self.server_id, adminPass=self.password)
- waiters.wait_for_server_status(self.servers_client, self.server_id,
+ password = data_utils.rand_password()
+ server = self.create_test_server(adminPass=password,
+ wait_until='ACTIVE')
+ self.servers_client.rescue_server(server['id'], adminPass=password)
+ waiters.wait_for_server_status(self.servers_client, server['id'],
'RESCUE')
- self.servers_client.unrescue_server(self.server_id)
- waiters.wait_for_server_status(self.servers_client, self.server_id,
+ self.servers_client.unrescue_server(server['id'])
+ waiters.wait_for_server_status(self.servers_client, server['id'],
'ACTIVE')
@decorators.idempotent_id('4842e0cf-e87d-4d9d-b61f-f4791da3cacc')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
+ @testtools.skipUnless(CONF.network_feature_enabled.floating_ips,
+ "Floating ips are not available")
def test_rescued_vm_associate_dissociate_floating_ip(self):
- # Rescue the server
- self.servers_client.rescue_server(
- self.server_id, adminPass=self.password)
- waiters.wait_for_server_status(self.servers_client, self.server_id,
- 'RESCUE')
- self.addCleanup(self._unrescue, self.server_id)
-
# Association of floating IP to a rescued vm
- client = self.floating_ips_client
- client.associate_floating_ip_to_server(self.floating_ip,
- self.server_id)
+ floating_ip_body = self.floating_ips_client.create_floating_ip(
+ pool=CONF.network.floating_network_name)['floating_ip']
+ self.addCleanup(self.floating_ips_client.delete_floating_ip,
+ floating_ip_body['id'])
+
+ self.floating_ips_client.associate_floating_ip_to_server(
+ str(floating_ip_body['ip']).strip(), self.rescued_server_id)
# Disassociation of floating IP that was associated in this method
- client.disassociate_floating_ip_from_server(self.floating_ip,
- self.server_id)
+ self.floating_ips_client.disassociate_floating_ip_from_server(
+ str(floating_ip_body['ip']).strip(), self.rescued_server_id)
@decorators.idempotent_id('affca41f-7195-492d-8065-e09eee245404')
def test_rescued_vm_add_remove_security_group(self):
- # Rescue the server
- self.servers_client.rescue_server(
- self.server_id, adminPass=self.password)
- waiters.wait_for_server_status(self.servers_client, self.server_id,
- 'RESCUE')
- self.addCleanup(self._unrescue, self.server_id)
-
# Add Security group
- self.servers_client.add_security_group(self.server_id,
- name=self.sg_name)
+ sg = self.create_security_group()
+ self.servers_client.add_security_group(self.rescued_server_id,
+ name=sg['name'])
# Delete Security group
- self.servers_client.remove_security_group(self.server_id,
- name=self.sg_name)
+ self.servers_client.remove_security_group(self.rescued_server_id,
+ name=sg['name'])
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index 11f236b..7fd1dd1 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -102,14 +102,10 @@
prefix_name = u'\u00CD\u00F1st\u00E1\u00F1c\u00E9'
self._update_server_name(server['id'], 'ACTIVE', prefix_name)
- @decorators.idempotent_id('6ac19cb1-27a3-40ec-b350-810bdc04c08e')
- def test_update_server_name_in_stop_state(self):
- # The server name should be changed to the provided value
- server = self.create_test_server(wait_until='ACTIVE')
+ # stop server and check server name update again
self.client.stop_server(server['id'])
waiters.wait_for_server_status(self.client, server['id'], 'SHUTOFF')
# Update instance name with non-ASCII characters
- prefix_name = u'\u00CD\u00F1st\u00E1\u00F1c\u00E9'
updated_server = self._update_server_name(server['id'],
'SHUTOFF',
prefix_name)
@@ -138,3 +134,14 @@
waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE')
server = self.client.show_server(server['id'])['server']
self.assertEqual('2001:2001::3', server['accessIPv6'])
+
+
+class ServerShowV247Test(base.BaseV2ComputeTest):
+ min_microversion = '2.47'
+ max_microversion = 'latest'
+
+ @decorators.idempotent_id('88b0bdb2-494c-11e7-a919-92ebcb67fe33')
+ def test_show_server(self):
+ server = self.create_test_server()
+ # All fields will be checked by API schema
+ self.servers_client.show_server(server['id'])
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index a480a15..764767b 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -54,6 +54,11 @@
server = cls.create_test_server(wait_until='ACTIVE')
cls.server_id = server['id']
+ server = cls.create_test_server()
+ cls.client.delete_server(server['id'])
+ waiters.wait_for_server_termination(cls.client, server['id'])
+ cls.deleted_server_id = server['id']
+
@decorators.attr(type=['negative'])
@decorators.idempotent_id('dbbfd247-c40c-449e-8f6c-d2aa7c7da7cf')
def test_server_name_blank(self):
@@ -170,25 +175,17 @@
@decorators.idempotent_id('98fa0458-1485-440f-873b-fe7f0d714930')
def test_rebuild_deleted_server(self):
# Rebuild a deleted server
- server = self.create_test_server()
- self.client.delete_server(server['id'])
- waiters.wait_for_server_termination(self.client, server['id'])
-
self.assertRaises(lib_exc.NotFound,
self.client.rebuild_server,
- server['id'], self.image_ref)
+ self.deleted_server_id, self.image_ref)
@decorators.related_bug('1660878', status_code=409)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('581a397d-5eab-486f-9cf9-1014bbd4c984')
def test_reboot_deleted_server(self):
# Reboot a deleted server
- server = self.create_test_server()
- self.client.delete_server(server['id'])
- waiters.wait_for_server_termination(self.client, server['id'])
-
self.assertRaises(lib_exc.NotFound, self.client.reboot_server,
- server['id'], type='SOFT')
+ self.deleted_server_id, type='SOFT')
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d86141a7-906e-4731-b187-d64a2ea61422')
@@ -551,7 +548,7 @@
def setUp(self):
super(ServersNegativeTestMultiTenantJSON, self).setUp()
try:
- waiters.wait_for_server_status(self.client, self.server_id,
+ waiters.wait_for_server_status(self.servers_client, self.server_id,
'ACTIVE')
except Exception:
self.__class__.server_id = self.rebuild_server(self.server_id)
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index 610121b..6b625d9 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -58,7 +58,7 @@
output = self.client.list_virtual_interfaces(self.server['id'])
self.assertIsNotNone(output)
virt_ifaces = output
- self.assertNotEqual(0, len(virt_ifaces['virtual_interfaces']),
+ self.assertNotEmpty(virt_ifaces['virtual_interfaces'],
'Expected virtual interfaces, got 0 '
'interfaces.')
for virt_iface in virt_ifaces['virtual_interfaces']:
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index 3b41775..42e13bd 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -35,16 +35,18 @@
raise self.skipException('There are not any extensions configured')
extensions = self.extensions_client.list_extensions()['extensions']
ext = CONF.compute_feature_enabled.api_extensions[0]
- if ext == 'all':
- self.assertIn('Hosts', map(lambda x: x['name'], extensions))
- elif ext:
- self.assertIn(ext, map(lambda x: x['alias'], extensions))
- else:
- raise self.skipException('There are not any extensions configured')
+
# Log extensions list
extension_list = map(lambda x: x['alias'], extensions)
LOG.debug("Nova extensions: %s", ','.join(extension_list))
+ if ext == 'all':
+ self.assertIn('Hosts', map(lambda x: x['name'], extensions))
+ elif ext:
+ self.assertIn(ext, extension_list)
+ else:
+ raise self.skipException('There are not any extensions configured')
+
@decorators.idempotent_id('05762f39-bdfa-4cdb-9b46-b78f8e78e2fd')
@test.requires_ext(extension='os-consoles', service='compute')
def test_get_extension(self):
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index b0a6622..ed5f9a6 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -52,6 +52,7 @@
validatable=True,
wait_until='ACTIVE',
adminPass=self.image_ssh_password)
+ self.addCleanup(self.delete_server, server['id'])
# Record addresses so that we can ssh later
server['addresses'] = self.servers_client.list_addresses(
server['id'])['addresses']
@@ -113,51 +114,35 @@
def test_list_get_volume_attachments(self):
# List volume attachment of the server
server = self._create_server()
- volume = self.create_volume()
- attachment = self.attach_volume(server, volume,
- device=('/dev/%s' % self.device))
+ volume_1st = self.create_volume()
+ attachment_1st = self.attach_volume(server, volume_1st,
+ device=('/dev/%s' % self.device))
body = self.servers_client.list_volume_attachments(
server['id'])['volumeAttachments']
self.assertEqual(1, len(body))
- self.assertIn(attachment, body)
+ self.assertIn(attachment_1st, body)
# Get volume attachment of the server
body = self.servers_client.show_volume_attachment(
server['id'],
- attachment['id'])['volumeAttachment']
+ attachment_1st['id'])['volumeAttachment']
self.assertEqual(server['id'], body['serverId'])
- self.assertEqual(volume['id'], body['volumeId'])
- self.assertEqual(attachment['id'], body['id'])
+ self.assertEqual(volume_1st['id'], body['volumeId'])
+ self.assertEqual(attachment_1st['id'], body['id'])
- @decorators.idempotent_id('757d488b-a951-4bc7-b3cd-f417028da08a')
- def test_list_get_two_volume_attachments(self):
- # NOTE: This test is using the volume device auto-assignment
- # without specifying the device ("/dev/sdb", etc). The feature
- # is supported since Nova Liberty release or later. So this should
- # be skipped on older clouds.
- server = self._create_server()
- volume_1st = self.create_volume()
+ # attach one more volume to server
volume_2nd = self.create_volume()
- attachment_1st = self.attach_volume(server, volume_1st)
attachment_2nd = self.attach_volume(server, volume_2nd)
-
body = self.servers_client.list_volume_attachments(
server['id'])['volumeAttachments']
self.assertEqual(2, len(body))
- body = self.servers_client.show_volume_attachment(
- server['id'],
- attachment_1st['id'])['volumeAttachment']
- self.assertEqual(server['id'], body['serverId'])
- self.assertEqual(attachment_1st['volumeId'], body['volumeId'])
- self.assertEqual(attachment_1st['id'], body['id'])
-
- body = self.servers_client.show_volume_attachment(
- server['id'],
- attachment_2nd['id'])['volumeAttachment']
- self.assertEqual(server['id'], body['serverId'])
- self.assertEqual(attachment_2nd['volumeId'], body['volumeId'])
- self.assertEqual(attachment_2nd['id'], body['id'])
+ for attachment in [attachment_1st, attachment_2nd]:
+ body = self.servers_client.show_volume_attachment(
+ server['id'], attachment['id'])['volumeAttachment']
+ self.assertEqual(server['id'], body['serverId'])
+ self.assertEqual(attachment['volumeId'], body['volumeId'])
+ self.assertEqual(attachment['id'], body['id'])
class AttachVolumeShelveTestJSON(AttachVolumeTestJSON):
diff --git a/tempest/api/compute/volumes/test_volume_snapshots.py b/tempest/api/compute/volumes/test_volume_snapshots.py
index 2f3a06e..0f436eb 100644
--- a/tempest/api/compute/volumes/test_volume_snapshots.py
+++ b/tempest/api/compute/volumes/test_volume_snapshots.py
@@ -27,6 +27,11 @@
class VolumesSnapshotsTestJSON(base.BaseV2ComputeTest):
+ # These tests will fail with a 404 starting from microversion 2.36. For
+ # more information, see:
+ # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated
+ max_microversion = '2.35'
+
@classmethod
def skip_checks(cls):
super(VolumesSnapshotsTestJSON, cls).skip_checks()
diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py
index 43c837a..01cfb5f 100644
--- a/tempest/api/compute/volumes/test_volumes_get.py
+++ b/tempest/api/compute/volumes/test_volumes_get.py
@@ -16,7 +16,6 @@
from testtools import matchers
from tempest.api.compute import base
-from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
@@ -27,6 +26,11 @@
class VolumesGetTestJSON(base.BaseV2ComputeTest):
+ # These tests will fail with a 404 starting from microversion 2.36. For
+ # more information, see:
+ # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated
+ max_microversion = '2.35'
+
@classmethod
def skip_checks(cls):
super(VolumesGetTestJSON, cls).skip_checks()
@@ -37,7 +41,7 @@
@classmethod
def setup_clients(cls):
super(VolumesGetTestJSON, cls).setup_clients()
- cls.client = cls.volumes_extensions_client
+ cls.volumes_client = cls.volumes_extensions_client
@decorators.idempotent_id('f10f25eb-9775-4d9d-9cbe-1cf54dae9d5f')
def test_volume_create_get_delete(self):
@@ -45,22 +49,19 @@
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
metadata = {'Type': 'work'}
# Create volume
- volume = self.client.create_volume(size=CONF.volume.volume_size,
- display_name=v_name,
- metadata=metadata)['volume']
+ volume = self.create_volume(size=CONF.volume.volume_size,
+ display_name=v_name,
+ metadata=metadata)
self.assertIn('id', volume)
- self.addCleanup(self.delete_volume, volume['id'])
self.assertIn('displayName', volume)
self.assertEqual(volume['displayName'], v_name,
"The created volume name is not equal "
"to the requested name")
self.assertIsNotNone(volume['id'],
"Field volume id is empty or not found.")
- # Wait for Volume status to become ACTIVE
- waiters.wait_for_volume_resource_status(self.client, volume['id'],
- 'available')
# GET Volume
- fetched_volume = self.client.show_volume(volume['id'])['volume']
+ fetched_volume = self.volumes_client.show_volume(
+ volume['id'])['volume']
# Verification of details of fetched Volume
self.assertEqual(v_name,
fetched_volume['displayName'],
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index 0d8214f..b2aebe7 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -27,6 +27,11 @@
# If you are running a Devstack environment, ensure that the
# VOLUME_BACKING_FILE_SIZE is at least 4G in your localrc
+ # These tests will fail with a 404 starting from microversion 2.36. For
+ # more information, see:
+ # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated
+ max_microversion = '2.35'
+
@classmethod
def skip_checks(cls):
super(VolumesTestJSON, cls).skip_checks()
diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py
index 80db1be..87f7d8a 100644
--- a/tempest/api/compute/volumes/test_volumes_negative.py
+++ b/tempest/api/compute/volumes/test_volumes_negative.py
@@ -24,6 +24,11 @@
class VolumesNegativeTest(base.BaseV2ComputeTest):
+ # These tests will fail with a 404 starting from microversion 2.36. For
+ # more information, see:
+ # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated
+ max_microversion = '2.35'
+
@classmethod
def skip_checks(cls):
super(VolumesNegativeTest, cls).skip_checks()
diff --git a/tempest/api/identity/admin/v2/test_endpoints.py b/tempest/api/identity/admin/v2/test_endpoints.py
index db32f5a..59fc4d8 100644
--- a/tempest/api/identity/admin/v2/test_endpoints.py
+++ b/tempest/api/identity/admin/v2/test_endpoints.py
@@ -62,7 +62,7 @@
# Asserting LIST endpoints
missing_endpoints =\
[e for e in self.setup_endpoints if e not in fetched_endpoints]
- self.assertEqual(0, len(missing_endpoints),
+ self.assertEmpty(missing_endpoints,
"Failed to find endpoint %s in fetched list" %
', '.join(str(e) for e in missing_endpoints))
diff --git a/tempest/api/identity/admin/v2/test_roles_negative.py b/tempest/api/identity/admin/v2/test_roles_negative.py
index 86d06e2..f3b7494 100644
--- a/tempest/api/identity/admin/v2/test_roles_negative.py
+++ b/tempest/api/identity/admin/v2/test_roles_negative.py
@@ -143,7 +143,7 @@
@decorators.idempotent_id('99b297f6-2b5d-47c7-97a9-8b6bb4f91042')
def test_assign_user_role_for_non_existent_role(self):
# Attempt to assign a non existent role to user should fail
- (user, tenant, role) = self._get_role_params()
+ (user, tenant, _) = self._get_role_params()
non_existent_role = data_utils.rand_uuid_hex()
self.assertRaises(lib_exc.NotFound,
self.roles_client.create_user_role_on_project,
@@ -153,7 +153,7 @@
@decorators.idempotent_id('b2285aaa-9e76-4704-93a9-7a8acd0a6c8f')
def test_assign_user_role_for_non_existent_tenant(self):
# Attempt to assign a role on a non existent tenant should fail
- (user, tenant, role) = self._get_role_params()
+ (user, _, role) = self._get_role_params()
non_existent_tenant = data_utils.rand_uuid_hex()
self.assertRaises(lib_exc.NotFound,
self.roles_client.create_user_role_on_project,
@@ -244,7 +244,7 @@
@decorators.idempotent_id('682adfb2-fd5f-4b0a-a9ca-322e9bebb907')
def test_list_user_roles_request_without_token(self):
# Request to list user's roles without a valid token should fail
- (user, tenant, role) = self._get_role_params()
+ (user, tenant, _) = self._get_role_params()
token = self.client.auth_provider.get_token()
self.client.delete_token(token)
try:
diff --git a/tempest/api/identity/admin/v2/test_tokens.py b/tempest/api/identity/admin/v2/test_tokens.py
index b4c9389..6b30d23 100644
--- a/tempest/api/identity/admin/v2/test_tokens.py
+++ b/tempest/api/identity/admin/v2/test_tokens.py
@@ -14,14 +14,18 @@
# under the License.
from tempest.api.identity import base
+from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+CONF = config.CONF
class TokensTestJSON(base.BaseIdentityV2AdminTest):
@decorators.idempotent_id('453ad4d5-e486-4b2f-be72-cffc8149e586')
- def test_create_get_delete_token(self):
+ def test_create_check_get_delete_token(self):
# get a token by username and password
user_name = data_utils.rand_name(name='user')
user_password = data_utils.rand_password()
@@ -40,6 +44,7 @@
tenant['name'])
# Perform GET Token
token_id = body['token']['id']
+ self.client.check_token_existence(token_id)
token_details = self.client.show_token(token_id)['access']
self.assertEqual(token_id, token_details['token']['id'])
self.assertEqual(user['id'], token_details['user']['id'])
@@ -48,6 +53,9 @@
token_details['token']['tenant']['name'])
# then delete the token
self.client.delete_token(token_id)
+ self.assertRaises(lib_exc.NotFound,
+ self.client.check_token_existence,
+ token_id)
@decorators.idempotent_id('25ba82ee-8a32-4ceb-8f50-8b8c71e8765e')
def test_rescope_token(self):
@@ -101,3 +109,25 @@
# Use the unscoped token to get a token scoped to tenant2
body = self.token_client.auth_token(token_id,
tenant=tenant2_name)
+
+ @decorators.idempotent_id('ca3ea6f7-ed08-4a61-adbd-96906456ad31')
+ def test_list_endpoints_for_token(self):
+ # get a token for the user
+ creds = self.os_primary.credentials
+ username = creds.username
+ password = creds.password
+ tenant_name = creds.tenant_name
+ token = self.token_client.auth(username,
+ password,
+ tenant_name)['token']
+ endpoints = self.client.list_endpoints_for_token(
+ token['id'])['endpoints']
+ self.assertIsInstance(endpoints, list)
+ # Store list of service names
+ service_names = [e['name'] for e in endpoints]
+ # Get the list of available services.
+ available_services = [s[0] for s in list(
+ CONF.service_available.items()) if s[1] is True]
+ # Verify that all available services are present.
+ for service in available_services:
+ self.assertIn(service, service_names)
diff --git a/tempest/api/identity/admin/v2/test_tokens_negative.py b/tempest/api/identity/admin/v2/test_tokens_negative.py
new file mode 100644
index 0000000..eb3e365
--- /dev/null
+++ b/tempest/api/identity/admin/v2/test_tokens_negative.py
@@ -0,0 +1,38 @@
+# Copyright 2017 AT&T Corporation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.identity import base
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+
+class TokensAdminTestNegative(base.BaseIdentityV2AdminTest):
+
+ credentials = ['primary', 'admin', 'alt']
+
+ @decorators.attr(type=['negative'])
+ @decorators.idempotent_id('a0a0a600-4292-4364-99c5-922c834fdf05')
+ def test_check_token_existence_negative(self):
+ creds = self.os_primary.credentials
+ creds_alt = self.os_alt.credentials
+ username = creds.username
+ password = creds.password
+ tenant_name = creds.tenant_name
+ alt_tenant_name = creds_alt.tenant_name
+ body = self.token_client.auth(username, password, tenant_name)
+ self.assertRaises(lib_exc.Unauthorized,
+ self.client.check_token_existence,
+ body['token']['id'],
+ belongsTo=alt_tenant_name)
diff --git a/tempest/api/identity/admin/v2/test_users.py b/tempest/api/identity/admin/v2/test_users.py
index 2711a2d..0d98af5 100644
--- a/tempest/api/identity/admin/v2/test_users.py
+++ b/tempest/api/identity/admin/v2/test_users.py
@@ -141,7 +141,7 @@
# verifying the user Id in the list
missing_users =\
[user for user in user_ids if user not in fetched_user_ids]
- self.assertEqual(0, len(missing_users),
+ self.assertEmpty(missing_users,
"Failed to find user %s in fetched list" %
', '.join(m_user for m_user in missing_users))
@@ -169,7 +169,7 @@
# verifying the user Id in the list
missing_users = [missing_user for missing_user in user_ids
if missing_user not in fetched_user_ids]
- self.assertEqual(0, len(missing_users),
+ self.assertEmpty(missing_users,
"Failed to find user %s in fetched list" %
', '.join(m_user for m_user in missing_users))
diff --git a/tempest/api/identity/admin/v3/test_credentials.py b/tempest/api/identity/admin/v3/test_credentials.py
index 75e877a..15b2008 100644
--- a/tempest/api/identity/admin/v3/test_credentials.py
+++ b/tempest/api/identity/admin/v3/test_credentials.py
@@ -107,6 +107,6 @@
fetched_cred_ids.append(i['id'])
missing_creds = [c for c in created_cred_ids
if c not in fetched_cred_ids]
- self.assertEqual(0, len(missing_creds),
+ self.assertEmpty(missing_creds,
"Failed to find cred %s in fetched list" %
', '.join(m_cred for m_cred in missing_creds))
diff --git a/tempest/api/identity/admin/v3/test_default_project_id.py b/tempest/api/identity/admin/v3/test_default_project_id.py
index ac2faa9..302a0e5 100644
--- a/tempest/api/identity/admin/v3/test_default_project_id.py
+++ b/tempest/api/identity/admin/v3/test_default_project_id.py
@@ -79,7 +79,7 @@
admin_client = clients.Manager(credentials=creds)
# verify the user's token and see that it is scoped to the project
- token, auth_data = admin_client.auth_provider.get_auth()
+ token, _ = admin_client.auth_provider.get_auth()
result = admin_client.identity_v3_client.show_token(token)['token']
self.assertEqual(result['project']['domain']['id'], dom_id)
self.assertEqual(result['project']['id'], proj_id)
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index cddba53..9fe978c 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -57,7 +57,7 @@
fetched_ids.append(d['id'])
missing_doms = [d for d in self.setup_domains
if d['id'] not in fetched_ids]
- self.assertEqual(0, len(missing_doms))
+ self.assertEmpty(missing_doms)
@decorators.idempotent_id('c6aee07b-4981-440c-bb0b-eb598f58ffe9')
def test_list_domains_filter_by_name(self):
diff --git a/tempest/api/identity/admin/v3/test_endpoint_groups.py b/tempest/api/identity/admin/v3/test_endpoint_groups.py
new file mode 100644
index 0000000..5cd456c
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_endpoint_groups.py
@@ -0,0 +1,157 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+
+
+class EndPointGroupsTest(base.BaseIdentityV3AdminTest):
+
+ @classmethod
+ def setup_clients(cls):
+ super(EndPointGroupsTest, cls).setup_clients()
+ cls.client = cls.endpoint_groups_client
+
+ @classmethod
+ def resource_setup(cls):
+ super(EndPointGroupsTest, cls).resource_setup()
+ cls.service_ids = list()
+ cls.endpoint_groups = list()
+
+ # Create endpoint group so as to use it for LIST test
+ service_id = cls._create_service()
+
+ name = data_utils.rand_name('service_group')
+ description = data_utils.rand_name('description')
+ filters = {'service_id': service_id}
+
+ endpoint_group = cls.client.create_endpoint_group(
+ name=name,
+ description=description,
+ filters=filters)['endpoint_group']
+
+ cls.endpoint_groups.append(endpoint_group)
+
+ @classmethod
+ def resource_cleanup(cls):
+ for e in cls.endpoint_groups:
+ cls.client.delete_endpoint_group(e['id'])
+ for s in cls.service_ids:
+ cls.services_client.delete_service(s)
+ super(EndPointGroupsTest, cls).resource_cleanup()
+
+ @classmethod
+ def _create_service(self):
+ s_name = data_utils.rand_name('service')
+ s_type = data_utils.rand_name('type')
+ s_description = data_utils.rand_name('description')
+ service_data = (
+ self.services_client.create_service(name=s_name,
+ type=s_type,
+ description=s_description))
+
+ service_id = service_data['service']['id']
+ self.service_ids.append(service_id)
+ return service_id
+
+ @decorators.idempotent_id('7c69e7a1-f865-402d-a2ea-44493017315a')
+ def test_create_list_show_check_delete_endpoint_group(self):
+ service_id = self._create_service()
+ name = data_utils.rand_name('service_group')
+ description = data_utils.rand_name('description')
+ filters = {'service_id': service_id}
+
+ endpoint_group = self.client.create_endpoint_group(
+ name=name,
+ description=description,
+ filters=filters)['endpoint_group']
+
+ self.endpoint_groups.append(endpoint_group)
+
+ # Asserting created endpoint group response body
+ self.assertIn('id', endpoint_group)
+ self.assertEqual(name, endpoint_group['name'])
+ self.assertEqual(description, endpoint_group['description'])
+
+ # Checking if endpoint groups are present in the list of endpoints
+ # Note that there are two endpoint groups in the list, one created
+ # in the resource setup, one created in this test case.
+ fetched_endpoints = \
+ self.client.list_endpoint_groups()['endpoint_groups']
+
+ missing_endpoints = \
+ [e for e in self.endpoint_groups if e not in fetched_endpoints]
+
+ # Asserting LIST endpoints
+ self.assertEmpty(missing_endpoints,
+ "Failed to find endpoint %s in fetched list" %
+ ', '.join(str(e) for e in missing_endpoints))
+
+ # Show endpoint group
+ fetched_endpoint = self.client.show_endpoint_group(
+ endpoint_group['id'])['endpoint_group']
+
+ # Asserting if the attributes of endpoint group are the same
+ self.assertEqual(service_id,
+ fetched_endpoint['filters']['service_id'])
+ for attr in ('id', 'name', 'description'):
+ self.assertEqual(endpoint_group[attr], fetched_endpoint[attr])
+
+ # Check endpoint group
+ self.client.check_endpoint_group(endpoint_group['id'])
+
+ # Deleting the endpoint group created in this method
+ self.client.delete_endpoint_group(endpoint_group['id'])
+ self.endpoint_groups.remove(endpoint_group)
+
+ # Checking whether endpoint group is deleted successfully
+ fetched_endpoints = \
+ self.client.list_endpoint_groups()['endpoint_groups']
+ fetched_endpoint_ids = [e['id'] for e in fetched_endpoints]
+ self.assertNotIn(endpoint_group['id'], fetched_endpoint_ids)
+
+ @decorators.idempotent_id('51c8fc38-fa84-4e76-b5b6-6fc37770fb26')
+ def test_update_endpoint_group(self):
+ # Creating an endpoint group so as to check update endpoint group
+ # with new values
+ service1_id = self._create_service()
+ name = data_utils.rand_name('service_group')
+ description = data_utils.rand_name('description')
+ filters = {'service_id': service1_id}
+
+ endpoint_group = self.client.create_endpoint_group(
+ name=name,
+ description=description,
+ filters=filters)['endpoint_group']
+ self.endpoint_groups.append(endpoint_group)
+
+ # Creating new attr values to update endpoint group
+ service2_id = self._create_service()
+ name2 = data_utils.rand_name('service_group2')
+ description2 = data_utils.rand_name('description2')
+ filters = {'service_id': service2_id}
+
+ # Updating endpoint group with new attr values
+ updated_endpoint_group = self.client.update_endpoint_group(
+ endpoint_group['id'],
+ name=name2,
+ description=description2,
+ filters=filters)['endpoint_group']
+
+ self.assertEqual(name2, updated_endpoint_group['name'])
+ self.assertEqual(description2, updated_endpoint_group['description'])
+ self.assertEqual(service2_id,
+ updated_endpoint_group['filters']['service_id'])
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index 09f92e2..b1ae2aa 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -64,7 +64,7 @@
# Asserting LIST endpoints
missing_endpoints =\
[e for e in self.setup_endpoints if e not in fetched_endpoints]
- self.assertEqual(0, len(missing_endpoints),
+ self.assertEmpty(missing_endpoints,
"Failed to find endpoint %s in fetched list" %
', '.join(str(e) for e in missing_endpoints))
diff --git a/tempest/api/identity/admin/v3/test_groups.py b/tempest/api/identity/admin/v3/test_groups.py
index 2694402..4bc987f 100644
--- a/tempest/api/identity/admin/v3/test_groups.py
+++ b/tempest/api/identity/admin/v3/test_groups.py
@@ -134,4 +134,4 @@
for g in body:
fetched_ids.append(g['id'])
missing_groups = [g for g in group_ids if g not in fetched_ids]
- self.assertEqual([], missing_groups)
+ self.assertEmpty(missing_groups)
diff --git a/tempest/api/identity/admin/v3/test_list_users.py b/tempest/api/identity/admin/v3/test_list_users.py
index bcbf6b6..47a3580 100644
--- a/tempest/api/identity/admin/v3/test_list_users.py
+++ b/tempest/api/identity/admin/v3/test_list_users.py
@@ -93,7 +93,7 @@
fetched_ids = [u['id'] for u in body]
missing_users = [u['id'] for u in self.users
if u['id'] not in fetched_ids]
- self.assertEqual(0, len(missing_users),
+ self.assertEmpty(missing_users,
"Failed to find user %s in fetched list" %
', '.join(m_user for m_user in missing_users))
diff --git a/tempest/api/identity/admin/v3/test_oauth_consumers.py b/tempest/api/identity/admin/v3/test_oauth_consumers.py
index f06fb8f..970ead3 100644
--- a/tempest/api/identity/admin/v3/test_oauth_consumers.py
+++ b/tempest/api/identity/admin/v3/test_oauth_consumers.py
@@ -14,7 +14,7 @@
# under the License.
from tempest.api.identity import base
-from tempest.common.utils import data_utils
+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 exceptions
diff --git a/tempest/api/identity/admin/v3/test_policies.py b/tempest/api/identity/admin/v3/test_policies.py
index 730d469..960e2cb 100644
--- a/tempest/api/identity/admin/v3/test_policies.py
+++ b/tempest/api/identity/admin/v3/test_policies.py
@@ -41,7 +41,7 @@
for p in body:
fetched_ids.append(p['id'])
missing_pols = [p for p in policy_ids if p not in fetched_ids]
- self.assertEqual(0, len(missing_pols))
+ self.assertEmpty(missing_pols)
@decorators.attr(type='smoke')
@decorators.idempotent_id('e544703a-2f03-4cf2-9b0f-350782fdb0d3')
diff --git a/tempest/api/identity/admin/v3/test_regions.py b/tempest/api/identity/admin/v3/test_regions.py
index ac550a7..d00e408 100644
--- a/tempest/api/identity/admin/v3/test_regions.py
+++ b/tempest/api/identity/admin/v3/test_regions.py
@@ -98,7 +98,7 @@
missing_regions =\
[e for e in self.setup_regions if e not in fetched_regions]
# Asserting List Regions response
- self.assertEqual(0, len(missing_regions),
+ self.assertEmpty(missing_regions,
"Failed to find region %s in fetched list" %
', '.join(str(e) for e in missing_regions))
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index adb467c..6d42b2a 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -215,7 +215,7 @@
implies_role_id)
@decorators.idempotent_id('c90c316c-d706-4728-bcba-eb1912081b69')
- def test_implied_roles_create_delete(self):
+ def test_implied_roles_create_check_show_delete(self):
prior_role_id = self.roles[0]['id']
implies_role_id = self.roles[1]['id']
@@ -224,9 +224,19 @@
ignore_not_found=True)
# Check if the inference rule exists
- self.roles_client.show_role_inference_rule(
+ self.roles_client.check_role_inference_rule(
prior_role_id, implies_role_id)
+ # Show the inference rule and check its elements
+ resp_body = self.roles_client.show_role_inference_rule(
+ prior_role_id, implies_role_id)
+ self.assertIn('role_inference', resp_body)
+ role_inference = resp_body['role_inference']
+ for key1 in ['prior_role', 'implies']:
+ self.assertIn(key1, role_inference)
+ for key2 in ['id', 'links', 'name']:
+ self.assertIn(key2, role_inference[key1])
+
# Delete the inference rule
self.roles_client.delete_role_inference_rule(
prior_role_id, implies_role_id)
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index 8c5e63b..1acc67d 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -145,7 +145,7 @@
@decorators.idempotent_id('08ed85ce-2ba8-4864-b442-bcc61f16ae89')
def test_get_available_project_scopes(self):
- manager_project_id = self.manager.credentials.project_id
+ manager_project_id = self.os_primary.credentials.project_id
admin_user_id = self.os_admin.credentials.user_id
admin_role_id = self.get_role_by_name(CONF.identity.admin_role)['id']
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index 751962f..409d4f8 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -131,7 +131,7 @@
missing_projects =\
[p for p in assigned_project_ids
if p not in fetched_project_ids]
- self.assertEqual(0, len(missing_projects),
+ self.assertEmpty(missing_projects,
"Failed to find project %s in fetched list" %
', '.join(m_project for m_project
in missing_projects))
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 785485b..3bc6ce1 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -225,6 +225,7 @@
cls.oauth_consumers_client = cls.os_admin.oauth_consumers_client
cls.domain_config_client = cls.os_admin.domain_config_client
cls.endpoint_filter_client = cls.os_admin.endpoint_filter_client
+ cls.endpoint_groups_client = cls.os_admin.endpoint_groups_client
if CONF.identity.admin_domain_scope:
# NOTE(andreaf) When keystone policy requires it, the identity
diff --git a/tempest/api/identity/v3/test_tokens.py b/tempest/api/identity/v3/test_tokens.py
index c9d7a4d..4c72d82 100644
--- a/tempest/api/identity/v3/test_tokens.py
+++ b/tempest/api/identity/v3/test_tokens.py
@@ -15,12 +15,39 @@
from oslo_utils import timeutils
import six
+
from tempest.api.identity import base
from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
class TokensV3Test(base.BaseIdentityV3Test):
+ @decorators.idempotent_id('a9512ac3-3909-48a4-b395-11f438e16260')
+ def test_validate_token(self):
+ creds = self.os_primary.credentials
+ user_id = creds.user_id
+ username = creds.username
+ password = creds.password
+ user_domain_id = creds.user_domain_id
+ # GET and validate token
+ subject_token, token_body = self.non_admin_token.get_token(
+ user_id=user_id,
+ username=username,
+ user_domain_id=user_domain_id,
+ password=password,
+ auth_data=True)
+ authenticated_token = self.non_admin_client.show_token(
+ subject_token)['token']
+ # sanity checking to make sure they are indeed the same token
+ self.assertEqual(authenticated_token, token_body)
+ # test to see if token has been properly authenticated
+ self.assertEqual(authenticated_token['user']['id'], user_id)
+ self.assertEqual(authenticated_token['user']['name'], username)
+ self.non_admin_client.delete_token(subject_token)
+ self.assertRaises(
+ lib_exc.NotFound, self.non_admin_client.show_token, subject_token)
+
@decorators.idempotent_id('6f8e4436-fc96-4282-8122-e41df57197a9')
def test_create_token(self):
@@ -54,15 +81,13 @@
self.assertEqual(subject_id, user_id)
else:
# Expect a user ID, but don't know what it will be.
- self.assertGreaterEqual(len(subject_id), 0,
- 'Expected user ID in token.')
+ self.assertIsNotNone(subject_id, 'Expected user ID in token.')
subject_name = resp['user']['name']
if username:
self.assertEqual(subject_name, username)
else:
# Expect a user name, but don't know what it will be.
- self.assertGreaterEqual(len(subject_name), 0,
- 'Expected user name in token.')
+ self.assertIsNotNone(subject_name, 'Expected user name in token.')
self.assertEqual(resp['methods'][0], 'password')
diff --git a/tempest/api/image/v1/test_image_members.py b/tempest/api/image/v1/test_image_members.py
index 4902316..bf2e510 100644
--- a/tempest/api/image/v1/test_image_members.py
+++ b/tempest/api/image/v1/test_image_members.py
@@ -54,6 +54,6 @@
self.alt_tenant_id)
body = self.image_member_client.list_image_members(image_id)
members = body['members']
- self.assertEqual(0, len(members), str(members))
+ self.assertEmpty(members)
self.assertRaises(
lib_exc.NotFound, self.alt_img_cli.show_image, image_id)
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index b341ab7..76723f4 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -43,7 +43,8 @@
else:
msg = ("The container format and the disk format don't match. "
"Container format: %(container)s, Disk format: %(disk)s." %
- {'container': container_format, 'disk': disk_format})
+ {'container': container_format, 'disk':
+ CONF.image.disk_formats})
raise exceptions.InvalidConfiguration(msg)
else:
disk_format = CONF.image.disk_formats[0]
diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_tags.py b/tempest/api/image/v2/test_images_metadefs_namespace_tags.py
index e2a3617..69bebfe 100644
--- a/tempest/api/image/v2/test_images_metadefs_namespace_tags.py
+++ b/tempest/api/image/v2/test_images_metadefs_namespace_tags.py
@@ -58,7 +58,7 @@
namespace['namespace'])
body = self.namespace_tags_client.list_namespace_tags(
namespace['namespace'])
- self.assertEqual([], body['tags'])
+ self.assertEmpty(body['tags'])
@decorators.idempotent_id('a2a3765e-1a2c-3f6d-a3a7-3cc3466ab875')
def test_create_update_delete_tag(self):
diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py
index 6389489..7304db9 100644
--- a/tempest/api/network/admin/test_agent_management.py
+++ b/tempest/api/network/admin/test_agent_management.py
@@ -49,7 +49,7 @@
@decorators.idempotent_id('e335be47-b9a1-46fd-be30-0874c0b751e6')
def test_list_agents_non_admin(self):
body = self.agents_client.list_agents()
- self.assertEqual(len(body["agents"]), 0)
+ self.assertEmpty(body["agents"])
@decorators.idempotent_id('869bc8e8-0fda-4a30-9b71-f8a7cf58ca9f')
def test_show_agent(self):
diff --git a/tempest/api/network/admin/test_external_network_extension.py b/tempest/api/network/admin/test_external_network_extension.py
index c83dd7f..4d41e33 100644
--- a/tempest/api/network/admin/test_external_network_extension.py
+++ b/tempest/api/network/admin/test_external_network_extension.py
@@ -10,11 +10,16 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.api.network import base
+from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
+CONF = config.CONF
+
class ExternalNetworksTestJSON(base.BaseAdminNetworkTest):
@@ -91,6 +96,8 @@
self.assertFalse(show_net['router:external'])
@decorators.idempotent_id('82068503-2cf2-4ed4-b3be-ecb89432e4bb')
+ @testtools.skipUnless(CONF.network_feature_enabled.floating_ips,
+ 'Floating ips are not availabled')
def test_delete_external_networks_with_floating_ip(self):
# Verifies external network can be deleted while still holding
# (unassociated) floating IPs
diff --git a/tempest/api/network/admin/test_floating_ips_admin_actions.py b/tempest/api/network/admin/test_floating_ips_admin_actions.py
index 11f520a..7ee819e 100644
--- a/tempest/api/network/admin/test_floating_ips_admin_actions.py
+++ b/tempest/api/network/admin/test_floating_ips_admin_actions.py
@@ -34,6 +34,8 @@
if not CONF.network.public_network_id:
msg = "The public_network_id option must be specified."
raise cls.skipException(msg)
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/network/test_metering_extensions.py b/tempest/api/network/admin/test_metering_extensions.py
similarity index 85%
rename from tempest/api/network/test_metering_extensions.py
rename to tempest/api/network/admin/test_metering_extensions.py
index 18dccc3..21a7ab4 100644
--- a/tempest/api/network/test_metering_extensions.py
+++ b/tempest/api/network/admin/test_metering_extensions.py
@@ -45,6 +45,28 @@
remote_ip_prefix, direction,
metering_label_id=cls.metering_label['id'])
+ @classmethod
+ def create_metering_label(cls, name, description):
+ """Wrapper utility that returns a test metering label."""
+ body = cls.admin_metering_labels_client.create_metering_label(
+ description=description,
+ name=name)
+ metering_label = body['metering_label']
+ cls.metering_labels.append(metering_label)
+ return metering_label
+
+ @classmethod
+ def create_metering_label_rule(cls, remote_ip_prefix, direction,
+ metering_label_id):
+ """Wrapper utility that returns a test metering label rule."""
+ client = cls.admin_metering_label_rules_client
+ body = client.create_metering_label_rule(
+ remote_ip_prefix=remote_ip_prefix, direction=direction,
+ metering_label_id=metering_label_id)
+ metering_label_rule = body['metering_label_rule']
+ cls.metering_label_rules.append(metering_label_rule)
+ return metering_label_rule
+
def _delete_metering_label(self, metering_label_id):
# Deletes a label and verifies if it is deleted or not
self.admin_metering_labels_client.delete_metering_label(
@@ -52,7 +74,7 @@
# Asserting that the label is not found in list after deletion
labels = self.admin_metering_labels_client.list_metering_labels(
id=metering_label_id)
- self.assertEqual(len(labels['metering_labels']), 0)
+ self.assertEmpty(labels['metering_labels'])
def _delete_metering_label_rule(self, metering_label_rule_id):
client = self.admin_metering_label_rules_client
@@ -67,7 +89,7 @@
# Verify label filtering
body = self.admin_metering_labels_client.list_metering_labels(id=33)
metering_labels = body['metering_labels']
- self.assertEqual(0, len(metering_labels))
+ self.assertEmpty(metering_labels)
@decorators.idempotent_id('ec8e15ff-95d0-433b-b8a6-b466bddb1e50')
def test_create_delete_metering_label_with_filters(self):
@@ -104,7 +126,7 @@
# Verify rule filtering
body = client.list_metering_label_rules(id=33)
metering_label_rules = body['metering_label_rules']
- self.assertEqual(0, len(metering_label_rules))
+ self.assertEmpty(metering_label_rules)
@decorators.idempotent_id('f4d547cd-3aee-408f-bf36-454f8825e045')
def test_create_delete_metering_label_rule_with_filters(self):
diff --git a/tempest/api/network/admin/test_ports.py b/tempest/api/network/admin/test_ports.py
new file mode 100644
index 0000000..807994b
--- /dev/null
+++ b/tempest/api/network/admin/test_ports.py
@@ -0,0 +1,99 @@
+# Copyright 2014 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import socket
+
+from tempest.api.network import base
+from tempest import config
+from tempest.lib import decorators
+
+CONF = config.CONF
+
+
+class PortsAdminExtendedAttrsTestJSON(base.BaseAdminNetworkTest):
+
+ @classmethod
+ def resource_setup(cls):
+ super(PortsAdminExtendedAttrsTestJSON, cls).resource_setup()
+ cls.network = cls.create_network()
+ cls.host_id = socket.gethostname()
+
+ @decorators.idempotent_id('8e8569c1-9ac7-44db-8bc1-f5fb2814f29b')
+ def test_create_port_binding_ext_attr(self):
+ post_body = {"network_id": self.network['id'],
+ "binding:host_id": self.host_id}
+ body = self.admin_ports_client.create_port(**post_body)
+ port = body['port']
+ self.addCleanup(self.admin_ports_client.delete_port, port['id'])
+ host_id = port['binding:host_id']
+ self.assertIsNotNone(host_id)
+ self.assertEqual(self.host_id, host_id)
+
+ @decorators.idempotent_id('6f6c412c-711f-444d-8502-0ac30fbf5dd5')
+ def test_update_port_binding_ext_attr(self):
+ post_body = {"network_id": self.network['id']}
+ body = self.admin_ports_client.create_port(**post_body)
+ port = body['port']
+ self.addCleanup(self.admin_ports_client.delete_port, port['id'])
+ update_body = {"binding:host_id": self.host_id}
+ body = self.admin_ports_client.update_port(port['id'], **update_body)
+ updated_port = body['port']
+ host_id = updated_port['binding:host_id']
+ self.assertIsNotNone(host_id)
+ self.assertEqual(self.host_id, host_id)
+
+ @decorators.idempotent_id('1c82a44a-6c6e-48ff-89e1-abe7eaf8f9f8')
+ def test_list_ports_binding_ext_attr(self):
+ # Create a new port
+ post_body = {"network_id": self.network['id']}
+ body = self.admin_ports_client.create_port(**post_body)
+ port = body['port']
+ self.addCleanup(self.admin_ports_client.delete_port, port['id'])
+
+ # Update the port's binding attributes so that is now 'bound'
+ # to a host
+ update_body = {"binding:host_id": self.host_id}
+ self.admin_ports_client.update_port(port['id'], **update_body)
+
+ # List all ports, ensure new port is part of list and its binding
+ # attributes are set and accurate
+ body = self.admin_ports_client.list_ports()
+ ports_list = body['ports']
+ pids_list = [p['id'] for p in ports_list]
+ self.assertIn(port['id'], pids_list)
+ listed_port = [p for p in ports_list if p['id'] == port['id']]
+ self.assertEqual(1, len(listed_port),
+ 'Multiple ports listed with id %s in ports listing: '
+ '%s' % (port['id'], ports_list))
+ self.assertEqual(self.host_id, listed_port[0]['binding:host_id'])
+
+ @decorators.idempotent_id('b54ac0ff-35fc-4c79-9ca3-c7dbd4ea4f13')
+ def test_show_port_binding_ext_attr(self):
+ body = self.admin_ports_client.create_port(
+ network_id=self.network['id'])
+ port = body['port']
+ self.addCleanup(self.admin_ports_client.delete_port, port['id'])
+ body = self.admin_ports_client.show_port(port['id'])
+ show_port = body['port']
+ self.assertEqual(port['binding:host_id'],
+ show_port['binding:host_id'])
+ self.assertEqual(port['binding:vif_type'],
+ show_port['binding:vif_type'])
+ self.assertEqual(port['binding:vif_details'],
+ show_port['binding:vif_details'])
+
+
+class PortsAdminExtendedAttrsIpV6TestJSON(PortsAdminExtendedAttrsTestJSON):
+ _ip_version = 6
diff --git a/tempest/api/network/admin/test_routers.py b/tempest/api/network/admin/test_routers.py
new file mode 100644
index 0000000..07c4157
--- /dev/null
+++ b/tempest/api/network/admin/test_routers.py
@@ -0,0 +1,231 @@
+# Copyright 2013 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import testtools
+
+from tempest.api.network import base
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest import test
+
+CONF = config.CONF
+
+
+class RoutersAdminTest(base.BaseAdminNetworkTest):
+ # NOTE(salv-orlando): This class inherits from BaseAdminNetworkTest
+ # as some router operations, such as enabling or disabling SNAT
+ # require admin credentials by default
+
+ def _cleanup_router(self, router):
+ self.delete_router(router)
+ self.routers.remove(router)
+
+ def _create_router(self, name=None, admin_state_up=False,
+ external_network_id=None, enable_snat=None):
+ # associate a cleanup with created routers to avoid quota limits
+ router = self.create_router(name, admin_state_up,
+ external_network_id, enable_snat)
+ self.addCleanup(self._cleanup_router, router)
+ return router
+
+ def _add_router_interface_with_subnet_id(self, router_id, subnet_id):
+ interface = self.routers_client.add_router_interface(
+ router_id, subnet_id=subnet_id)
+ self.addCleanup(self._remove_router_interface_with_subnet_id,
+ router_id, subnet_id)
+ self.assertEqual(subnet_id, interface['subnet_id'])
+ return interface
+
+ def _remove_router_interface_with_subnet_id(self, router_id, subnet_id):
+ body = self.routers_client.remove_router_interface(router_id,
+ subnet_id=subnet_id)
+ self.assertEqual(subnet_id, body['subnet_id'])
+
+ @classmethod
+ def skip_checks(cls):
+ super(RoutersAdminTest, cls).skip_checks()
+ if not test.is_extension_enabled('router', 'network'):
+ msg = "router extension not enabled."
+ raise cls.skipException(msg)
+
+ @classmethod
+ def resource_setup(cls):
+ super(RoutersAdminTest, cls).resource_setup()
+ cls.tenant_cidr = (CONF.network.project_network_cidr
+ if cls._ip_version == 4 else
+ CONF.network.project_network_v6_cidr)
+
+ @decorators.idempotent_id('e54dd3a3-4352-4921-b09d-44369ae17397')
+ def test_create_router_setting_project_id(self):
+ # Test creating router from admin user setting project_id.
+ project = data_utils.rand_name('test_tenant_')
+ description = data_utils.rand_name('desc_')
+ project = self.identity_utils.create_project(name=project,
+ description=description)
+ project_id = project['id']
+ self.addCleanup(self.identity_utils.delete_project, project_id)
+
+ name = data_utils.rand_name('router-')
+ create_body = self.admin_routers_client.create_router(
+ name=name, tenant_id=project_id)
+ self.addCleanup(self.admin_routers_client.delete_router,
+ create_body['router']['id'])
+ self.assertEqual(project_id, create_body['router']['tenant_id'])
+
+ @decorators.idempotent_id('847257cc-6afd-4154-b8fb-af49f5670ce8')
+ @test.requires_ext(extension='ext-gw-mode', service='network')
+ @testtools.skipUnless(CONF.network.public_network_id,
+ 'The public_network_id option must be specified.')
+ def test_create_router_with_default_snat_value(self):
+ # Create a router with default snat rule
+ router = self._create_router(
+ external_network_id=CONF.network.public_network_id)
+ self._verify_router_gateway(
+ router['id'], {'network_id': CONF.network.public_network_id,
+ 'enable_snat': True})
+
+ @decorators.idempotent_id('ea74068d-09e9-4fd7-8995-9b6a1ace920f')
+ @test.requires_ext(extension='ext-gw-mode', service='network')
+ @testtools.skipUnless(CONF.network.public_network_id,
+ 'The public_network_id option must be specified.')
+ def test_create_router_with_snat_explicit(self):
+ name = data_utils.rand_name('snat-router')
+ # Create a router enabling snat attributes
+ enable_snat_states = [False, True]
+ for enable_snat in enable_snat_states:
+ external_gateway_info = {
+ 'network_id': CONF.network.public_network_id,
+ 'enable_snat': enable_snat}
+ create_body = self.admin_routers_client.create_router(
+ name=name, external_gateway_info=external_gateway_info)
+ self.addCleanup(self.admin_routers_client.delete_router,
+ create_body['router']['id'])
+ # Verify snat attributes after router creation
+ self._verify_router_gateway(create_body['router']['id'],
+ exp_ext_gw_info=external_gateway_info)
+
+ def _verify_router_gateway(self, router_id, exp_ext_gw_info=None):
+ show_body = self.admin_routers_client.show_router(router_id)
+ actual_ext_gw_info = show_body['router']['external_gateway_info']
+ if exp_ext_gw_info is None:
+ self.assertIsNone(actual_ext_gw_info)
+ return
+ # Verify only keys passed in exp_ext_gw_info
+ for k, v in exp_ext_gw_info.items():
+ self.assertEqual(v, actual_ext_gw_info[k])
+
+ def _verify_gateway_port(self, router_id):
+ list_body = self.admin_ports_client.list_ports(
+ network_id=CONF.network.public_network_id,
+ device_id=router_id)
+ self.assertEqual(len(list_body['ports']), 1)
+ gw_port = list_body['ports'][0]
+ fixed_ips = gw_port['fixed_ips']
+ self.assertNotEmpty(fixed_ips)
+ # Assert that all of the IPs from the router gateway port
+ # are allocated from a valid public subnet.
+ public_net_body = self.admin_networks_client.show_network(
+ CONF.network.public_network_id)
+ public_subnet_ids = public_net_body['network']['subnets']
+ for fixed_ip in fixed_ips:
+ subnet_id = fixed_ip['subnet_id']
+ self.assertIn(subnet_id, public_subnet_ids)
+
+ @decorators.idempotent_id('6cc285d8-46bf-4f36-9b1a-783e3008ba79')
+ @testtools.skipUnless(CONF.network.public_network_id,
+ 'The public_network_id option must be specified.')
+ def test_update_router_set_gateway(self):
+ router = self._create_router()
+ self.routers_client.update_router(
+ router['id'],
+ external_gateway_info={
+ 'network_id': CONF.network.public_network_id})
+ # Verify operation - router
+ self._verify_router_gateway(
+ router['id'],
+ {'network_id': CONF.network.public_network_id})
+ self._verify_gateway_port(router['id'])
+
+ @decorators.idempotent_id('b386c111-3b21-466d-880c-5e72b01e1a33')
+ @test.requires_ext(extension='ext-gw-mode', service='network')
+ @testtools.skipUnless(CONF.network.public_network_id,
+ 'The public_network_id option must be specified.')
+ def test_update_router_set_gateway_with_snat_explicit(self):
+ router = self._create_router()
+ self.admin_routers_client.update_router(
+ router['id'],
+ external_gateway_info={
+ 'network_id': CONF.network.public_network_id,
+ 'enable_snat': True})
+ self._verify_router_gateway(
+ router['id'],
+ {'network_id': CONF.network.public_network_id,
+ 'enable_snat': True})
+ self._verify_gateway_port(router['id'])
+
+ @decorators.idempotent_id('96536bc7-8262-4fb2-9967-5c46940fa279')
+ @test.requires_ext(extension='ext-gw-mode', service='network')
+ @testtools.skipUnless(CONF.network.public_network_id,
+ 'The public_network_id option must be specified.')
+ def test_update_router_set_gateway_without_snat(self):
+ router = self._create_router()
+ self.admin_routers_client.update_router(
+ router['id'],
+ external_gateway_info={
+ 'network_id': CONF.network.public_network_id,
+ 'enable_snat': False})
+ self._verify_router_gateway(
+ router['id'],
+ {'network_id': CONF.network.public_network_id,
+ 'enable_snat': False})
+ self._verify_gateway_port(router['id'])
+
+ @decorators.idempotent_id('ad81b7ee-4f81-407b-a19c-17e623f763e8')
+ @testtools.skipUnless(CONF.network.public_network_id,
+ 'The public_network_id option must be specified.')
+ def test_update_router_unset_gateway(self):
+ router = self._create_router(
+ external_network_id=CONF.network.public_network_id)
+ self.routers_client.update_router(router['id'],
+ external_gateway_info={})
+ self._verify_router_gateway(router['id'])
+ # No gateway port expected
+ list_body = self.admin_ports_client.list_ports(
+ network_id=CONF.network.public_network_id,
+ device_id=router['id'])
+ self.assertFalse(list_body['ports'])
+
+ @decorators.idempotent_id('f2faf994-97f4-410b-a831-9bc977b64374')
+ @test.requires_ext(extension='ext-gw-mode', service='network')
+ @testtools.skipUnless(CONF.network.public_network_id,
+ 'The public_network_id option must be specified.')
+ def test_update_router_reset_gateway_without_snat(self):
+ router = self._create_router(
+ external_network_id=CONF.network.public_network_id)
+ self.admin_routers_client.update_router(
+ router['id'],
+ external_gateway_info={
+ 'network_id': CONF.network.public_network_id,
+ 'enable_snat': False})
+ self._verify_router_gateway(
+ router['id'],
+ {'network_id': CONF.network.public_network_id,
+ 'enable_snat': False})
+ self._verify_gateway_port(router['id'])
+
+
+class RoutersIpV6AdminTest(RoutersAdminTest):
+ _ip_version = 6
diff --git a/tempest/api/network/admin/test_routers_dvr.py b/tempest/api/network/admin/test_routers_dvr.py
index 4ccad30..f9a0cfb 100644
--- a/tempest/api/network/admin/test_routers_dvr.py
+++ b/tempest/api/network/admin/test_routers_dvr.py
@@ -15,13 +15,13 @@
import testtools
-from tempest.api.network import base_routers as base
+from tempest.api.network import base
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
from tempest import test
-class RoutersTestDVR(base.BaseRouterTest):
+class RoutersTestDVR(base.BaseAdminNetworkTest):
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/network/admin/test_routers_negative.py b/tempest/api/network/admin/test_routers_negative.py
new file mode 100644
index 0000000..f350a15
--- /dev/null
+++ b/tempest/api/network/admin/test_routers_negative.py
@@ -0,0 +1,63 @@
+# Copyright 2013 OpenStack Foundation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import testtools
+
+from tempest.api.network import base
+from tempest import config
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from tempest import test
+
+CONF = config.CONF
+
+
+class RoutersAdminNegativeTest(base.BaseAdminNetworkTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(RoutersAdminNegativeTest, cls).skip_checks()
+ if not test.is_extension_enabled('router', 'network'):
+ msg = "router extension not enabled."
+ raise cls.skipException(msg)
+
+ @decorators.attr(type=['negative'])
+ @decorators.idempotent_id('7101cc02-058a-11e7-93e1-fa163e4fa634')
+ @test.requires_ext(extension='ext-gw-mode', service='network')
+ @testtools.skipUnless(CONF.network.public_network_id,
+ 'The public_network_id option must be specified.')
+ def test_router_set_gateway_used_ip_returns_409(self):
+ # At first create a address from public_network_id
+ port = self.admin_ports_client.create_port(
+ network_id=CONF.network.public_network_id)['port']
+ self.addCleanup(self.admin_ports_client.delete_port,
+ port_id=port['id'])
+ # Add used ip and subnet_id in external_fixed_ips
+ fixed_ip = {
+ 'subnet_id': port['fixed_ips'][0]['subnet_id'],
+ 'ip_address': port['fixed_ips'][0]['ip_address']
+ }
+ external_gateway_info = {
+ 'network_id': CONF.network.public_network_id,
+ 'external_fixed_ips': [fixed_ip]
+ }
+ # Create a router and set gateway to used ip
+ self.assertRaises(lib_exc.Conflict,
+ self.admin_routers_client.create_router,
+ external_gateway_info=external_gateway_info)
+
+
+class RoutersAdminNegativeIpV6Test(RoutersAdminNegativeTest):
+ _ip_version = 6
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 359a444..6bec0d7 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -83,6 +83,7 @@
cls.os_primary.security_group_rules_client)
cls.network_versions_client = cls.os_primary.network_versions_client
cls.service_providers_client = cls.os_primary.service_providers_client
+ cls.tags_client = cls.os_primary.tags_client
@classmethod
def resource_setup(cls):
@@ -269,25 +270,3 @@
cls.admin_metering_labels_client = cls.os_admin.metering_labels_client
cls.admin_metering_label_rules_client = (
cls.os_admin.metering_label_rules_client)
-
- @classmethod
- def create_metering_label(cls, name, description):
- """Wrapper utility that returns a test metering label."""
- body = cls.admin_metering_labels_client.create_metering_label(
- description=description,
- name=name)
- metering_label = body['metering_label']
- cls.metering_labels.append(metering_label)
- return metering_label
-
- @classmethod
- def create_metering_label_rule(cls, remote_ip_prefix, direction,
- metering_label_id):
- """Wrapper utility that returns a test metering label rule."""
- client = cls.admin_metering_label_rules_client
- body = client.create_metering_label_rule(
- remote_ip_prefix=remote_ip_prefix, direction=direction,
- metering_label_id=metering_label_id)
- metering_label_rule = body['metering_label_rule']
- cls.metering_label_rules.append(metering_label_rule)
- return metering_label_rule
diff --git a/tempest/api/network/base_routers.py b/tempest/api/network/base_routers.py
deleted file mode 100644
index f6fd871..0000000
--- a/tempest/api/network/base_routers.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.network import base
-
-
-class BaseRouterTest(base.BaseAdminNetworkTest):
- # NOTE(salv-orlando): This class inherits from BaseAdminNetworkTest
- # as some router operations, such as enabling or disabling SNAT
- # require admin credentials by default
-
- def _cleanup_router(self, router):
- self.delete_router(router)
- self.routers.remove(router)
-
- def _create_router(self, name=None, admin_state_up=False,
- external_network_id=None, enable_snat=None):
- # associate a cleanup with created routers to avoid quota limits
- router = self.create_router(name, admin_state_up,
- external_network_id, enable_snat)
- self.addCleanup(self._cleanup_router, router)
- return router
-
- def _delete_router(self, router_id, routers_client=None):
- client = routers_client or self.routers_client
- client.delete_router(router_id)
- # Asserting that the router is not found in the list
- # after deletion
- list_body = client.list_routers()
- routers_list = [router['id'] for router in list_body['routers']]
- self.assertNotIn(router_id, routers_list)
-
- def _add_router_interface_with_subnet_id(self, router_id, subnet_id):
- interface = self.routers_client.add_router_interface(
- router_id, subnet_id=subnet_id)
- self.addCleanup(self._remove_router_interface_with_subnet_id,
- router_id, subnet_id)
- self.assertEqual(subnet_id, interface['subnet_id'])
- return interface
-
- def _remove_router_interface_with_subnet_id(self, router_id, subnet_id):
- body = self.routers_client.remove_router_interface(router_id,
- subnet_id=subnet_id)
- self.assertEqual(subnet_id, body['subnet_id'])
-
- def _remove_router_interface_with_port_id(self, router_id, port_id):
- body = self.routers_client.remove_router_interface(router_id,
- port_id=port_id)
- self.assertEqual(port_id, body['port_id'])
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index f0f92ac..c799b15 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -49,6 +49,8 @@
if not CONF.network.public_network_id:
msg = "The public_network_id option must be specified."
raise cls.skipException(msg)
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/network/test_floating_ips_negative.py b/tempest/api/network/test_floating_ips_negative.py
index f5830ab..5ca17fe 100644
--- a/tempest/api/network/test_floating_ips_negative.py
+++ b/tempest/api/network/test_floating_ips_negative.py
@@ -40,6 +40,8 @@
if not CONF.network.public_network_id:
msg = "The public_network_id option must be specified."
raise cls.skipException(msg)
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 69a1441..f81927d 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -13,12 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-import socket
-
import netaddr
import testtools
-from tempest.api.network import base
from tempest.api.network import base_security_groups as sec_base
from tempest.common import custom_matchers
from tempest import config
@@ -358,82 +355,5 @@
self.assertEmpty(port['security_groups'])
-class PortsAdminExtendedAttrsTestJSON(base.BaseAdminNetworkTest):
-
- @classmethod
- def resource_setup(cls):
- super(PortsAdminExtendedAttrsTestJSON, cls).resource_setup()
- cls.network = cls.create_network()
- cls.host_id = socket.gethostname()
-
- @decorators.idempotent_id('8e8569c1-9ac7-44db-8bc1-f5fb2814f29b')
- def test_create_port_binding_ext_attr(self):
- post_body = {"network_id": self.network['id'],
- "binding:host_id": self.host_id}
- body = self.admin_ports_client.create_port(**post_body)
- port = body['port']
- self.addCleanup(self.admin_ports_client.delete_port, port['id'])
- host_id = port['binding:host_id']
- self.assertIsNotNone(host_id)
- self.assertEqual(self.host_id, host_id)
-
- @decorators.idempotent_id('6f6c412c-711f-444d-8502-0ac30fbf5dd5')
- def test_update_port_binding_ext_attr(self):
- post_body = {"network_id": self.network['id']}
- body = self.admin_ports_client.create_port(**post_body)
- port = body['port']
- self.addCleanup(self.admin_ports_client.delete_port, port['id'])
- update_body = {"binding:host_id": self.host_id}
- body = self.admin_ports_client.update_port(port['id'], **update_body)
- updated_port = body['port']
- host_id = updated_port['binding:host_id']
- self.assertIsNotNone(host_id)
- self.assertEqual(self.host_id, host_id)
-
- @decorators.idempotent_id('1c82a44a-6c6e-48ff-89e1-abe7eaf8f9f8')
- def test_list_ports_binding_ext_attr(self):
- # Create a new port
- post_body = {"network_id": self.network['id']}
- body = self.admin_ports_client.create_port(**post_body)
- port = body['port']
- self.addCleanup(self.admin_ports_client.delete_port, port['id'])
-
- # Update the port's binding attributes so that is now 'bound'
- # to a host
- update_body = {"binding:host_id": self.host_id}
- self.admin_ports_client.update_port(port['id'], **update_body)
-
- # List all ports, ensure new port is part of list and its binding
- # attributes are set and accurate
- body = self.admin_ports_client.list_ports()
- ports_list = body['ports']
- pids_list = [p['id'] for p in ports_list]
- self.assertIn(port['id'], pids_list)
- listed_port = [p for p in ports_list if p['id'] == port['id']]
- self.assertEqual(1, len(listed_port),
- 'Multiple ports listed with id %s in ports listing: '
- '%s' % (port['id'], ports_list))
- self.assertEqual(self.host_id, listed_port[0]['binding:host_id'])
-
- @decorators.idempotent_id('b54ac0ff-35fc-4c79-9ca3-c7dbd4ea4f13')
- def test_show_port_binding_ext_attr(self):
- body = self.admin_ports_client.create_port(
- network_id=self.network['id'])
- port = body['port']
- self.addCleanup(self.admin_ports_client.delete_port, port['id'])
- body = self.admin_ports_client.show_port(port['id'])
- show_port = body['port']
- self.assertEqual(port['binding:host_id'],
- show_port['binding:host_id'])
- self.assertEqual(port['binding:vif_type'],
- show_port['binding:vif_type'])
- self.assertEqual(port['binding:vif_details'],
- show_port['binding:vif_details'])
-
-
class PortsIpV6TestJSON(PortsTestJSON):
_ip_version = 6
-
-
-class PortsAdminExtendedAttrsIpV6TestJSON(PortsAdminExtendedAttrsTestJSON):
- _ip_version = 6
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 97ad4d4..128544b 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -16,7 +16,7 @@
import netaddr
import testtools
-from tempest.api.network import base_routers as base
+from tempest.api.network import base
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
@@ -25,7 +25,32 @@
CONF = config.CONF
-class RoutersTest(base.BaseRouterTest):
+class RoutersTest(base.BaseNetworkTest):
+
+ def _cleanup_router(self, router):
+ self.delete_router(router)
+ self.routers.remove(router)
+
+ def _create_router(self, name=None, admin_state_up=False,
+ external_network_id=None, enable_snat=None):
+ # associate a cleanup with created routers to avoid quota limits
+ router = self.create_router(name, admin_state_up,
+ external_network_id, enable_snat)
+ self.addCleanup(self._cleanup_router, router)
+ return router
+
+ def _add_router_interface_with_subnet_id(self, router_id, subnet_id):
+ interface = self.routers_client.add_router_interface(
+ router_id, subnet_id=subnet_id)
+ self.addCleanup(self._remove_router_interface_with_subnet_id,
+ router_id, subnet_id)
+ self.assertEqual(subnet_id, interface['subnet_id'])
+ return interface
+
+ def _remove_router_interface_with_subnet_id(self, router_id, subnet_id):
+ body = self.routers_client.remove_router_interface(router_id,
+ subnet_id=subnet_id)
+ self.assertEqual(subnet_id, body['subnet_id'])
@classmethod
def skip_checks(cls):
@@ -73,55 +98,6 @@
router['id'])['router']
self.assertEqual(router_show['name'], updated_name)
- @decorators.idempotent_id('e54dd3a3-4352-4921-b09d-44369ae17397')
- def test_create_router_setting_project_id(self):
- # Test creating router from admin user setting project_id.
- project = data_utils.rand_name('test_tenant_')
- description = data_utils.rand_name('desc_')
- project = self.identity_utils.create_project(name=project,
- description=description)
- project_id = project['id']
- self.addCleanup(self.identity_utils.delete_project, project_id)
-
- name = data_utils.rand_name('router-')
- create_body = self.admin_routers_client.create_router(
- name=name, tenant_id=project_id)
- self.addCleanup(self.admin_routers_client.delete_router,
- create_body['router']['id'])
- self.assertEqual(project_id, create_body['router']['tenant_id'])
-
- @decorators.idempotent_id('847257cc-6afd-4154-b8fb-af49f5670ce8')
- @test.requires_ext(extension='ext-gw-mode', service='network')
- @testtools.skipUnless(CONF.network.public_network_id,
- 'The public_network_id option must be specified.')
- def test_create_router_with_default_snat_value(self):
- # Create a router with default snat rule
- router = self._create_router(
- external_network_id=CONF.network.public_network_id)
- self._verify_router_gateway(
- router['id'], {'network_id': CONF.network.public_network_id,
- 'enable_snat': True})
-
- @decorators.idempotent_id('ea74068d-09e9-4fd7-8995-9b6a1ace920f')
- @test.requires_ext(extension='ext-gw-mode', service='network')
- @testtools.skipUnless(CONF.network.public_network_id,
- 'The public_network_id option must be specified.')
- def test_create_router_with_snat_explicit(self):
- name = data_utils.rand_name('snat-router')
- # Create a router enabling snat attributes
- enable_snat_states = [False, True]
- for enable_snat in enable_snat_states:
- external_gateway_info = {
- 'network_id': CONF.network.public_network_id,
- 'enable_snat': enable_snat}
- create_body = self.admin_routers_client.create_router(
- name=name, external_gateway_info=external_gateway_info)
- self.addCleanup(self.admin_routers_client.delete_router,
- create_body['router']['id'])
- # Verify snat attributes after router creation
- self._verify_router_gateway(create_body['router']['id'],
- exp_ext_gw_info=external_gateway_info)
-
@decorators.attr(type='smoke')
@decorators.idempotent_id('b42e6e39-2e37-49cc-a6f4-8467e940900a')
def test_add_remove_router_interface_with_subnet_id(self):
@@ -153,8 +129,8 @@
interface = self.routers_client.add_router_interface(
router['id'],
port_id=port_body['port']['id'])
- self.addCleanup(self._remove_router_interface_with_port_id,
- router['id'], port_body['port']['id'])
+ self.addCleanup(self.routers_client.remove_router_interface,
+ router['id'], port_id=port_body['port']['id'])
self.assertIn('subnet_id', interface.keys())
self.assertIn('port_id', interface.keys())
# Verify router id is equal to device id in port details
@@ -180,7 +156,7 @@
self.assertEqual(len(list_body['ports']), 1)
gw_port = list_body['ports'][0]
fixed_ips = gw_port['fixed_ips']
- self.assertGreaterEqual(len(fixed_ips), 1)
+ self.assertNotEmpty(fixed_ips)
# Assert that all of the IPs from the router gateway port
# are allocated from a valid public subnet.
public_net_body = self.admin_networks_client.show_network(
@@ -190,55 +166,6 @@
subnet_id = fixed_ip['subnet_id']
self.assertIn(subnet_id, public_subnet_ids)
- @decorators.idempotent_id('6cc285d8-46bf-4f36-9b1a-783e3008ba79')
- @testtools.skipUnless(CONF.network.public_network_id,
- 'The public_network_id option must be specified.')
- def test_update_router_set_gateway(self):
- router = self._create_router()
- self.routers_client.update_router(
- router['id'],
- external_gateway_info={
- 'network_id': CONF.network.public_network_id})
- # Verify operation - router
- self._verify_router_gateway(
- router['id'],
- {'network_id': CONF.network.public_network_id})
- self._verify_gateway_port(router['id'])
-
- @decorators.idempotent_id('b386c111-3b21-466d-880c-5e72b01e1a33')
- @test.requires_ext(extension='ext-gw-mode', service='network')
- @testtools.skipUnless(CONF.network.public_network_id,
- 'The public_network_id option must be specified.')
- def test_update_router_set_gateway_with_snat_explicit(self):
- router = self._create_router()
- self.admin_routers_client.update_router(
- router['id'],
- external_gateway_info={
- 'network_id': CONF.network.public_network_id,
- 'enable_snat': True})
- self._verify_router_gateway(
- router['id'],
- {'network_id': CONF.network.public_network_id,
- 'enable_snat': True})
- self._verify_gateway_port(router['id'])
-
- @decorators.idempotent_id('96536bc7-8262-4fb2-9967-5c46940fa279')
- @test.requires_ext(extension='ext-gw-mode', service='network')
- @testtools.skipUnless(CONF.network.public_network_id,
- 'The public_network_id option must be specified.')
- def test_update_router_set_gateway_without_snat(self):
- router = self._create_router()
- self.admin_routers_client.update_router(
- router['id'],
- external_gateway_info={
- 'network_id': CONF.network.public_network_id,
- 'enable_snat': False})
- self._verify_router_gateway(
- router['id'],
- {'network_id': CONF.network.public_network_id,
- 'enable_snat': False})
- self._verify_gateway_port(router['id'])
-
@decorators.idempotent_id('cbe42f84-04c2-11e7-8adb-fa163e4fa634')
@test.requires_ext(extension='ext-gw-mode', service='network')
@testtools.skipUnless(CONF.network.public_network_id,
@@ -270,39 +197,6 @@
'external_fixed_ips'][0]['ip_address'],
fixed_ip['ip_address'])
- @decorators.idempotent_id('ad81b7ee-4f81-407b-a19c-17e623f763e8')
- @testtools.skipUnless(CONF.network.public_network_id,
- 'The public_network_id option must be specified.')
- def test_update_router_unset_gateway(self):
- router = self._create_router(
- external_network_id=CONF.network.public_network_id)
- self.routers_client.update_router(router['id'],
- external_gateway_info={})
- self._verify_router_gateway(router['id'])
- # No gateway port expected
- list_body = self.admin_ports_client.list_ports(
- network_id=CONF.network.public_network_id,
- device_id=router['id'])
- self.assertFalse(list_body['ports'])
-
- @decorators.idempotent_id('f2faf994-97f4-410b-a831-9bc977b64374')
- @test.requires_ext(extension='ext-gw-mode', service='network')
- @testtools.skipUnless(CONF.network.public_network_id,
- 'The public_network_id option must be specified.')
- def test_update_router_reset_gateway_without_snat(self):
- router = self._create_router(
- external_network_id=CONF.network.public_network_id)
- self.admin_routers_client.update_router(
- router['id'],
- external_gateway_info={
- 'network_id': CONF.network.public_network_id,
- 'enable_snat': False})
- self._verify_router_gateway(
- router['id'],
- {'network_id': CONF.network.public_network_id,
- 'enable_snat': False})
- self._verify_gateway_port(router['id'])
-
@decorators.idempotent_id('c86ac3a8-50bd-4b00-a6b8-62af84a0765c')
@test.requires_ext(extension='extraroute', service='network')
def test_update_delete_extra_route(self):
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index fdd8dd8..72face8 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -14,9 +14,8 @@
# under the License.
import netaddr
-import testtools
-from tempest.api.network import base_routers as base
+from tempest.api.network import base
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
@@ -26,7 +25,7 @@
CONF = config.CONF
-class RoutersNegativeTest(base.BaseRouterTest):
+class RoutersNegativeTest(base.BaseNetworkTest):
@classmethod
def skip_checks(cls):
@@ -75,37 +74,15 @@
network_name=data_utils.rand_name('router-network02-'))
subnet01 = self.create_subnet(network01)
subnet02 = self.create_subnet(network02)
- self._add_router_interface_with_subnet_id(self.router['id'],
- subnet01['id'])
+ interface = self.routers_client.add_router_interface(
+ self.router['id'], subnet_id=subnet01['id'])
+ self.addCleanup(self.routers_client.remove_router_interface,
+ self.router['id'], subnet_id=subnet01['id'])
+ self.assertEqual(subnet01['id'], interface['subnet_id'])
self.assertRaises(lib_exc.BadRequest,
- self._add_router_interface_with_subnet_id,
+ self.routers_client.add_router_interface,
self.router['id'],
- subnet02['id'])
-
- @decorators.attr(type=['negative'])
- @decorators.idempotent_id('7101cc02-058a-11e7-93e1-fa163e4fa634')
- @test.requires_ext(extension='ext-gw-mode', service='network')
- @testtools.skipUnless(CONF.network.public_network_id,
- 'The public_network_id option must be specified.')
- def test_router_set_gateway_used_ip_returns_409(self):
- # At first create a address from public_network_id
- port = self.admin_ports_client.create_port(
- network_id=CONF.network.public_network_id)['port']
- self.addCleanup(self.admin_ports_client.delete_port,
- port_id=port['id'])
- # Add used ip and subnet_id in external_fixed_ips
- fixed_ip = {
- 'subnet_id': port['fixed_ips'][0]['subnet_id'],
- 'ip_address': port['fixed_ips'][0]['ip_address']
- }
- external_gateway_info = {
- 'network_id': CONF.network.public_network_id,
- 'external_fixed_ips': [fixed_ip]
- }
- # Create a router and set gateway to used ip
- self.assertRaises(lib_exc.Conflict,
- self.admin_routers_client.create_router,
- external_gateway_info=external_gateway_info)
+ subnet_id=subnet02['id'])
@decorators.attr(type=['negative'])
@decorators.idempotent_id('04df80f9-224d-47f5-837a-bf23e33d1c20')
@@ -142,7 +119,7 @@
_ip_version = 6
-class DvrRoutersNegativeTest(base.BaseRouterTest):
+class DvrRoutersNegativeTest(base.BaseNetworkTest):
@classmethod
def skip_checks(cls):
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 0d5e230..a121864 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -83,7 +83,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('bfd128e5-3c92-44b6-9d66-7fe29d22c802')
def test_create_list_update_show_delete_security_group(self):
- group_create_body, name = self._create_security_group()
+ group_create_body, _ = self._create_security_group()
# List security groups and verify if created group is there in response
list_body = self.security_groups_client.list_security_groups()
diff --git a/tempest/api/network/test_tags.py b/tempest/api/network/test_tags.py
new file mode 100644
index 0000000..1f3a7c4
--- /dev/null
+++ b/tempest/api/network/test_tags.py
@@ -0,0 +1,90 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.network import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from tempest import test
+
+
+class TagsTest(base.BaseNetworkTest):
+ """Tests the following operations in the tags API:
+
+ Update all tags.
+ Delete all tags.
+ Check tag existence.
+ Create a tag.
+ List tags.
+ Remove a tag.
+
+ v2.0 of the Neutron API is assumed. The tag extension allows users to set
+ tags on their networks. The extension supports networks only.
+ """
+
+ @classmethod
+ def skip_checks(cls):
+ super(TagsTest, cls).skip_checks()
+ if not test.is_extension_enabled('tag', 'network'):
+ msg = "tag extension not enabled."
+ raise cls.skipException(msg)
+
+ @classmethod
+ def resource_setup(cls):
+ super(TagsTest, cls).resource_setup()
+ cls.network = cls.create_network()
+
+ @decorators.idempotent_id('ee76bfaf-ac94-4d74-9ecc-4bbd4c583cb1')
+ def test_create_list_show_update_delete_tags(self):
+ # Validate that creating a tag on a network resource works.
+ tag_name = data_utils.rand_name(self.__class__.__name__ + '-Tag')
+ self.tags_client.create_tag('networks', self.network['id'], tag_name)
+ self.addCleanup(self.tags_client.delete_all_tags, 'networks',
+ self.network['id'])
+ self.tags_client.check_tag_existence('networks', self.network['id'],
+ tag_name)
+
+ # Validate that listing tags on a network resource works.
+ retrieved_tags = self.tags_client.list_tags(
+ 'networks', self.network['id'])['tags']
+ self.assertEqual([tag_name], retrieved_tags)
+
+ # Generate 3 new tag names.
+ replace_tags = [data_utils.rand_name(
+ self.__class__.__name__ + '-Tag') for _ in range(3)]
+
+ # Replace the current tag with the 3 new tags and validate that the
+ # network resource has the 3 new tags.
+ updated_tags = self.tags_client.update_all_tags(
+ 'networks', self.network['id'], replace_tags)['tags']
+ self.assertEqual(3, len(updated_tags))
+ self.assertEqual(set(replace_tags), set(updated_tags))
+
+ # Delete the first tag and check that it has been removed.
+ self.tags_client.delete_tag(
+ 'networks', self.network['id'], replace_tags[0])
+ self.assertRaises(lib_exc.NotFound,
+ self.tags_client.check_tag_existence, 'networks',
+ self.network['id'], replace_tags[0])
+ for i in range(1, 3):
+ self.tags_client.check_tag_existence(
+ 'networks', self.network['id'], replace_tags[i])
+
+ # Delete all the remaining tags and check that they have been removed.
+ self.tags_client.delete_all_tags('networks', self.network['id'])
+ for i in range(1, 3):
+ self.assertRaises(lib_exc.NotFound,
+ self.tags_client.check_tag_existence, 'networks',
+ self.network['id'], replace_tags[i])
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 2bac8d3..13614cb 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -43,8 +43,7 @@
for cont in containers:
try:
params = {'limit': 9999, 'format': 'json'}
- resp, objlist = container_client.list_container_contents(
- cont, params)
+ _, objlist = container_client.list_container_contents(cont, params)
# delete every object in the container
for obj in objlist:
test_utils.call_and_ignore_notfound_exc(
diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py
index 0a72d75..e765414 100644
--- a/tempest/api/object_storage/test_account_bulk.py
+++ b/tempest/api/object_storage/test_account_bulk.py
@@ -112,7 +112,7 @@
self._upload_archive(filepath)
data = '%s/%s\n%s' % (container_name, object_name, container_name)
- resp, body = self.bulk_client.delete_bulk_data(data=data)
+ resp, _ = self.bulk_client.delete_bulk_data(data=data)
# When deleting multiple files using the bulk operation, the response
# does not contain 'content-length' header. This is the special case,
@@ -138,7 +138,7 @@
data = '%s/%s\n%s' % (container_name, object_name, container_name)
- resp, body = self.bulk_client.delete_bulk_data_with_post(data=data)
+ resp, _ = self.bulk_client.delete_bulk_data_with_post(data=data)
# When deleting multiple files using the bulk operation, the response
# does not contain 'content-length' header. This is the special case,
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index e54b6e7..9e62046 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -101,7 +101,7 @@
# Check only the format of common headers with custom matcher
self.assertThat(resp, custom_matchers.AreAllWellFormatted())
- self.assertEqual(len(container_list), 0)
+ self.assertEmpty(container_list)
@decorators.idempotent_id('1c7efa35-e8a2-4b0b-b5ff-862c7fd83704')
def test_list_containers_with_format_json(self):
@@ -135,7 +135,7 @@
not CONF.object_storage_feature_enabled.discoverability,
'Discoverability function is disabled')
def test_list_extensions(self):
- resp, extensions = self.capabilities_client.list_capabilities()
+ resp, _ = self.capabilities_client.list_capabilities()
self.assertThat(resp, custom_matchers.AreAllWellFormatted())
@@ -162,7 +162,7 @@
self.account_client.list_account_containers(params=params)
self.assertHeaders(resp, 'Account', 'GET')
- self.assertEqual(len(container_list), 0)
+ self.assertEmpty(container_list)
params = {'marker': self.containers[self.containers_count // 2]}
resp, container_list = \
@@ -182,7 +182,7 @@
resp, container_list = \
self.account_client.list_account_containers(params=params)
self.assertHeaders(resp, 'Account', 'GET')
- self.assertEqual(len(container_list), 0)
+ self.assertEmpty(container_list)
params = {'end_marker': self.containers[self.containers_count // 2]}
resp, container_list = \
@@ -297,7 +297,7 @@
create_update_metadata=metadata)
self.assertHeaders(resp, 'Account', 'POST')
- resp, body = self.account_client.list_account_metadata()
+ resp, _ = self.account_client.list_account_metadata()
self.assertIn('x-account-meta-test-account-meta1', resp)
self.assertEqual(resp['x-account-meta-test-account-meta1'],
metadata['test-account-meta1'])
@@ -352,7 +352,7 @@
self.account_client.create_update_or_delete_account_metadata(
create_update_metadata=metadata_1)
metadata_2 = {'test-account-meta2': 'Meta2'}
- resp, body = (
+ resp, _ = (
self.account_client.create_update_or_delete_account_metadata(
create_update_metadata=metadata_2,
delete_metadata=metadata_1))
diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py
index d4e5ec5..4b66ebf 100644
--- a/tempest/api/object_storage/test_container_acl.py
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -41,10 +41,10 @@
tenant_name = self.os_roles_operator_alt.credentials.tenant_name
username = self.os_roles_operator_alt.credentials.username
cont_headers = {'X-Container-Read': tenant_name + ':' + username}
- resp_meta, body = self.os_roles_operator.container_client.\
- update_container_metadata(
+ resp_meta, _ = (
+ self.os_roles_operator.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
- metadata_prefix='')
+ metadata_prefix=''))
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')
@@ -68,10 +68,10 @@
tenant_name = self.os_roles_operator_alt.credentials.tenant_name
username = self.os_roles_operator_alt.credentials.username
cont_headers = {'X-Container-Write': tenant_name + ':' + username}
- resp_meta, body = self.os_roles_operator.container_client.\
- update_container_metadata(self.container_name,
- metadata=cont_headers,
- metadata_prefix='')
+ resp_meta, _ = (
+ self.os_roles_operator.container_client.update_container_metadata(
+ self.container_name, metadata=cont_headers,
+ metadata_prefix=''))
self.assertHeaders(resp_meta, 'Container', 'POST')
# set alternative authentication data; cannot simply use the
# other object client.
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index 9c9d821..655626c 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -65,8 +65,8 @@
def test_delete_object_without_using_creds(self):
# create object
object_name = data_utils.rand_name(name='Object')
- resp, _ = self.object_client.create_object(self.container_name,
- object_name, 'data')
+ self.object_client.create_object(self.container_name, object_name,
+ 'data')
# trying to delete object with empty headers
# X-Auth-Token is not provided
self.object_client.auth_provider.set_alt_auth_data(
@@ -134,7 +134,7 @@
# attempt to read object using non-authorized user
# update X-Container-Read metadata ACL
cont_headers = {'X-Container-Read': 'badtenant:baduser'}
- resp_meta, body = self.container_client.update_container_metadata(
+ resp_meta, _ = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
self.assertHeaders(resp_meta, 'Container', 'POST')
@@ -158,7 +158,7 @@
# attempt to write object using non-authorized user
# update X-Container-Write metadata ACL
cont_headers = {'X-Container-Write': 'badtenant:baduser'}
- resp_meta, body = self.container_client.update_container_metadata(
+ resp_meta, _ = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
self.assertHeaders(resp_meta, 'Container', 'POST')
@@ -183,7 +183,7 @@
cont_headers = {'X-Container-Read':
tenant_name + ':' + username,
'X-Container-Write': ''}
- resp_meta, body = self.container_client.update_container_metadata(
+ resp_meta, _ = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
self.assertHeaders(resp_meta, 'Container', 'POST')
@@ -208,7 +208,7 @@
cont_headers = {'X-Container-Read':
tenant_name + ':' + username,
'X-Container-Write': ''}
- resp_meta, body = self.container_client.update_container_metadata(
+ resp_meta, _ = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
self.assertHeaders(resp_meta, 'Container', 'POST')
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 2b5692d..76fe8d4 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -27,7 +27,7 @@
@decorators.idempotent_id('92139d73-7819-4db1-85f8-3f2f22a8d91f')
def test_create_container(self):
container_name = data_utils.rand_name(name='TestContainer')
- resp, body = self.container_client.create_container(container_name)
+ resp, _ = self.container_client.create_container(container_name)
self.containers.append(container_name)
self.assertHeaders(resp, 'Container', 'PUT')
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 9e01c26..378061a 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -124,9 +124,8 @@
# test GET on http://account_url/container_name
# we should retrieve a listing of objects
- resp, body = self.account_client.request("GET",
- self.container_name,
- headers={})
+ _, body = self.account_client.request("GET", self.container_name,
+ headers={})
self.assertIn(self.object_name, body.decode())
css = '<link rel="stylesheet" type="text/css" href="listings.css" />'
self.assertIn(css, body.decode())
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index 3c11a51..4cb1914 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -90,8 +90,7 @@
cont_client = [self.clients[c][0] for c in cont]
obj_client = [self.clients[c][1] for c in cont]
headers = make_headers(cont[1], cont_client[1])
- resp, body = \
- cont_client[0].put(str(cont[0]), body=None, headers=headers)
+ cont_client[0].put(str(cont[0]), body=None, headers=headers)
# create object in container
object_name = data_utils.rand_name(name='TestSyncObject')
data = object_name[::-1].encode() # Raw data, we need bytes
diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py
index 7768d23..ed1be90 100644
--- a/tempest/api/object_storage/test_object_expiry.py
+++ b/tempest/api/object_storage/test_object_expiry.py
@@ -54,8 +54,8 @@
# actually expire, so figure out how many secs in the future that is.
sleepy_time = int(resp['x-delete-at']) - int(time.time())
sleepy_time = sleepy_time if sleepy_time > 0 else 0
- resp, body = self.object_client.get_object(self.container_name,
- self.object_name)
+ resp, _ = self.object_client.get_object(self.container_name,
+ self.object_name)
self.assertHeaders(resp, 'Object', 'GET')
self.assertIn('x-delete-at', resp)
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 21ea6ae..b29a77f 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -48,7 +48,7 @@
data_segments = [data + str(i) for i in range(segments)]
# uploading segments
for i in range(segments):
- resp, _ = self.object_client.create_object_segments(
+ self.object_client.create_object_segments(
self.container_name, object_name, i, data_segments[i])
return object_name, data_segments
@@ -184,7 +184,7 @@
# create object with transfer_encoding
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.random_bytes(1024)
- status, _, resp_headers = self.object_client.put_object_with_chunk(
+ _, _, resp_headers = self.object_client.put_object_with_chunk(
container=self.container_name,
name=object_name,
contents=data_utils.chunkify(data, 512)
@@ -394,7 +394,7 @@
# update object metadata with x_object_manifest
# uploading segments
- object_name, data_segments = self._upload_segments()
+ object_name, _ = self._upload_segments()
# creating a manifest file
data_empty = ''
self.object_client.create_object(self.container_name,
@@ -414,7 +414,7 @@
self.container_name,
object_name)
self.assertIn('x-object-manifest', resp)
- self.assertNotEqual(len(resp['x-object-manifest']), 0)
+ self.assertNotEmpty(resp['x-object-manifest'])
@decorators.idempotent_id('0dbbe89c-6811-4d84-a2df-eca2bdd40c0e')
def test_update_object_metadata_with_x_object_metakey(self):
@@ -494,7 +494,7 @@
# get object metadata with x_object_manifest
# uploading segments
- object_name, data_segments = self._upload_segments()
+ object_name, _ = self._upload_segments()
# creating a manifest file
object_prefix = '%s/%s' % (self.container_name, object_name)
metadata = {'X-Object-Manifest': object_prefix}
@@ -520,11 +520,11 @@
self.assertTrue(resp['etag'].startswith('\"'))
self.assertTrue(resp['etag'].endswith('\"'))
self.assertTrue(resp['etag'].strip('\"').isalnum())
- self.assertTrue(re.match("^\d+\.?\d*\Z", resp['x-timestamp']))
- self.assertNotEqual(len(resp['content-type']), 0)
+ self.assertTrue(re.match(r"^\d+\.?\d*\Z", resp['x-timestamp']))
+ self.assertNotEmpty(resp['content-type'])
self.assertTrue(re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*",
resp['x-trans-id']))
- self.assertNotEqual(len(resp['date']), 0)
+ self.assertNotEmpty(resp['date'])
self.assertEqual(resp['accept-ranges'], 'bytes')
self.assertEqual(resp['x-object-manifest'],
'%s/%s' % (self.container_name, object_name))
@@ -612,11 +612,11 @@
self.assertTrue(resp['etag'].startswith('\"'))
self.assertTrue(resp['etag'].endswith('\"'))
self.assertTrue(resp['etag'].strip('\"').isalnum())
- self.assertTrue(re.match("^\d+\.?\d*\Z", resp['x-timestamp']))
- self.assertNotEqual(len(resp['content-type']), 0)
+ self.assertTrue(re.match(r"^\d+\.?\d*\Z", resp['x-timestamp']))
+ self.assertNotEmpty(resp['content-type'])
self.assertTrue(re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*",
resp['x-trans-id']))
- self.assertNotEqual(len(resp['date']), 0)
+ self.assertNotEmpty(resp['date'])
self.assertEqual(resp['accept-ranges'], 'bytes')
self.assertEqual(resp['x-object-manifest'],
'%s/%s' % (self.container_name, object_name))
@@ -955,7 +955,7 @@
local_data = "something different"
md5 = hashlib.md5(local_data.encode()).hexdigest()
headers = {'If-None-Match': md5}
- resp, body = self.object_client.get(url, headers=headers)
+ resp, _ = self.object_client.get(url, headers=headers)
self.assertHeaders(resp, 'Object', 'GET')
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
index 085ad13..894e42d 100644
--- a/tempest/api/object_storage/test_object_slo.py
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -127,7 +127,7 @@
# list static large object metadata using multipart manifest
object_name = self._create_large_object()
- resp, body = self.object_client.list_object_metadata(
+ resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
@@ -155,7 +155,7 @@
object_name = self._create_large_object()
params_del = {'multipart-manifest': 'delete'}
- resp, body = self.object_client.delete_object(
+ resp, _ = self.object_client.delete_object(
self.container_name,
object_name,
params=params_del)
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index 4b506f8..91bc677 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -128,7 +128,7 @@
url = self._get_temp_url(self.container_name,
self.object_name, "GET",
expires, key2)
- resp, body = self.object_client.get(url)
+ _, body = self.object_client.get(url)
self.assertEqual(body, self.content)
@decorators.idempotent_id('9b08dade-3571-4152-8a4f-a4f2a873a735')
@@ -168,7 +168,7 @@
expires, self.key)
# Testing a HEAD on this Temp URL
- resp, body = self.object_client.head(url)
+ resp, _ = self.object_client.head(url)
self.assertHeaders(resp, 'Object', 'HEAD')
@decorators.idempotent_id('9d9cfd90-708b-465d-802c-e4a8090b823d')
diff --git a/tempest/api/object_storage/test_object_temp_url_negative.py b/tempest/api/object_storage/test_object_temp_url_negative.py
index f4d63fd..3edaa86 100644
--- a/tempest/api/object_storage/test_object_temp_url_negative.py
+++ b/tempest/api/object_storage/test_object_temp_url_negative.py
@@ -46,7 +46,7 @@
@classmethod
def resource_cleanup(cls):
- resp, _ = cls.account_client.create_update_or_delete_account_metadata(
+ cls.account_client.create_update_or_delete_account_metadata(
delete_metadata=cls.metadata)
cls.delete_containers()
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
deleted file mode 100644
index d9d8017..0000000
--- a/tempest/api/orchestration/base.py
+++ /dev/null
@@ -1,169 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import os.path
-
-import yaml
-
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
-import tempest.test
-
-CONF = config.CONF
-
-
-class BaseOrchestrationTest(tempest.test.BaseTestCase):
- """Base test case class for all Orchestration API tests."""
-
- credentials = ['primary']
-
- @classmethod
- def skip_checks(cls):
- super(BaseOrchestrationTest, cls).skip_checks()
- if not CONF.service_available.heat:
- raise cls.skipException("Heat support is required")
-
- @classmethod
- def setup_credentials(cls):
- super(BaseOrchestrationTest, cls).setup_credentials()
- stack_owner_role = CONF.orchestration.stack_owner_role
- cls.os = cls.get_client_manager(roles=[stack_owner_role])
-
- @classmethod
- def setup_clients(cls):
- super(BaseOrchestrationTest, cls).setup_clients()
- cls.orchestration_client = cls.os_primary.orchestration_client
- cls.client = cls.orchestration_client
- cls.servers_client = cls.os_primary.servers_client
- cls.keypairs_client = cls.os_primary.keypairs_client
- cls.networks_client = cls.os_primary.networks_client
- cls.images_v2_client = cls.os_primary.image_client_v2
- cls.volumes_client = cls.os_primary.volumes_v2_client
-
- @classmethod
- def resource_setup(cls):
- super(BaseOrchestrationTest, cls).resource_setup()
- cls.build_timeout = CONF.orchestration.build_timeout
- cls.build_interval = CONF.orchestration.build_interval
- cls.stacks = []
- cls.keypairs = []
- cls.images = []
-
- @classmethod
- def create_stack(cls, stack_name, template_data, parameters=None,
- environment=None, files=None):
- if parameters is None:
- parameters = {}
- body = cls.client.create_stack(
- stack_name,
- template=template_data,
- parameters=parameters,
- environment=environment,
- files=files)
- stack_id = body.response['location'].split('/')[-1]
- stack_identifier = '%s/%s' % (stack_name, stack_id)
- cls.stacks.append(stack_identifier)
- return stack_identifier
-
- @classmethod
- def _clear_stacks(cls):
- for stack_identifier in cls.stacks:
- test_utils.call_and_ignore_notfound_exc(
- cls.client.delete_stack, stack_identifier)
-
- for stack_identifier in cls.stacks:
- test_utils.call_and_ignore_notfound_exc(
- cls.client.wait_for_stack_status, stack_identifier,
- 'DELETE_COMPLETE')
-
- @classmethod
- def _create_keypair(cls, name_start='keypair-heat-'):
- kp_name = data_utils.rand_name(name_start)
- body = cls.keypairs_client.create_keypair(name=kp_name)['keypair']
- cls.keypairs.append(kp_name)
- return body
-
- @classmethod
- def _clear_keypairs(cls):
- for kp_name in cls.keypairs:
- try:
- cls.keypairs_client.delete_keypair(kp_name)
- except Exception:
- pass
-
- @classmethod
- def _create_image(cls, name_start='image-heat-', container_format='bare',
- disk_format='iso'):
- image_name = data_utils.rand_name(name_start)
- body = cls.images_v2_client.create_image(image_name,
- container_format,
- disk_format)
- image_id = body['id']
- cls.images.append(image_id)
- return body
-
- @classmethod
- def _clear_images(cls):
- for image_id in cls.images:
- test_utils.call_and_ignore_notfound_exc(
- cls.images_v2_client.delete_image, image_id)
-
- @classmethod
- def read_template(cls, name, ext='yaml'):
- loc = ["stacks", "templates", "%s.%s" % (name, ext)]
- fullpath = os.path.join(os.path.dirname(__file__), *loc)
-
- with open(fullpath, "r") as f:
- content = f.read()
- return content
-
- @classmethod
- def load_template(cls, name, ext='yaml'):
- loc = ["stacks", "templates", "%s.%s" % (name, ext)]
- fullpath = os.path.join(os.path.dirname(__file__), *loc)
-
- with open(fullpath, "r") as f:
- return yaml.safe_load(f)
-
- @classmethod
- def resource_cleanup(cls):
- cls._clear_stacks()
- cls._clear_keypairs()
- cls._clear_images()
- super(BaseOrchestrationTest, cls).resource_cleanup()
-
- @staticmethod
- def stack_output(stack, output_key):
- """Return a stack output value for a given key."""
- return next((o['output_value'] for o in stack['outputs']
- if o['output_key'] == output_key), None)
-
- def assert_fields_in_dict(self, obj, *fields):
- for field in fields:
- self.assertIn(field, obj)
-
- def list_resources(self, stack_identifier):
- """Get a dict mapping of resource names to types."""
- resources = self.client.list_resources(stack_identifier)['resources']
- self.assertIsInstance(resources, list)
- for res in resources:
- self.assert_fields_in_dict(res, 'logical_resource_id',
- 'resource_type', 'resource_status',
- 'updated_time')
-
- return dict((r['resource_name'], r['resource_type'])
- for r in resources)
-
- def get_stack_output(self, stack_identifier, output_key):
- body = self.client.show_stack(stack_identifier)['stack']
- return self.stack_output(body, output_key)
diff --git a/tempest/api/orchestration/stacks/__init__.py b/tempest/api/orchestration/stacks/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api/orchestration/stacks/__init__.py
+++ /dev/null
diff --git a/tempest/api/orchestration/stacks/templates/cinder_basic.yaml b/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
deleted file mode 100644
index 61c271c..0000000
--- a/tempest/api/orchestration/stacks/templates/cinder_basic.yaml
+++ /dev/null
@@ -1,33 +0,0 @@
-heat_template_version: 2013-05-23
-
-parameters:
- volume_size:
- type: number
- default: 1
-
-resources:
- volume:
- type: OS::Cinder::Volume
- properties:
- size: { get_param: volume_size }
- description: a descriptive description
- name: volume_name
-
-outputs:
- status:
- description: status
- value: { get_attr: ['volume', 'status'] }
-
- size:
- description: size
- value: { get_attr: ['volume', 'size'] }
-
- display_description:
- description: display_description
- value: { get_attr: ['volume', 'display_description'] }
-
- display_name:
- value: { get_attr: ['volume', 'display_name'] }
-
- volume_id:
- value: { get_resource: volume }
diff --git a/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml b/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
deleted file mode 100644
index 0bc6d69..0000000
--- a/tempest/api/orchestration/stacks/templates/cinder_basic_delete_retain.yaml
+++ /dev/null
@@ -1,34 +0,0 @@
-heat_template_version: 2013-05-23
-
-parameters:
- volume_size:
- type: number
- default: 1
-
-resources:
- volume:
- deletion_policy: 'Retain'
- type: OS::Cinder::Volume
- properties:
- size: { get_param: volume_size }
- description: a descriptive description
- name: volume_name
-
-outputs:
- status:
- description: status
- value: { get_attr: ['volume', 'status'] }
-
- size:
- description: size
- value: { get_attr: ['volume', 'size'] }
-
- display_description:
- description: display_description
- value: { get_attr: ['volume', 'display_description'] }
-
- display_name:
- value: { get_attr: ['volume', 'display_name'] }
-
- volume_id:
- value: { get_resource: volume }
diff --git a/tempest/api/orchestration/stacks/templates/neutron_basic.yaml b/tempest/api/orchestration/stacks/templates/neutron_basic.yaml
deleted file mode 100644
index ccb1b54..0000000
--- a/tempest/api/orchestration/stacks/templates/neutron_basic.yaml
+++ /dev/null
@@ -1,72 +0,0 @@
-heat_template_version: '2013-05-23'
-description: |
- Template which creates single EC2 instance
-parameters:
- KeyName:
- type: string
- InstanceType:
- type: string
- ImageId:
- type: string
- SubNetCidr:
- type: string
- ExternalNetworkId:
- type: string
- DNSServers:
- type: comma_delimited_list
- timeout:
- type: number
-resources:
- Network:
- type: OS::Neutron::Net
- properties:
- name: NewNetwork
- Subnet:
- type: OS::Neutron::Subnet
- properties:
- network_id: {Ref: Network}
- name: NewSubnet
- ip_version: 4
- cidr: { get_param: SubNetCidr }
- dns_nameservers: { get_param: DNSServers }
- Router:
- type: OS::Neutron::Router
- properties:
- name: NewRouter
- admin_state_up: true
- external_gateway_info:
- network: {get_param: ExternalNetworkId}
- RouterInterface:
- type: OS::Neutron::RouterInterface
- properties:
- router_id: {get_resource: Router}
- subnet_id: {get_resource: Subnet}
- Server:
- type: OS::Nova::Server
- metadata:
- Name: SmokeServerNeutron
- properties:
- image: {get_param: ImageId}
- flavor: {get_param: InstanceType}
- key_name: {get_param: KeyName}
- networks:
- - network: {get_resource: Network}
- user_data_format: RAW
- user_data:
- str_replace:
- template: |
- #!/bin/sh -v
-
- SIGNAL_DATA='{"Status": "SUCCESS", "Reason": "SmokeServerNeutron created", "Data": "Application has completed configuration.", "UniqueId": "00000"}'
- while ! curl --insecure --fail -X PUT -H 'Content-Type:' --data-binary "$SIGNAL_DATA" \
- 'wait_handle' ; do sleep 3; done
- params:
- wait_handle: {get_resource: WaitHandleNeutron}
- WaitHandleNeutron:
- type: AWS::CloudFormation::WaitConditionHandle
- WaitCondition:
- type: AWS::CloudFormation::WaitCondition
- depends_on: Server
- properties:
- Handle: {get_resource: WaitHandleNeutron}
- Timeout: {get_param: timeout}
diff --git a/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml b/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml
deleted file mode 100644
index 4f9df91..0000000
--- a/tempest/api/orchestration/stacks/templates/non_empty_stack.yaml
+++ /dev/null
@@ -1,36 +0,0 @@
-HeatTemplateFormatVersion: '2012-12-12'
-Description: |
- Template which creates some simple resources
-Parameters:
- trigger:
- Type: String
- Default: not_yet
- image:
- Type: String
- flavor:
- Type: String
-Resources:
- fluffy:
- Type: AWS::AutoScaling::LaunchConfiguration
- Metadata:
- kittens:
- - Tom
- - Stinky
- Properties:
- ImageId: {Ref: image}
- InstanceType: {Ref: flavor}
- UserData:
- Fn::Replace:
- - variable_a: {Ref: trigger}
- variable_b: bee
- - |
- A == variable_a
- B == variable_b
-Outputs:
- fluffy:
- Description: "fluffies irc nick"
- Value:
- Fn::Replace:
- - nick: {Ref: fluffy}
- - |
- #nick
diff --git a/tempest/api/orchestration/stacks/templates/nova_keypair.json b/tempest/api/orchestration/stacks/templates/nova_keypair.json
deleted file mode 100644
index 63d3817..0000000
--- a/tempest/api/orchestration/stacks/templates/nova_keypair.json
+++ /dev/null
@@ -1,48 +0,0 @@
-{
- "AWSTemplateFormatVersion" : "2010-09-09",
- "Description" : "Template which create two key pairs.",
- "Parameters" : {
- "KeyPairName1": {
- "Type": "String",
- "Default": "testkey1"
- },
- "KeyPairName2": {
- "Type": "String",
- "Default": "testkey2"
- }
- },
- "Resources" : {
- "KeyPairSavePrivate": {
- "Type": "OS::Nova::KeyPair",
- "Properties": {
- "name" : { "Ref" : "KeyPairName1" },
- "save_private_key": true
- }
- },
- "KeyPairDontSavePrivate": {
- "Type": "OS::Nova::KeyPair",
- "Properties": {
- "name" : { "Ref" : "KeyPairName2" },
- "save_private_key": false
- }
- }
- },
- "Outputs": {
- "KeyPair_PublicKey": {
- "Description": "Public Key of generated keypair.",
- "Value": { "Fn::GetAtt" : ["KeyPairSavePrivate", "public_key"] }
- },
- "KeyPair_PrivateKey": {
- "Description": "Private Key of generated keypair.",
- "Value": { "Fn::GetAtt" : ["KeyPairSavePrivate", "private_key"] }
- },
- "KeyPairDontSavePrivate_PublicKey": {
- "Description": "Public Key of generated keypair.",
- "Value": { "Fn::GetAtt" : ["KeyPairDontSavePrivate", "public_key"] }
- },
- "KeyPairDontSavePrivate_PrivateKey": {
- "Description": "Private Key of generated keypair.",
- "Value": { "Fn::GetAtt" : ["KeyPairDontSavePrivate", "private_key"] }
- }
- }
-}
diff --git a/tempest/api/orchestration/stacks/templates/nova_keypair.yaml b/tempest/api/orchestration/stacks/templates/nova_keypair.yaml
deleted file mode 100644
index 81ad99c..0000000
--- a/tempest/api/orchestration/stacks/templates/nova_keypair.yaml
+++ /dev/null
@@ -1,43 +0,0 @@
-heat_template_version: 2013-05-23
-
-description: >
- Template which creates two key pairs.
-
-parameters:
- KeyPairName1:
- type: string
- default: testkey
-
- KeyPairName2:
- type: string
- default: testkey2
-
-resources:
- KeyPairSavePrivate:
- type: OS::Nova::KeyPair
- properties:
- name: { get_param: KeyPairName1 }
- save_private_key: true
-
- KeyPairDontSavePrivate:
- type: OS::Nova::KeyPair
- properties:
- name: { get_param: KeyPairName2 }
- save_private_key: false
-
-outputs:
- KeyPair_PublicKey:
- description: Public Key of generated keypair
- value: { get_attr: [KeyPairSavePrivate, public_key] }
-
- KeyPair_PrivateKey:
- description: Private Key of generated keypair
- value: { get_attr: [KeyPairSavePrivate, private_key] }
-
- KeyPairDontSavePrivate_PublicKey:
- description: Public Key of generated keypair
- value: { get_attr: [KeyPairDontSavePrivate, public_key] }
-
- KeyPairDontSavePrivate_PrivateKey:
- description: Private Key of generated keypair
- value: { get_attr: [KeyPairDontSavePrivate, private_key] }
diff --git a/tempest/api/orchestration/stacks/templates/random_string.yaml b/tempest/api/orchestration/stacks/templates/random_string.yaml
deleted file mode 100644
index dfd2342..0000000
--- a/tempest/api/orchestration/stacks/templates/random_string.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-heat_template_version: 2013-05-23
-
-parameters:
- random_length:
- type: number
- default: 10
-
-resources:
- random:
- type: OS::Heat::RandomString
- properties:
- length: {get_param: random_length}
-
-outputs:
- random_length:
- value: {get_param: random_length}
- random_value:
- value: {get_attr: [random, value]}
diff --git a/tempest/api/orchestration/stacks/templates/swift_basic.yaml b/tempest/api/orchestration/stacks/templates/swift_basic.yaml
deleted file mode 100644
index 713f8bc..0000000
--- a/tempest/api/orchestration/stacks/templates/swift_basic.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-heat_template_version: 2013-05-23
-description: Template which creates a Swift container resource
-
-resources:
- SwiftContainerWebsite:
- deletion_policy: "Delete"
- type: OS::Swift::Container
- properties:
- X-Container-Read: ".r:*"
- X-Container-Meta:
- web-index: "index.html"
- web-error: "error.html"
-
- SwiftContainer:
- type: OS::Swift::Container
-
-outputs:
- WebsiteURL:
- description: "URL for website hosted on S3"
- value: { get_attr: [SwiftContainer, WebsiteURL] }
- DomainName:
- description: "Domain of Swift host"
- value: { get_attr: [SwiftContainer, DomainName] }
diff --git a/tempest/api/orchestration/stacks/test_environment.py b/tempest/api/orchestration/stacks/test_environment.py
deleted file mode 100644
index c8a9aa7..0000000
--- a/tempest/api/orchestration/stacks/test_environment.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-
-class StackEnvironmentTest(base.BaseOrchestrationTest):
-
- @decorators.idempotent_id('37d4346b-1abd-4442-b7b1-2a4e5749a1e3')
- def test_environment_parameter(self):
- """Test passing a stack parameter via the environment."""
- stack_name = data_utils.rand_name('heat')
- template = self.read_template('random_string')
- environment = {'parameters': {'random_length': 20}}
-
- stack_identifier = self.create_stack(stack_name, template,
- environment=environment)
- self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-
- random_len = self.get_stack_output(stack_identifier, 'random_length')
- self.assertEqual(20, random_len)
-
- random_value = self.get_stack_output(stack_identifier, 'random_value')
- self.assertEqual(20, len(random_value))
-
- @decorators.idempotent_id('73bce717-ad22-4853-bbef-6ed89b632701')
- def test_environment_provider_resource(self):
- """Test passing resource_registry defining a provider resource."""
- stack_name = data_utils.rand_name('heat')
- template = '''
-heat_template_version: 2013-05-23
-resources:
- random:
- type: My:Random::String
-outputs:
- random_value:
- value: {get_attr: [random, random_value]}
-'''
- environment = {'resource_registry':
- {'My:Random::String': 'my_random.yaml'}}
- files = {'my_random.yaml': self.read_template('random_string')}
-
- stack_identifier = self.create_stack(stack_name, template,
- environment=environment,
- files=files)
- self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-
- # random_string.yaml specifies a length of 10
- random_value = self.get_stack_output(stack_identifier, 'random_value')
- random_string_template = self.load_template('random_string')
- expected_length = random_string_template['parameters'][
- 'random_length']['default']
- self.assertEqual(expected_length, len(random_value))
-
- @decorators.idempotent_id('9d682e5a-f4bb-47d5-8472-9d3cacb855df')
- def test_files_provider_resource(self):
- """Test untyped defining of a provider resource via "files"."""
- # It's also possible to specify the filename directly in the template.
- # without adding the type alias to resource_registry
- stack_name = data_utils.rand_name('heat')
- template = '''
-heat_template_version: 2013-05-23
-resources:
- random:
- type: my_random.yaml
-outputs:
- random_value:
- value: {get_attr: [random, random_value]}
-'''
- files = {'my_random.yaml': self.read_template('random_string')}
-
- stack_identifier = self.create_stack(stack_name, template,
- files=files)
- self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-
- # random_string.yaml specifies a length of 10
- random_value = self.get_stack_output(stack_identifier, 'random_value')
- random_string_template = self.load_template('random_string')
- expected_length = random_string_template['parameters'][
- 'random_length']['default']
- self.assertEqual(expected_length, len(random_value))
diff --git a/tempest/api/orchestration/stacks/test_limits.py b/tempest/api/orchestration/stacks/test_limits.py
deleted file mode 100644
index 9c9d4f9..0000000
--- a/tempest/api/orchestration/stacks/test_limits.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-from tempest.lib import exceptions as lib_exc
-
-CONF = config.CONF
-
-
-class TestServerStackLimits(base.BaseOrchestrationTest):
-
- @decorators.idempotent_id('ec9bed71-c460-45c9-ab98-295caa9fd76b')
- def test_exceed_max_template_size_fails(self):
- stack_name = data_utils.rand_name('heat')
- fill = 'A' * CONF.orchestration.max_template_size
- template = '''
-HeatTemplateFormatVersion: '2012-12-12'
-Description: '%s'
-Outputs:
- Foo: bar''' % fill
- ex = self.assertRaises(lib_exc.BadRequest, self.create_stack,
- stack_name, template)
- self.assertIn('exceeds maximum allowed size', str(ex))
-
- @decorators.idempotent_id('d1b83e73-7cad-4a22-9839-036548c5387c')
- def test_exceed_max_resources_per_stack(self):
- stack_name = data_utils.rand_name('heat')
- # Create a big template, one resource more than the limit
- template = 'heat_template_version: \'2013-05-23\'\nresources:\n'
- rsrc_snippet = ' random%s:\n type: \'OS::Heat::RandomString\'\n'
- num_resources = CONF.orchestration.max_resources_per_stack + 1
- for i in range(num_resources):
- template += rsrc_snippet % i
-
- ex = self.assertRaises(lib_exc.BadRequest, self.create_stack,
- stack_name, template)
- self.assertIn('Maximum resources per stack exceeded', str(ex))
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
deleted file mode 100644
index 36881bf..0000000
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ /dev/null
@@ -1,196 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import netaddr
-from oslo_log import log as logging
-
-from tempest.api.orchestration import base
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-from tempest.lib import exceptions
-from tempest import test
-
-CONF = config.CONF
-
-LOG = logging.getLogger(__name__)
-
-
-class NeutronResourcesTestJSON(base.BaseOrchestrationTest):
-
- @classmethod
- def skip_checks(cls):
- super(NeutronResourcesTestJSON, cls).skip_checks()
- if not CONF.service_available.neutron:
- raise cls.skipException("Neutron support is required")
-
- @classmethod
- def setup_credentials(cls):
- cls.set_network_resources()
- super(NeutronResourcesTestJSON, cls).setup_credentials()
-
- @classmethod
- def setup_clients(cls):
- super(NeutronResourcesTestJSON, cls).setup_clients()
- cls.subnets_client = cls.os_primary.subnets_client
- cls.ports_client = cls.os_primary.ports_client
- cls.routers_client = cls.os_primary.routers_client
-
- @classmethod
- def resource_setup(cls):
- super(NeutronResourcesTestJSON, cls).resource_setup()
- cls.neutron_basic_template = cls.load_template('neutron_basic')
- cls.stack_name = data_utils.rand_name('heat')
- template = cls.read_template('neutron_basic')
- cls.keypair_name = (CONF.orchestration.keypair_name or
- cls._create_keypair()['name'])
- cls.external_network_id = CONF.network.public_network_id
-
- tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
- mask_bits = CONF.network.project_network_mask_bits
- cls.subnet_cidr = tenant_cidr.subnet(mask_bits).next()
-
- # create the stack
- cls.stack_identifier = cls.create_stack(
- cls.stack_name,
- template,
- parameters={
- 'KeyName': cls.keypair_name,
- 'InstanceType': CONF.orchestration.instance_type,
- 'ImageId': CONF.compute.image_ref,
- 'ExternalNetworkId': cls.external_network_id,
- 'timeout': CONF.orchestration.build_timeout,
- 'DNSServers': CONF.network.dns_servers,
- 'SubNetCidr': str(cls.subnet_cidr)
- })
- cls.stack_id = cls.stack_identifier.split('/')[1]
- try:
- cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
- resources = (cls.client.list_resources(cls.stack_identifier)
- ['resources'])
- except exceptions.TimeoutException:
- if CONF.compute_feature_enabled.console_output:
- # attempt to log the server console to help with debugging
- # the cause of the server not signalling the waitcondition
- # to heat.
- body = cls.client.show_resource(cls.stack_identifier,
- 'Server')
- server_id = body.get('physical_resource_id')
- if server_id:
- LOG.debug('Console output for %s', server_id)
- output = cls.servers_client.get_console_output(
- server_id)['output']
- LOG.debug(output)
- else:
- LOG.debug('Server resource is %s', body)
- raise # original exception
-
- cls.test_resources = {}
- for resource in resources:
- cls.test_resources[resource['logical_resource_id']] = resource
-
- @decorators.idempotent_id('f9e2664c-bc44-4eef-98b6-495e4f9d74b3')
- def test_created_resources(self):
- """Verifies created neutron resources."""
- resources = [('Network', self.neutron_basic_template['resources'][
- 'Network']['type']),
- ('Subnet', self.neutron_basic_template['resources'][
- 'Subnet']['type']),
- ('RouterInterface', self.neutron_basic_template[
- 'resources']['RouterInterface']['type']),
- ('Server', self.neutron_basic_template['resources'][
- 'Server']['type'])]
- for resource_name, resource_type in resources:
- resource = self.test_resources.get(resource_name, None)
- self.assertIsInstance(resource, dict)
- self.assertEqual(resource_name, resource['logical_resource_id'])
- self.assertEqual(resource_type, resource['resource_type'])
- self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
-
- @decorators.idempotent_id('c572b915-edb1-4e90-b196-c7199a6848c0')
- @test.services('network')
- def test_created_network(self):
- """Verifies created network."""
- network_id = self.test_resources.get('Network')['physical_resource_id']
- body = self.networks_client.show_network(network_id)
- network = body['network']
- self.assertIsInstance(network, dict)
- self.assertEqual(network_id, network['id'])
- self.assertEqual(self.neutron_basic_template['resources'][
- 'Network']['properties']['name'], network['name'])
-
- @decorators.idempotent_id('e8f84b96-f9d7-4684-ad5f-340203e9f2c2')
- @test.services('network')
- def test_created_subnet(self):
- """Verifies created subnet."""
- subnet_id = self.test_resources.get('Subnet')['physical_resource_id']
- body = self.subnets_client.show_subnet(subnet_id)
- subnet = body['subnet']
- network_id = self.test_resources.get('Network')['physical_resource_id']
- self.assertEqual(subnet_id, subnet['id'])
- self.assertEqual(network_id, subnet['network_id'])
- self.assertEqual(self.neutron_basic_template['resources'][
- 'Subnet']['properties']['name'], subnet['name'])
- self.assertEqual(sorted(CONF.network.dns_servers),
- sorted(subnet['dns_nameservers']))
- self.assertEqual(self.neutron_basic_template['resources'][
- 'Subnet']['properties']['ip_version'], subnet['ip_version'])
- self.assertEqual(str(self.subnet_cidr), subnet['cidr'])
-
- @decorators.idempotent_id('96af4c7f-5069-44bc-bdcf-c0390f8a67d1')
- @test.services('network')
- def test_created_router(self):
- """Verifies created router."""
- router_id = self.test_resources.get('Router')['physical_resource_id']
- body = self.routers_client.show_router(router_id)
- router = body['router']
- self.assertEqual(self.neutron_basic_template['resources'][
- 'Router']['properties']['name'], router['name'])
- self.assertEqual(self.external_network_id,
- router['external_gateway_info']['network_id'])
- self.assertEqual(True, router['admin_state_up'])
-
- @decorators.idempotent_id('89f605bd-153e-43ee-a0ed-9919b63423c5')
- @test.services('network')
- def test_created_router_interface(self):
- """Verifies created router interface."""
- router_id = self.test_resources.get('Router')['physical_resource_id']
- network_id = self.test_resources.get('Network')['physical_resource_id']
- subnet_id = self.test_resources.get('Subnet')['physical_resource_id']
- body = self.ports_client.list_ports()
- ports = body['ports']
- router_ports = filter(lambda port: port['device_id'] ==
- router_id, ports)
- created_network_ports = filter(lambda port: port['network_id'] ==
- network_id, router_ports)
- self.assertEqual(1, len(created_network_ports))
- router_interface = created_network_ports[0]
- fixed_ips = router_interface['fixed_ips']
- subnet_fixed_ips = filter(lambda port: port['subnet_id'] ==
- subnet_id, fixed_ips)
- self.assertEqual(1, len(subnet_fixed_ips))
- router_interface_ip = subnet_fixed_ips[0]['ip_address']
- self.assertEqual(str(self.subnet_cidr.iter_hosts().next()),
- router_interface_ip)
-
- @decorators.idempotent_id('75d85316-4ac2-4c0e-a1a9-edd2148fc10e')
- @test.services('compute', 'network')
- def test_created_server(self):
- """Verifies created sever."""
- server_id = self.test_resources.get('Server')['physical_resource_id']
- server = self.servers_client.show_server(server_id)['server']
- self.assertEqual(self.keypair_name, server['key_name'])
- self.assertEqual('ACTIVE', server['status'])
- network = server['addresses'][self.neutron_basic_template['resources'][
- 'Network']['properties']['name']][0]
- self.assertEqual(4, network['version'])
- self.assertIn(netaddr.IPAddress(network['addr']), self.subnet_cidr)
diff --git a/tempest/api/orchestration/stacks/test_non_empty_stack.py b/tempest/api/orchestration/stacks/test_non_empty_stack.py
deleted file mode 100644
index 6b9c88b..0000000
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-CONF = config.CONF
-
-
-class StacksTestJSON(base.BaseOrchestrationTest):
-
- @classmethod
- def resource_setup(cls):
- super(StacksTestJSON, cls).resource_setup()
- cls.stack_name = data_utils.rand_name('heat')
- template = cls.read_template('non_empty_stack')
- image_id = (CONF.compute.image_ref or
- cls._create_image()['id'])
- flavor = CONF.orchestration.instance_type
- # create the stack
- cls.stack_identifier = cls.create_stack(
- cls.stack_name,
- template,
- parameters={
- 'trigger': 'start',
- 'image': image_id,
- 'flavor': flavor
- })
- cls.stack_id = cls.stack_identifier.split('/')[1]
- cls.resource_name = 'fluffy'
- cls.resource_type = 'AWS::AutoScaling::LaunchConfiguration'
- cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
-
- def _list_stacks(self, expected_num=None, **filter_kwargs):
- stacks = self.client.list_stacks(params=filter_kwargs)['stacks']
- self.assertIsInstance(stacks, list)
- if expected_num is not None:
- self.assertEqual(expected_num, len(stacks))
- return stacks
-
- @decorators.idempotent_id('065c652a-720d-4760-9132-06aedeb8e3ab')
- def test_stack_list(self):
- """Created stack should be in the list of existing stacks."""
- stacks = self._list_stacks()
- stacks_names = map(lambda stack: stack['stack_name'], stacks)
- self.assertIn(self.stack_name, stacks_names)
-
- @decorators.idempotent_id('992f96e3-41ee-4ff6-91c7-bcfb670c0919')
- def test_stack_show(self):
- """Getting details about created stack should be possible."""
- stack = self.client.show_stack(self.stack_name)['stack']
- self.assertIsInstance(stack, dict)
- self.assert_fields_in_dict(stack, 'stack_name', 'id', 'links',
- 'parameters', 'outputs', 'disable_rollback',
- 'stack_status_reason', 'stack_status',
- 'creation_time', 'updated_time',
- 'capabilities', 'notification_topics',
- 'timeout_mins', 'template_description')
- self.assert_fields_in_dict(stack['parameters'], 'AWS::StackId',
- 'trigger', 'AWS::Region', 'AWS::StackName')
- self.assertEqual(True, stack['disable_rollback'],
- 'disable_rollback should default to True')
- self.assertEqual(self.stack_name, stack['stack_name'])
- self.assertEqual(self.stack_id, stack['id'])
- self.assertEqual('fluffy', stack['outputs'][0]['output_key'])
-
- @decorators.idempotent_id('fe719f7a-305a-44d8-bbb5-c91e93d9da17')
- def test_suspend_resume_stack(self):
- """Suspend and resume a stack."""
- self.client.suspend_stack(self.stack_identifier)
- self.client.wait_for_stack_status(self.stack_identifier,
- 'SUSPEND_COMPLETE')
- self.client.resume_stack(self.stack_identifier)
- self.client.wait_for_stack_status(self.stack_identifier,
- 'RESUME_COMPLETE')
-
- @decorators.idempotent_id('c951d55e-7cce-4c1f-83a0-bad735437fa6')
- def test_list_resources(self):
- """Get list of created resources for the stack should be possible."""
- resources = self.list_resources(self.stack_identifier)
- self.assertEqual({self.resource_name: self.resource_type}, resources)
-
- @decorators.idempotent_id('2aba03b3-392f-4237-900b-1f5a5e9bd962')
- def test_show_resource(self):
- """Getting details about created resource should be possible."""
- resource = self.client.show_resource(self.stack_identifier,
- self.resource_name)['resource']
- self.assertIsInstance(resource, dict)
- self.assert_fields_in_dict(resource, 'resource_name', 'description',
- 'links', 'logical_resource_id',
- 'resource_status', 'updated_time',
- 'required_by', 'resource_status_reason',
- 'physical_resource_id', 'resource_type')
- self.assertEqual(self.resource_name, resource['logical_resource_id'])
- self.assertEqual(self.resource_type, resource['resource_type'])
-
- @decorators.idempotent_id('898070a9-eba5-4fae-b7d6-cf3ffa03090f')
- def test_resource_metadata(self):
- """Getting metadata for created resources should be possible."""
- metadata = self.client.show_resource_metadata(
- self.stack_identifier,
- self.resource_name)['metadata']
- self.assertIsInstance(metadata, dict)
- self.assertEqual(['Tom', 'Stinky'], metadata.get('kittens', None))
-
- @decorators.idempotent_id('46567533-0a7f-483b-8942-fa19e0f17839')
- def test_list_events(self):
- """Getting list of created events for the stack should be possible."""
- events = self.client.list_events(self.stack_identifier)['events']
- self.assertIsInstance(events, list)
-
- for event in events:
- self.assert_fields_in_dict(event, 'logical_resource_id', 'id',
- 'resource_status_reason',
- 'resource_status', 'event_time')
-
- resource_statuses = [event['resource_status'] for event in events]
- self.assertIn('CREATE_IN_PROGRESS', resource_statuses)
- self.assertIn('CREATE_COMPLETE', resource_statuses)
-
- @decorators.idempotent_id('92465723-1673-400a-909d-4773757a3f21')
- def test_show_event(self):
- """Getting details about an event should be possible."""
- events = self.client.list_resource_events(self.stack_identifier,
- self.resource_name)['events']
- self.assertNotEqual([], events)
- events.sort(key=lambda event: event['event_time'])
- event_id = events[0]['id']
- event = self.client.show_event(self.stack_identifier,
- self.resource_name, event_id)['event']
- self.assertIsInstance(event, dict)
- self.assert_fields_in_dict(event, 'resource_name', 'event_time',
- 'links', 'logical_resource_id',
- 'resource_status', 'resource_status_reason',
- 'physical_resource_id', 'id',
- 'resource_properties', 'resource_type')
- self.assertEqual(self.resource_name, event['resource_name'])
- self.assertEqual('state changed', event['resource_status_reason'])
- self.assertEqual(self.resource_name, event['logical_resource_id'])
diff --git a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
deleted file mode 100644
index a51648f..0000000
--- a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-
-class NovaKeyPairResourcesYAMLTest(base.BaseOrchestrationTest):
- _tpl_type = 'yaml'
- _resource = 'resources'
- _type = 'type'
-
- @classmethod
- def resource_setup(cls):
- super(NovaKeyPairResourcesYAMLTest, cls).resource_setup()
- cls.stack_name = data_utils.rand_name('heat')
- template = cls.read_template('nova_keypair', ext=cls._tpl_type)
-
- # create the stack, avoid any duplicated key.
- cls.stack_identifier = cls.create_stack(
- cls.stack_name,
- template,
- parameters={
- 'KeyPairName1': cls.stack_name + '_1',
- 'KeyPairName2': cls.stack_name + '_2'
- })
-
- cls.stack_id = cls.stack_identifier.split('/')[1]
- cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
- resources = (cls.client.list_resources(cls.stack_identifier)
- ['resources'])
- cls.test_resources = {}
- for resource in resources:
- cls.test_resources[resource['logical_resource_id']] = resource
-
- @decorators.idempotent_id('b476eac2-a302-4815-961f-18c410a2a537')
- def test_created_resources(self):
- """Verifies created keypair resource."""
-
- nova_keypair_template = self.load_template('nova_keypair',
- ext=self._tpl_type)
- resources = [('KeyPairSavePrivate',
- nova_keypair_template[self._resource][
- 'KeyPairSavePrivate'][self._type]),
- ('KeyPairDontSavePrivate',
- nova_keypair_template[self._resource][
- 'KeyPairDontSavePrivate'][self._type])]
-
- for resource_name, resource_type in resources:
- resource = self.test_resources.get(resource_name, None)
- self.assertIsInstance(resource, dict)
- self.assertEqual(resource_name, resource['logical_resource_id'])
- self.assertEqual(resource_type, resource['resource_type'])
- self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
-
- @decorators.idempotent_id('8d77dec7-91fd-45a6-943d-5abd45e338a4')
- def test_stack_keypairs_output(self):
- stack = self.client.show_stack(self.stack_name)['stack']
- self.assertIsInstance(stack, dict)
-
- output_map = {}
- for outputs in stack['outputs']:
- output_map[outputs['output_key']] = outputs['output_value']
- # Test that first key generated public and private keys
- self.assertIn('KeyPair_PublicKey', output_map)
- self.assertIn("Generated", output_map['KeyPair_PublicKey'])
- self.assertIn('KeyPair_PrivateKey', output_map)
- self.assertIn('-----BEGIN', output_map['KeyPair_PrivateKey'])
- # Test that second key generated public key, and private key is not
- # in the output due to save_private_key = false
- self.assertIn('KeyPairDontSavePrivate_PublicKey', output_map)
- self.assertIn('Generated',
- output_map['KeyPairDontSavePrivate_PublicKey'])
- self.assertIn(u'KeyPairDontSavePrivate_PrivateKey', output_map)
- private_key = output_map['KeyPairDontSavePrivate_PrivateKey']
- self.assertEqual(0, len(private_key))
-
-
-class NovaKeyPairResourcesAWSTest(NovaKeyPairResourcesYAMLTest):
- _tpl_type = 'json'
- _resource = 'Resources'
- _type = 'Type'
diff --git a/tempest/api/orchestration/stacks/test_resource_types.py b/tempest/api/orchestration/stacks/test_resource_types.py
deleted file mode 100644
index 6d0707e..0000000
--- a/tempest/api/orchestration/stacks/test_resource_types.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib import decorators
-
-
-class ResourceTypesTest(base.BaseOrchestrationTest):
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('7123d082-3577-4a30-8f00-f805327c4ffd')
- def test_resource_type_list(self):
- """Verify it is possible to list resource types."""
- resource_types = self.client.list_resource_types()['resource_types']
- self.assertIsInstance(resource_types, list)
- self.assertIn('OS::Nova::Server', resource_types)
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('0e85a483-828b-4a28-a0e3-f0a21809192b')
- def test_resource_type_show(self):
- """Verify it is possible to get schema about resource types."""
- resource_types = self.client.list_resource_types()['resource_types']
- self.assertNotEmpty(resource_types)
-
- for resource_type in resource_types:
- type_schema = self.client.show_resource_type(resource_type)
- self.assert_fields_in_dict(type_schema, 'properties',
- 'attributes', 'resource_type')
- self.assertEqual(resource_type, type_schema['resource_type'])
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('8401821d-65fe-4d43-9fa3-57d5ce3a35c7')
- def test_resource_type_template(self):
- """Verify it is possible to get template about resource types."""
- type_template = self.client.show_resource_type_template(
- 'OS::Nova::Server')
- self.assert_fields_in_dict(
- type_template,
- 'Outputs',
- 'Parameters', 'Resources')
diff --git a/tempest/api/orchestration/stacks/test_soft_conf.py b/tempest/api/orchestration/stacks/test_soft_conf.py
deleted file mode 100644
index 8192999..0000000
--- a/tempest/api/orchestration/stacks/test_soft_conf.py
+++ /dev/null
@@ -1,169 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-from tempest.lib import exceptions as lib_exc
-
-
-class TestSoftwareConfig(base.BaseOrchestrationTest):
-
- def setUp(self):
- super(TestSoftwareConfig, self).setUp()
- self.configs = []
- # Add 2 sets of software configuration
- self.configs.append(self._config_create('a'))
- self.configs.append(self._config_create('b'))
- # Create a deployment using config a's id
- self._deployment_create(self.configs[0]['id'])
-
- def _config_create(self, suffix):
- configuration = {'group': 'script',
- 'inputs': [],
- 'outputs': [],
- 'options': {}}
- configuration['name'] = 'heat_soft_config_%s' % suffix
- configuration['config'] = '#!/bin/bash echo init-%s' % suffix
- api_config = self.client.create_software_config(**configuration)
- configuration['id'] = api_config['software_config']['id']
- self.addCleanup(self._config_delete, configuration['id'])
- self._validate_config(configuration, api_config)
- return configuration
-
- def _validate_config(self, configuration, api_config):
- # Assert all expected keys are present with matching data
- for k in configuration:
- self.assertEqual(configuration[k],
- api_config['software_config'][k])
-
- def _deployment_create(self, config_id):
- self.server_id = data_utils.rand_name('dummy-server')
- self.action = 'ACTION_0'
- self.status = 'STATUS_0'
- self.input_values = {}
- self.output_values = []
- self.status_reason = 'REASON_0'
- self.signal_transport = 'NO_SIGNAL'
- self.deployment = self.client.create_software_deploy(
- self.server_id, config_id, self.action, self.status,
- self.input_values, self.output_values, self.status_reason,
- self.signal_transport)
- self.deployment_id = self.deployment['software_deployment']['id']
- self.addCleanup(self._deployment_delete, self.deployment_id)
-
- def _deployment_delete(self, deploy_id):
- self.client.delete_software_deploy(deploy_id)
- # Testing that it is really gone
- self.assertRaises(
- lib_exc.NotFound, self.client.show_software_deployment,
- self.deployment_id)
-
- def _config_delete(self, config_id):
- self.client.delete_software_config(config_id)
- # Testing that it is really gone
- self.assertRaises(
- lib_exc.NotFound, self.client.show_software_config, config_id)
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('136162ed-9445-4b9c-b7fc-306af8b5da99')
- def test_get_software_config(self):
- """Testing software config get."""
- for conf in self.configs:
- api_config = self.client.show_software_config(conf['id'])
- self._validate_config(conf, api_config)
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('1275c835-c967-4a2c-8d5d-ad533447ed91')
- def test_get_deployment_list(self):
- """Getting a list of all deployments"""
- deploy_list = self.client.list_software_deployments()
- deploy_ids = [deploy['id'] for deploy in
- deploy_list['software_deployments']]
- self.assertIn(self.deployment_id, deploy_ids)
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('fe7cd9f9-54b1-429c-a3b7-7df8451db913')
- def test_get_deployment_metadata(self):
- """Testing deployment metadata get"""
- metadata = self.client.show_software_deployment_metadata(
- self.server_id)
- conf_ids = [conf['id'] for conf in metadata['metadata']]
- self.assertIn(self.configs[0]['id'], conf_ids)
-
- def _validate_deployment(self, action, status, reason, config_id):
- deployment = self.client.show_software_deployment(self.deployment_id)
- self.assertEqual(action, deployment['software_deployment']['action'])
- self.assertEqual(status, deployment['software_deployment']['status'])
- self.assertEqual(reason,
- deployment['software_deployment']['status_reason'])
- self.assertEqual(config_id,
- deployment['software_deployment']['config_id'])
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('f29d21f3-ed75-47cf-8cdc-ef1bdeb4c674')
- def test_software_deployment_create_validate(self):
- """Testing software deployment was created as expected."""
- # Asserting that all fields were created
- self.assert_fields_in_dict(
- self.deployment['software_deployment'], 'action', 'config_id',
- 'id', 'input_values', 'output_values', 'server_id', 'status',
- 'status_reason')
- # Testing get for this deployment and verifying parameters
- self._validate_deployment(self.action, self.status,
- self.status_reason, self.configs[0]['id'])
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('2ac43ab3-34f2-415d-be2e-eabb4d14ee32')
- def test_software_deployment_update_no_metadata_change(self):
- """Testing software deployment update without metadata change."""
- metadata = self.client.show_software_deployment_metadata(
- self.server_id)
- # Updating values without changing the configuration ID
- new_action = 'ACTION_1'
- new_status = 'STATUS_1'
- new_reason = 'REASON_1'
- self.client.update_software_deploy(
- self.deployment_id, self.server_id, self.configs[0]['id'],
- new_action, new_status, self.input_values, self.output_values,
- new_reason, self.signal_transport)
- # Verifying get and that the deployment was updated as expected
- self._validate_deployment(new_action, new_status,
- new_reason, self.configs[0]['id'])
-
- # Metadata should not be changed at this point
- test_metadata = self.client.show_software_deployment_metadata(
- self.server_id)
- for key in metadata['metadata'][0]:
- self.assertEqual(
- metadata['metadata'][0][key],
- test_metadata['metadata'][0][key])
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('92c48944-d79d-4595-a840-8e1a581c1a72')
- def test_software_deployment_update_with_metadata_change(self):
- """Testing software deployment update with metadata change."""
- metadata = self.client.show_software_deployment_metadata(
- self.server_id)
- self.client.update_software_deploy(
- self.deployment_id, self.server_id, self.configs[1]['id'],
- self.action, self.status, self.input_values,
- self.output_values, self.status_reason, self.signal_transport)
- self._validate_deployment(self.action, self.status,
- self.status_reason, self.configs[1]['id'])
- # Metadata should now be changed
- new_metadata = self.client.show_software_deployment_metadata(
- self.server_id)
- # Its enough to test the ID in this case
- meta_id = metadata['metadata'][0]['id']
- test_id = new_metadata['metadata'][0]['id']
- self.assertNotEqual(meta_id, test_id)
diff --git a/tempest/api/orchestration/stacks/test_stacks.py b/tempest/api/orchestration/stacks/test_stacks.py
deleted file mode 100644
index dc1bb4f..0000000
--- a/tempest/api/orchestration/stacks/test_stacks.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-
-class StacksTestJSON(base.BaseOrchestrationTest):
- empty_template = "HeatTemplateFormatVersion: '2012-12-12'\n"
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('d35d628c-07f6-4674-85a1-74db9919e986')
- def test_stack_list_responds(self):
- stacks = self.client.list_stacks()['stacks']
- self.assertIsInstance(stacks, list)
-
- @decorators.attr(type='smoke')
- @decorators.idempotent_id('10498bd5-a83e-4b62-a817-ce24afe938fe')
- def test_stack_crud_no_resources(self):
- stack_name = data_utils.rand_name('heat')
-
- # create the stack
- stack_identifier = self.create_stack(
- stack_name, self.empty_template)
- stack_id = stack_identifier.split('/')[1]
-
- # wait for create complete (with no resources it should be instant)
- self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-
- # check for stack in list
- stacks = self.client.list_stacks()['stacks']
- list_ids = list([stack['id'] for stack in stacks])
- self.assertIn(stack_id, list_ids)
-
- # fetch the stack
- stack = self.client.show_stack(stack_identifier)['stack']
- self.assertEqual('CREATE_COMPLETE', stack['stack_status'])
-
- # fetch the stack by name
- stack = self.client.show_stack(stack_name)['stack']
- self.assertEqual('CREATE_COMPLETE', stack['stack_status'])
-
- # fetch the stack by id
- stack = self.client.show_stack(stack_id)['stack']
- self.assertEqual('CREATE_COMPLETE', stack['stack_status'])
-
- # delete the stack
- self.client.delete_stack(stack_identifier)
- self.client.wait_for_stack_status(stack_identifier, 'DELETE_COMPLETE')
diff --git a/tempest/api/orchestration/stacks/test_swift_resources.py b/tempest/api/orchestration/stacks/test_swift_resources.py
deleted file mode 100644
index d63cde8..0000000
--- a/tempest/api/orchestration/stacks/test_swift_resources.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-from tempest import test
-
-
-CONF = config.CONF
-
-
-class SwiftResourcesTestJSON(base.BaseOrchestrationTest):
- @classmethod
- def skip_checks(cls):
- super(SwiftResourcesTestJSON, cls).skip_checks()
- if not CONF.service_available.swift:
- raise cls.skipException("Swift support is required")
-
- @classmethod
- def setup_credentials(cls):
- super(SwiftResourcesTestJSON, cls).setup_credentials()
- stack_owner_role = CONF.orchestration.stack_owner_role
- operator_role = CONF.object_storage.operator_role
- cls.os = cls.get_client_manager(
- roles=[stack_owner_role, operator_role])
-
- @classmethod
- def setup_clients(cls):
- super(SwiftResourcesTestJSON, cls).setup_clients()
- cls.account_client = cls.os_primary.account_client
- cls.container_client = cls.os_primary.container_client
-
- @classmethod
- def resource_setup(cls):
- super(SwiftResourcesTestJSON, cls).resource_setup()
- cls.stack_name = data_utils.rand_name('heat')
- template = cls.read_template('swift_basic')
- # create the stack
- cls.stack_identifier = cls.create_stack(
- cls.stack_name,
- template)
- cls.stack_id = cls.stack_identifier.split('/')[1]
- cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
- cls.test_resources = {}
- resources = (cls.client.list_resources(cls.stack_identifier)
- ['resources'])
- for resource in resources:
- cls.test_resources[resource['logical_resource_id']] = resource
-
- @decorators.idempotent_id('1a6fe69e-4be4-4990-9a7a-84b6f18019cb')
- def test_created_resources(self):
- """Created stack should be in the list of existing stacks."""
- swift_basic_template = self.load_template('swift_basic')
- resources = [('SwiftContainer', swift_basic_template['resources'][
- 'SwiftContainer']['type']),
- ('SwiftContainerWebsite', swift_basic_template[
- 'resources']['SwiftContainerWebsite']['type'])]
- for resource_name, resource_type in resources:
- resource = self.test_resources.get(resource_name)
- self.assertIsInstance(resource, dict)
- self.assertEqual(resource_type, resource['resource_type'])
- self.assertEqual(resource_name, resource['logical_resource_id'])
- self.assertEqual('CREATE_COMPLETE', resource['resource_status'])
-
- @decorators.idempotent_id('bd438b18-5494-4d5a-9ce6-d2a942ec5060')
- @test.services('object_storage')
- def test_created_containers(self):
- params = {'format': 'json'}
- _, container_list = \
- self.account_client.list_account_containers(params=params)
- created_containers = [cont for cont in container_list
- if cont['name'].startswith(self.stack_name)]
- self.assertEqual(2, len(created_containers))
-
- @decorators.idempotent_id('73d0c093-9922-44a0-8b1d-1fc092dee367')
- @test.services('object_storage')
- def test_acl(self):
- acl_headers = ('x-container-meta-web-index', 'x-container-read')
-
- swcont = self.test_resources.get(
- 'SwiftContainer')['physical_resource_id']
- swcont_website = self.test_resources.get(
- 'SwiftContainerWebsite')['physical_resource_id']
-
- headers, _ = self.container_client.list_container_metadata(swcont)
- for h in acl_headers:
- self.assertNotIn(h, headers)
- headers, _ = self.container_client.list_container_metadata(
- swcont_website)
- for h in acl_headers:
- self.assertIn(h, headers)
-
- @decorators.idempotent_id('fda06135-6777-4594-aefa-0f6107169698')
- @test.services('object_storage')
- def test_metadata(self):
- swift_basic_template = self.load_template('swift_basic')
- metadatas = swift_basic_template['resources']['SwiftContainerWebsite'][
- 'properties']['X-Container-Meta']
- swcont_website = self.test_resources.get(
- 'SwiftContainerWebsite')['physical_resource_id']
- headers, _ = self.container_client.list_container_metadata(
- swcont_website)
-
- for meta in metadatas:
- header_meta = "x-container-meta-%s" % meta
- self.assertIn(header_meta, headers)
- self.assertEqual(headers[header_meta], metadatas[meta])
diff --git a/tempest/api/orchestration/stacks/test_templates.py b/tempest/api/orchestration/stacks/test_templates.py
deleted file mode 100644
index 4ff951d..0000000
--- a/tempest/api/orchestration/stacks/test_templates.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-
-class TemplateYAMLTestJSON(base.BaseOrchestrationTest):
- template = """
-HeatTemplateFormatVersion: '2012-12-12'
-Description: |
- Template which creates only a new user
-Resources:
- CfnUser:
- Type: AWS::IAM::User
-"""
-
- @classmethod
- def resource_setup(cls):
- super(TemplateYAMLTestJSON, cls).resource_setup()
- cls.stack_name = data_utils.rand_name('heat')
- cls.stack_identifier = cls.create_stack(cls.stack_name, cls.template)
- cls.client.wait_for_stack_status(cls.stack_identifier,
- 'CREATE_COMPLETE')
- cls.stack_id = cls.stack_identifier.split('/')[1]
- cls.parameters = {}
-
- @decorators.idempotent_id('47430699-c368-495e-a1db-64c26fd967d7')
- def test_show_template(self):
- """Getting template used to create the stack."""
- self.client.show_template(self.stack_identifier)
-
- @decorators.idempotent_id('ed53debe-8727-46c5-ab58-eba6090ec4de')
- def test_validate_template(self):
- """Validating template passing it content."""
- self.client.validate_template(self.template,
- self.parameters)
-
-
-class TemplateAWSTestJSON(TemplateYAMLTestJSON):
- template = """
-{
- "AWSTemplateFormatVersion" : "2010-09-09",
- "Description" : "Template which creates only a new user",
- "Resources" : {
- "CfnUser" : {
- "Type" : "AWS::IAM::User"
- }
- }
-}
-"""
diff --git a/tempest/api/orchestration/stacks/test_templates_negative.py b/tempest/api/orchestration/stacks/test_templates_negative.py
deleted file mode 100644
index eb93d95..0000000
--- a/tempest/api/orchestration/stacks/test_templates_negative.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright 2014 NEC Corporation. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest.lib import decorators
-from tempest.lib import exceptions as lib_exc
-
-
-class TemplateYAMLNegativeTestJSON(base.BaseOrchestrationTest):
- template = """
-HeatTemplateFormatVersion: '2012-12-12'
-Description: |
- Template which creates only a new user
-Resources:
- CfnUser:
- Type: AWS::IAM::User
-"""
-
- invalid_template_url = 'http:///template.yaml'
-
- @classmethod
- def resource_setup(cls):
- super(TemplateYAMLNegativeTestJSON, cls).resource_setup()
- cls.parameters = {}
-
- @decorators.attr(type=['negative'])
- @decorators.idempotent_id('5586cbca-ddc4-4152-9db8-fa1ce5fc1876')
- def test_validate_template_url(self):
- """Validating template passing url to it."""
- self.assertRaises(lib_exc.BadRequest,
- self.client.validate_template_url,
- template_url=self.invalid_template_url,
- parameters=self.parameters)
-
-
-class TemplateAWSNegativeTestJSON(TemplateYAMLNegativeTestJSON):
- template = """
-{
- "AWSTemplateFormatVersion" : "2010-09-09",
- "Description" : "Template which creates only a new user",
- "Resources" : {
- "CfnUser" : {
- "Type" : "AWS::IAM::User"
- }
- }
-}
-"""
-
- invalid_template_url = 'http:///template.template'
diff --git a/tempest/api/orchestration/stacks/test_volumes.py b/tempest/api/orchestration/stacks/test_volumes.py
deleted file mode 100644
index 7ddf7af..0000000
--- a/tempest/api/orchestration/stacks/test_volumes.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest.api.orchestration import base
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-from tempest.lib import exceptions as lib_exc
-from tempest import test
-
-
-CONF = config.CONF
-
-
-class CinderResourcesTest(base.BaseOrchestrationTest):
-
- @classmethod
- def skip_checks(cls):
- super(CinderResourcesTest, cls).skip_checks()
- if not CONF.service_available.cinder:
- raise cls.skipException('Cinder support is required')
-
- def _cinder_verify(self, volume_id, template):
- self.assertIsNotNone(volume_id)
- volume = self.volumes_client.show_volume(volume_id)['volume']
- self.assertEqual('available', volume.get('status'))
- self.assertEqual(CONF.volume.volume_size, volume.get('size'))
-
- self.assertEqual(template['resources']['volume']['properties'][
- 'description'], volume.get('description'))
- self.assertEqual(template['resources']['volume']['properties'][
- 'name'], volume.get('name'))
-
- def _outputs_verify(self, stack_identifier, template):
- self.assertEqual('available',
- self.get_stack_output(stack_identifier, 'status'))
- self.assertEqual(str(CONF.volume.volume_size),
- self.get_stack_output(stack_identifier, 'size'))
- self.assertEqual(template['resources']['volume']['properties'][
- 'description'], self.get_stack_output(stack_identifier,
- 'display_description'))
- self.assertEqual(template['resources']['volume']['properties'][
- 'name'], self.get_stack_output(stack_identifier, 'display_name'))
-
- @decorators.idempotent_id('c3243329-7bdd-4730-b402-4d19d50c41d8')
- @test.services('volume')
- def test_cinder_volume_create_delete(self):
- """Create and delete a volume via OS::Cinder::Volume."""
- stack_name = data_utils.rand_name('heat')
- template = self.read_template('cinder_basic')
- stack_identifier = self.create_stack(
- stack_name,
- template,
- parameters={
- 'volume_size': CONF.volume.volume_size
- })
- self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-
- # Verify with cinder that the volume exists, with matching details
- volume_id = self.get_stack_output(stack_identifier, 'volume_id')
- cinder_basic_template = self.load_template('cinder_basic')
- self._cinder_verify(volume_id, cinder_basic_template)
-
- # Verify the stack outputs are as expected
- self._outputs_verify(stack_identifier, cinder_basic_template)
-
- # Delete the stack and ensure the volume is gone
- self.client.delete_stack(stack_identifier)
- self.client.wait_for_stack_status(stack_identifier, 'DELETE_COMPLETE')
- self.assertRaises(lib_exc.NotFound,
- self.volumes_client.show_volume,
- volume_id)
-
- def _cleanup_volume(self, volume_id):
- """Cleanup the volume direct with cinder."""
- self.volumes_client.delete_volume(volume_id)
- self.volumes_client.wait_for_resource_deletion(volume_id)
-
- @decorators.idempotent_id('ea8b3a46-b932-4c18-907a-fe23f00b33f8')
- @test.services('volume')
- def test_cinder_volume_create_delete_retain(self):
- """Ensure the 'Retain' deletion policy is respected."""
- stack_name = data_utils.rand_name('heat')
- template = self.read_template('cinder_basic_delete_retain')
- stack_identifier = self.create_stack(
- stack_name,
- template,
- parameters={
- 'volume_size': CONF.volume.volume_size
- })
- self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-
- # Verify with cinder that the volume exists, with matching details
- volume_id = self.get_stack_output(stack_identifier, 'volume_id')
- self.addCleanup(self._cleanup_volume, volume_id)
- retain_template = self.load_template('cinder_basic_delete_retain')
- self._cinder_verify(volume_id, retain_template)
-
- # Verify the stack outputs are as expected
- self._outputs_verify(stack_identifier, retain_template)
-
- # Delete the stack and ensure the volume is *not* gone
- self.client.delete_stack(stack_identifier)
- self.client.wait_for_stack_status(stack_identifier, 'DELETE_COMPLETE')
- self._cinder_verify(volume_id, retain_template)
-
- # Volume cleanup happens via addCleanup calling _cleanup_volume
diff --git a/tempest/api/volume/admin/test_snapshot_manage.py b/tempest/api/volume/admin/test_snapshot_manage.py
index a2d5fb1..9ff7160 100644
--- a/tempest/api/volume/admin/test_snapshot_manage.py
+++ b/tempest/api/volume/admin/test_snapshot_manage.py
@@ -13,12 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
-import testtools
-
from tempest.api.volume import base
from tempest.common import waiters
from tempest import config
+from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
+from tempest.lib import exceptions
CONF = config.CONF
@@ -31,9 +31,19 @@
managed by Cinder from a storage back end to Cinder
"""
+ @classmethod
+ def skip_checks(cls):
+ super(SnapshotManageAdminTest, cls).skip_checks()
+
+ if not CONF.volume_feature_enabled.manage_snapshot:
+ raise cls.skipException("Manage snapshot tests are disabled")
+
+ if len(CONF.volume.manage_snapshot_ref) != 2:
+ msg = ("Manage snapshot ref is not correctly configured, "
+ "it should be a list of two elements")
+ raise exceptions.InvalidConfiguration(msg)
+
@decorators.idempotent_id('0132f42d-0147-4b45-8501-cc504bbf7810')
- @testtools.skipUnless(CONF.volume_feature_enabled.manage_snapshot,
- "Manage snapshot tests are disabled")
def test_unmanage_manage_snapshot(self):
# Create a volume
volume = self.create_volume()
@@ -47,20 +57,30 @@
self.admin_snapshots_client.unmanage_snapshot(snapshot['id'])
self.admin_snapshots_client.wait_for_resource_deletion(snapshot['id'])
- # Fetch snapshot ids
- snapshot_list = [
- snap['id'] for snap in
- self.snapshots_client.list_snapshots()['snapshots']
- ]
-
- # Verify snapshot does not exist in snapshot list
- self.assertNotIn(snapshot['id'], snapshot_list)
+ # Verify the original snapshot does not exist in snapshot list
+ params = {'all_tenants': 1}
+ all_snapshots = self.admin_snapshots_client.list_snapshots(
+ detail=True, params=params)['snapshots']
+ self.assertNotIn(snapshot['id'], [v['id'] for v in all_snapshots])
# Manage the snapshot
- snapshot_ref = '_snapshot-%s' % snapshot['id']
+ name = data_utils.rand_name(self.__class__.__name__ +
+ '-Managed-Snapshot')
+ description = data_utils.rand_name(self.__class__.__name__ +
+ '-Managed-Snapshot-Description')
+ metadata = {"manage-snap-meta1": "value1",
+ "manage-snap-meta2": "value2",
+ "manage-snap-meta3": "value3"}
+ snapshot_ref = {
+ 'volume_id': volume['id'],
+ 'ref': {CONF.volume.manage_snapshot_ref[0]:
+ CONF.volume.manage_snapshot_ref[1] % snapshot['id']},
+ 'name': name,
+ 'description': description,
+ 'metadata': metadata
+ }
new_snapshot = self.admin_snapshot_manage_client.manage_snapshot(
- volume_id=volume['id'],
- ref={'source-name': snapshot_ref})['snapshot']
+ **snapshot_ref)['snapshot']
self.addCleanup(self.delete_snapshot, new_snapshot['id'],
self.admin_snapshots_client)
@@ -70,4 +90,9 @@
'available')
# Verify the managed snapshot has the expected parent volume
- self.assertEqual(new_snapshot['volume_id'], volume['id'])
+ # and the expected field values.
+ new_snapshot_info = self.admin_snapshots_client.show_snapshot(
+ new_snapshot['id'])['snapshot']
+ self.assertEqual(snapshot['size'], new_snapshot_info['size'])
+ for key in ['volume_id', 'name', 'description', 'metadata']:
+ self.assertEqual(snapshot_ref[key], new_snapshot_info[key])
diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
index 04d6cf9..e4ec442 100644
--- a/tempest/api/volume/admin/test_volume_hosts.py
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import random
+
from tempest.api.volume import base
from tempest.lib import decorators
@@ -22,5 +24,38 @@
@decorators.idempotent_id('d5f3efa2-6684-4190-9ced-1c2f526352ad')
def test_list_hosts(self):
hosts = self.admin_hosts_client.list_hosts()['hosts']
- self.assertGreaterEqual(len(hosts), 2, "No. of hosts are < 2,"
- "response of list hosts is: % s" % hosts)
+ self.assertGreaterEqual(len(hosts), 2,
+ "The count of volume hosts is < 2, "
+ "response of list hosts is: %s" % hosts)
+
+ # Check elements in volume hosts list
+ host_list_keys = ['service', 'host_name', 'last-update',
+ 'zone', 'service-status', 'service-state']
+ for host in hosts:
+ for key in host_list_keys:
+ self.assertIn(key, host)
+
+ @decorators.idempotent_id('21168d57-b373-4b71-a3ac-f2c88f0c5d31')
+ def test_show_host(self):
+ hosts = self.admin_hosts_client.list_hosts()['hosts']
+ self.assertGreaterEqual(len(hosts), 2,
+ "The count of volume hosts is < 2, "
+ "response of list hosts is: %s" % hosts)
+
+ # Note(jeremyZ): Host in volume is always presented in two formats:
+ # <host-name> or <host-name>@<driver-name>. Since Mitaka is EOL,
+ # both formats can be chosen for test.
+ host_names = [host['host_name'] for host in hosts]
+ self.assertNotEmpty(host_names, "No available volume host is found, "
+ "all hosts that found are: %s" % hosts)
+
+ # Choose a random host to get and check its elements
+ host_details = self.admin_hosts_client.show_host(
+ random.choice(host_names))['host']
+ self.assertNotEmpty(host_details)
+ host_detail_keys = ['project', 'volume_count', 'snapshot_count',
+ 'host', 'total_volume_gb', 'total_snapshot_gb']
+ for detail in host_details:
+ self.assertIn('resource', detail)
+ for key in host_detail_keys:
+ self.assertIn(key, detail['resource'])
diff --git a/tempest/api/volume/admin/test_volume_manage.py b/tempest/api/volume/admin/test_volume_manage.py
index a039085..4b352e0 100644
--- a/tempest/api/volume/admin/test_volume_manage.py
+++ b/tempest/api/volume/admin/test_volume_manage.py
@@ -18,6 +18,7 @@
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
+from tempest.lib import exceptions
CONF = config.CONF
@@ -32,8 +33,9 @@
raise cls.skipException("Manage volume tests are disabled")
if len(CONF.volume.manage_volume_ref) != 2:
- raise cls.skipException("Manage volume ref is not correctly "
- "configured")
+ msg = ("Manage volume ref is not correctly configured, "
+ "it should be a list of two elements")
+ raise exceptions.InvalidConfiguration(msg)
@decorators.idempotent_id('70076c71-0ce1-4208-a8ff-36a66e65cc1e')
def test_unmanage_manage_volume(self):
diff --git a/tempest/api/volume/admin/test_volume_pools.py b/tempest/api/volume/admin/test_volume_pools.py
index 60a3bda..d389c26 100644
--- a/tempest/api/volume/admin/test_volume_pools.py
+++ b/tempest/api/volume/admin/test_volume_pools.py
@@ -22,7 +22,7 @@
class VolumePoolsAdminTestsJSON(base.BaseVolumeAdminTest):
def _assert_pools(self, with_detail=False):
- cinder_pools = self.admin_volume_client.show_pools(
+ cinder_pools = self.admin_scheduler_stats_client.list_pools(
detail=with_detail)['pools']
self.assertIn('name', cinder_pools[0])
if with_detail:
diff --git a/tempest/api/volume/admin/test_volume_quota_classes.py b/tempest/api/volume/admin/test_volume_quota_classes.py
index 016d87a..f551575 100644
--- a/tempest/api/volume/admin/test_volume_quota_classes.py
+++ b/tempest/api/volume/admin/test_volume_quota_classes.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import random
+
from oslo_log import log as logging
from testtools import matchers
@@ -53,31 +55,41 @@
LOG.debug("Get the current default quota class values")
body = self.admin_quota_classes_client.show_quota_class_set(
'default')['quota_class_set']
- body.pop('id')
- # Restore the defaults when the test is done
- self.addCleanup(self._restore_default_quotas, body.copy())
+ # Note(jeremyZ) Only include specified quota keys to avoid the conflict
+ # that other tests may create/delete volume types or update volume
+ # type's default quotas in concurrency running.
+ update_kwargs = {key: body[key] for key in body if key in QUOTA_KEYS}
- # Increment some of the values for updating the default quota class.
- # For safety, only items with value >= 0 will be updated, and items
- # with value < 0 (-1 means unlimited) will be ignored.
- for quota, default in body.items():
+ # Restore the defaults when the test is done.
+ self.addCleanup(self._restore_default_quotas, update_kwargs.copy())
+
+ # Note(jeremyZ) Increment some of the values for updating the default
+ # quota class. For safety, only items with value >= 0 will be updated,
+ # and items with value < 0 (-1 means unlimited) will be ignored.
+ for quota, default in update_kwargs.items():
if default >= 0:
- body[quota] = default + 1
+ update_kwargs[quota] = default + 1
+
+ # Create a volume type for updating default quotas class.
+ volume_type_name = self.create_volume_type()['name']
+ for key in ['volumes', 'snapshots', 'gigabytes']:
+ update_kwargs['%s_%s' % (key, volume_type_name)] = \
+ random.randint(1, 10)
LOG.debug("Update limits for the default quota class set")
update_body = self.admin_quota_classes_client.update_quota_class_set(
- 'default', **body)['quota_class_set']
+ 'default', **update_kwargs)['quota_class_set']
self.assertThat(update_body.items(),
- matchers.ContainsAll(body.items()))
+ matchers.ContainsAll(update_kwargs.items()))
- # Verify current project's default quotas
+ # Verify current project's default quotas.
default_quotas = self.admin_quotas_client.show_default_quota_set(
- self.os_adm.credentials.tenant_id)['quota_set']
+ self.os_admin.credentials.tenant_id)['quota_set']
self.assertThat(default_quotas.items(),
- matchers.ContainsAll(body.items()))
+ matchers.ContainsAll(update_kwargs.items()))
- # Verify a new project's default quotas
+ # Verify a new project's default quotas.
project_name = data_utils.rand_name('quota_class_tenant')
description = data_utils.rand_name('desc_')
project_id = self.identity_utils.create_project(
@@ -86,4 +98,4 @@
default_quotas = self.admin_quotas_client.show_default_quota_set(
project_id)['quota_set']
self.assertThat(default_quotas.items(),
- matchers.ContainsAll(body.items()))
+ matchers.ContainsAll(update_kwargs.items()))
diff --git a/tempest/api/volume/admin/test_volume_services.py b/tempest/api/volume/admin/test_volume_services.py
index 4aab9c1..293af81 100644
--- a/tempest/api/volume/admin/test_volume_services.py
+++ b/tempest/api/volume/admin/test_volume_services.py
@@ -41,13 +41,13 @@
def test_list_services(self):
services = (self.admin_volume_services_client.list_services()
['services'])
- self.assertNotEqual(0, len(services))
+ self.assertNotEmpty(services)
@decorators.idempotent_id('63a3e1ca-37ee-4983-826d-83276a370d25')
def test_get_service_by_service_binary_name(self):
services = (self.admin_volume_services_client.list_services(
binary=self.binary_name)['services'])
- self.assertNotEqual(0, len(services))
+ self.assertNotEmpty(services)
for service in services:
self.assertEqual(self.binary_name, service['binary'])
@@ -76,7 +76,7 @@
services = (self.admin_volume_services_client.list_services(
host=hostname, binary='cinder-volume')['services'])
- self.assertNotEqual(0, len(services),
+ self.assertNotEmpty(services,
'cinder-volume not found on host %s' % hostname)
self.assertEqual(hostname, _get_host(services[0]['host']))
self.assertEqual('cinder-volume', services[0]['binary'])
@@ -87,6 +87,6 @@
services = (self.admin_volume_services_client.list_services(
host=self.host_name, binary=self.binary_name))['services']
- self.assertNotEqual(0, len(services))
+ self.assertNotEmpty(services)
self.assertEqual(self.host_name, _get_host(services[0]['host']))
self.assertEqual(self.binary_name, services[0]['binary'])
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index ac717f8..af1024c 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -57,8 +57,6 @@
"to the requested name")
self.assertIsNotNone(volume['id'],
"Field volume id is empty or not found.")
- waiters.wait_for_volume_resource_status(self.volumes_client,
- volume['id'], 'available')
# Update volume with new volume_type
self.volumes_client.retype_volume(volume['id'],
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index acff7cd..b81a477 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -70,7 +70,7 @@
@test.services('compute')
def test_force_detach_volume(self):
# Create a server and a volume
- server_id = self.create_server(wait_until='ACTIVE')['id']
+ server_id = self.create_server()['id']
volume_id = self.create_volume()['id']
# Attach volume
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index a6f9246..afc3281 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -121,7 +121,7 @@
'available')
@decorators.idempotent_id('47a35425-a891-4e13-961c-c45deea21e94')
- def test_volume_backup_reset_status_force_delete(self):
+ def test_volume_backup_reset_status(self):
# Create a volume
volume = self.create_volume()
# Create a backup
@@ -136,6 +136,3 @@
status="error")
waiters.wait_for_volume_resource_status(self.admin_backups_client,
backup['id'], 'error')
- # Force delete a backup volume when backup is in error state.
- self.admin_backups_client.force_delete_backup(backup['id'])
- self.admin_backups_client.wait_for_resource_deletion(backup['id'])
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index c877969..8d66156 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -80,6 +80,9 @@
cls.messages_client = cls.os_primary.volume_v3_messages_client
cls.versions_client = cls.os_primary.volume_v3_versions_client
+ if cls._api_version == 3:
+ cls.volumes_client = cls.os_primary.volumes_v3_client
+
def setUp(self):
super(BaseVolumeTest, self).setUp()
self.useFixture(api_microversion_fixture.APIMicroversionFixture(
@@ -144,8 +147,7 @@
snapshot['id'], 'available')
return snapshot
- def create_backup(self, volume_id, backup_client=None,
- wait_until="available", **kwargs):
+ def create_backup(self, volume_id, backup_client=None, **kwargs):
"""Wrapper utility that returns a test backup."""
if backup_client is None:
backup_client = self.backups_client
@@ -155,12 +157,9 @@
backup = backup_client.create_backup(
volume_id=volume_id, **kwargs)['backup']
-
- self.addCleanup(test_utils.call_and_ignore_notfound_exc,
- backup_client.delete_backup, backup['id'])
- waiters.wait_for_volume_resource_status(backup_client,
- backup['id'],
- wait_until)
+ self.addCleanup(backup_client.delete_backup, backup['id'])
+ waiters.wait_for_volume_resource_status(backup_client, backup['id'],
+ 'available')
return backup
# NOTE(afazekas): these create_* and clean_* could be defined
@@ -218,16 +217,17 @@
cls.snapshots_client.wait_for_resource_deletion,
snapshot)
- def create_server(self, **kwargs):
+ def create_server(self, wait_until='ACTIVE', **kwargs):
name = kwargs.pop(
'name',
data_utils.rand_name(self.__class__.__name__ + '-instance'))
tenant_network = self.get_tenant_network()
body, _ = compute.create_test_server(
- self.os,
+ self.os_primary,
tenant_network=tenant_network,
name=name,
+ wait_until=wait_until,
**kwargs)
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
@@ -270,6 +270,9 @@
cls.os_admin.volume_scheduler_stats_v2_client
cls.admin_messages_client = cls.os_admin.volume_v3_messages_client
+ if cls._api_version == 3:
+ cls.admin_volume_client = cls.os_admin.volumes_v3_client
+
@classmethod
def resource_setup(cls):
super(BaseVolumeAdminTest, cls).resource_setup()
diff --git a/tempest/api/volume/test_availability_zone.py b/tempest/api/volume/test_availability_zone.py
index 666efdf..d0a87db 100644
--- a/tempest/api/volume/test_availability_zone.py
+++ b/tempest/api/volume/test_availability_zone.py
@@ -30,4 +30,4 @@
# List of availability zone
availability_zone = (self.client.list_availability_zones()
['availabilityZoneInfo'])
- self.assertGreater(len(availability_zone), 0)
+ self.assertNotEmpty(availability_zone)
diff --git a/tempest/api/volume/test_volume_absolute_limits.py b/tempest/api/volume/test_volume_absolute_limits.py
index 870b9f0..4018468 100644
--- a/tempest/api/volume/test_volume_absolute_limits.py
+++ b/tempest/api/volume/test_volume_absolute_limits.py
@@ -24,7 +24,7 @@
# NOTE(zhufl): This inherits from BaseVolumeAdminTest because
# it requires force_tenant_isolation=True, which need admin
# credentials to create non-admin users for the tests.
-class AbsoluteLimitsTests(base.BaseVolumeAdminTest):
+class AbsoluteLimitsTests(base.BaseVolumeAdminTest): # noqa
# avoid existing volumes of pre-defined tenant
force_tenant_isolation = True
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index 5fd1904..2c13a3c 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from testtools import matchers
-
from tempest.api.volume import base
from tempest.common import waiters
from tempest.lib import decorators
@@ -56,13 +54,19 @@
# List volume transfers, the result should be greater than
# or equal to 1
body = self.client.list_volume_transfers()['transfers']
- self.assertThat(len(body), matchers.GreaterThan(0))
+ self.assertNotEmpty(body)
# Accept a volume transfer by alt_tenant
body = self.alt_client.accept_volume_transfer(
transfer_id, auth_key=auth_key)['transfer']
waiters.wait_for_volume_resource_status(self.alt_volumes_client,
volume['id'], 'available')
+ accepted_volume = self.alt_volumes_client.show_volume(
+ volume['id'])['volume']
+ self.assertEqual(self.os_alt.credentials.user_id,
+ accepted_volume['user_id'])
+ self.assertEqual(self.os_alt.credentials.project_id,
+ accepted_volume['os-vol-tenant-attr:tenant_id'])
@decorators.idempotent_id('ab526943-b725-4c07-b875-8e8ef87a2c30')
def test_create_list_delete_volume_transfer(self):
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index 0e7f1e9..8541c6d 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -38,7 +38,7 @@
@test.services('compute')
def test_attach_detach_volume_to_instance(self):
# Create a server
- server = self.create_server(wait_until='ACTIVE')
+ server = self.create_server()
# Volume is attached and detached successfully from an instance
self.volumes_client.attach_volume(self.volume['id'],
instance_uuid=server['id'],
@@ -69,7 +69,7 @@
@test.services('compute')
def test_get_volume_attachment(self):
# Create a server
- server = self.create_server(wait_until='ACTIVE')
+ server = self.create_server()
# Verify that a volume's attachment information is retrieved
self.volumes_client.attach_volume(self.volume['id'],
instance_uuid=server['id'],
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 5ad209c..4b4aeec 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -108,7 +108,7 @@
volume = self.create_volume()
self.addCleanup(self.volumes_client.delete_volume,
volume['id'])
- server = self.create_server(wait_until='ACTIVE')
+ server = self.create_server()
# Attach volume to instance
self.attach_volume(server['id'], volume['id'])
# Create backup using force flag
@@ -118,9 +118,8 @@
name=backup_name, force=True)
self.assertEqual(backup_name, backup['name'])
- @testtools.skipUnless(CONF.service_available.glance,
- "Glance is not available")
@decorators.idempotent_id('2a8ba340-dff2-4511-9db7-646f07156b15')
+ @test.services('image')
def test_bootable_volume_backup_and_restore(self):
# Create volume from image
img_uuid = CONF.compute.image_ref
diff --git a/tempest/api/volume/test_volumes_clone.py b/tempest/api/volume/test_volumes_clone.py
index a6bbb0a..4c13375 100644
--- a/tempest/api/volume/test_volumes_clone.py
+++ b/tempest/api/volume/test_volumes_clone.py
@@ -13,11 +13,10 @@
# License for the specific language governing permissions and limitations
# under the License.
-import testtools
-
from tempest.api.volume import base
from tempest import config
from tempest.lib import decorators
+from tempest import test
CONF = config.CONF
@@ -47,9 +46,8 @@
self.assertEqual(volume['source_volid'], src_vol['id'])
self.assertEqual(volume['size'], src_size + 1)
- @testtools.skipUnless(CONF.service_available.glance,
- "Glance is not available")
@decorators.idempotent_id('cbbcd7c6-5a6c-481a-97ac-ca55ab715d16')
+ @test.services('image')
def test_create_from_bootable_volume(self):
# Create volume from image
img_uuid = CONF.compute.image_ref
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index 837758f..1eb76a0 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -40,6 +40,7 @@
@decorators.idempotent_id('86be1cba-2640-11e5-9c82-635fb964c912')
@testtools.skipUnless(CONF.volume_feature_enabled.snapshot,
"Cinder volume snapshots are disabled")
+ @decorators.skip_because(bug='1687044')
def test_volume_extend_when_volume_has_snapshot(self):
volume = self.create_volume()
self.create_snapshot(volume['id'])
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 712254e..ec9a0dd 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -137,3 +137,17 @@
origin = self.create_volume()
self._volume_create_get_update_delete(source_volid=origin['id'],
size=CONF.volume.volume_size)
+
+
+class VolumesSummaryTest(base.BaseVolumeTest):
+
+ _api_version = 3
+ min_microversion = '3.12'
+ max_microversion = 'latest'
+
+ @decorators.idempotent_id('c4f2431e-4920-4736-9e00-4040386b6feb')
+ def test_show_volume_summary(self):
+ volume_summary = \
+ self.volumes_client.show_volume_summary()['volume-summary']
+ for key in ['total_size', 'total_count']:
+ self.assertIn(key, volume_summary)
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 9787160..8593d3a 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -343,7 +343,7 @@
# If cannot follow make sure it's because we have finished
else:
- self.assertEqual([], remaining or [],
+ self.assertEmpty(remaining or [],
'No more pages reported, but still '
'missing ids %s' % remaining)
break
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index fc3bcab..4e19e62 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -170,7 +170,7 @@
@decorators.idempotent_id('f5e56b0a-5d02-43c1-a2a7-c9b792c2e3f6')
@test.services('compute')
def test_attach_volumes_with_nonexistent_volume_id(self):
- server = self.create_server(wait_until='ACTIVE')
+ server = self.create_server()
self.assertRaises(lib_exc.NotFound,
self.volumes_client.attach_volume,
@@ -261,7 +261,7 @@
params = {'name': v_name}
fetched_volume = self.volumes_client.list_volumes(
params=params)['volumes']
- self.assertEqual(0, len(fetched_volume))
+ self.assertEmpty(fetched_volume)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('9ca17820-a0e7-4cbd-a7fa-f4468735e359')
@@ -271,7 +271,7 @@
fetched_volume = \
self.volumes_client.list_volumes(
detail=True, params=params)['volumes']
- self.assertEqual(0, len(fetched_volume))
+ self.assertEmpty(fetched_volume)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('143b279b-7522-466b-81be-34a87d564a7c')
@@ -279,7 +279,7 @@
params = {'status': 'null'}
fetched_volume = self.volumes_client.list_volumes(
params=params)['volumes']
- self.assertEqual(0, len(fetched_volume))
+ self.assertEmpty(fetched_volume)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('ba94b27b-be3f-496c-a00e-0283b373fa75')
@@ -288,7 +288,7 @@
fetched_volume = \
self.volumes_client.list_volumes(detail=True,
params=params)['volumes']
- self.assertEqual(0, len(fetched_volume))
+ self.assertEmpty(fetched_volume)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('5b810c91-0ad1-47ce-aee8-615f789be78f')
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index be3f1f2..44c1def 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -35,31 +35,17 @@
super(VolumesSnapshotTestJSON, cls).resource_setup()
cls.volume_origin = cls.create_volume()
- @decorators.idempotent_id('b467b54c-07a4-446d-a1cf-651dedcc3ff1')
+ @decorators.idempotent_id('8567b54c-4455-446d-a1cf-651ddeaa3ff2')
@test.services('compute')
- def test_snapshot_create_with_volume_in_use(self):
- # Create a snapshot when volume status is in-use
+ def test_snapshot_create_delete_with_volume_in_use(self):
# Create a test instance
- server = self.create_server(wait_until='ACTIVE')
+ server = self.create_server()
self.attach_volume(server['id'], self.volume_origin['id'])
# Snapshot a volume which attached to an instance with force=False
self.assertRaises(lib_exc.BadRequest, self.create_snapshot,
self.volume_origin['id'], force=False)
- # Snapshot a volume even if it's attached to an instance
- snapshot = self.create_snapshot(self.volume_origin['id'],
- force=True)
- # Delete the snapshot
- self.delete_snapshot(snapshot['id'])
-
- @decorators.idempotent_id('8567b54c-4455-446d-a1cf-651ddeaa3ff2')
- @test.services('compute')
- def test_snapshot_delete_with_volume_in_use(self):
- # Create a test instance
- server = self.create_server(wait_until='ACTIVE')
- self.attach_volume(server['id'], self.volume_origin['id'])
-
# Snapshot a volume attached to an instance
snapshot1 = self.create_snapshot(self.volume_origin['id'], force=True)
snapshot2 = self.create_snapshot(self.volume_origin['id'], force=True)
@@ -79,7 +65,7 @@
snapshot1 = self.create_snapshot(self.volume_origin['id'])
# Create a server and attach it
- server = self.create_server(wait_until='ACTIVE')
+ server = self.create_server()
self.attach_volume(server['id'], self.volume_origin['id'])
# Now that the volume is attached, create another snapshots
diff --git a/tempest/clients.py b/tempest/clients.py
index 73a4b20..8ad6e92 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -41,8 +41,7 @@
_, identity_uri = get_auth_provider_class(credentials)
super(Manager, self).__init__(
credentials=credentials, identity_uri=identity_uri, scope=scope,
- region=CONF.identity.region,
- client_parameters=self._prepare_configuration())
+ region=CONF.identity.region)
# TODO(andreaf) When clients are initialised without the right
# parameters available, the calls below will trigger a KeyError.
# We should catch that and raise a better error.
@@ -62,35 +61,6 @@
build_timeout=CONF.orchestration.build_timeout,
**self.default_params)
- def _prepare_configuration(self):
- """Map values from CONF into Manager parameters
-
- This uses `config.service_client_config` for all services to collect
- most configuration items needed to init the clients.
- """
- # NOTE(andreaf) Once all service clients in Tempest are migrated
- # to tempest.lib, their configuration will be picked up from the
- # registry, and this method will become redundant.
-
- configuration = {}
-
- # Setup the parameters for all Tempest services which are not in lib.
- # NOTE(andreaf) Since client.py is an internal module of Tempest,
- # it doesn't have to consider plugin configuration.
- for service in clients._tempest_internal_modules():
- try:
- # NOTE(andreaf) Use the unversioned service name to fetch
- # the configuration since configuration is not versioned.
- service_for_config = service.split('.')[0]
- if service_for_config not in configuration:
- configuration[service_for_config] = (
- config.service_client_config(service_for_config))
- except lib_exc.UnknownServiceClient:
- LOG.warning(
- 'Could not load configuration for service %s', service)
-
- return configuration
-
def _set_network_clients(self):
self.network_agents_client = self.network.AgentsClient()
self.network_extensions_client = self.network.ExtensionsClient()
@@ -109,6 +79,7 @@
self.security_groups_client = self.network.SecurityGroupsClient()
self.network_versions_client = self.network.NetworkVersionsClient()
self.service_providers_client = self.network.ServiceProvidersClient()
+ self.tags_client = self.network.TagsClient()
def _set_image_clients(self):
if CONF.service_available.glance:
@@ -233,6 +204,8 @@
**params_v3)
self.endpoint_filter_client = \
self.identity_v3.EndPointsFilterClient(**params_v3)
+ self.endpoint_groups_client = self.identity_v3.EndPointGroupsClient(
+ **params_v3)
# Token clients do not use the catalog. They only need default_params.
# They read auth_url, so they should only be set if the corresponding
@@ -269,6 +242,7 @@
self.volume_manage_v2_client = self.volume_v2.VolumeManageClient()
self.volumes_client = self.volume_v1.VolumesClient()
self.volumes_v2_client = self.volume_v2.VolumesClient()
+ self.volumes_v3_client = self.volume_v3.VolumesClient()
self.volume_v3_messages_client = self.volume_v3.MessagesClient()
self.volume_v3_versions_client = self.volume_v3.VersionsClient()
self.volume_types_client = self.volume_v1.TypesClient()
@@ -295,8 +269,10 @@
self.volume_v2.TransfersClient()
def _set_object_storage_clients(self):
- # Mandatory parameters (always defined)
- params = self.parameters['object-storage']
+ # NOTE(andreaf) Load configuration from config. Once object storage
+ # is in lib, configuration will be pulled directly from the registry
+ # and this will not be required anymore.
+ params = config.service_client_config('object-storage')
self.account_client = object_storage.AccountClient(self.auth_provider,
**params)
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 0a1881c..6b81e0d 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -167,15 +167,13 @@
def get_extension_client(os, service):
extensions_client = {
'nova': os.extensions_client,
- 'cinder': os.volumes_extension_client,
'neutron': os.network_extensions_client,
'swift': os.capabilities_client,
+ # NOTE: Cinder v3 API is current and v2 and v1 are deprecated.
+ # V3 extension API is the same as v2, so we reuse the v2 client
+ # for v3 API also.
+ 'cinder': os.volumes_v2_extension_client,
}
- # NOTE (e0ne): Use Cinder API v2 by default because v1 is deprecated
- if CONF.volume_feature_enabled.api_v2:
- extensions_client['cinder'] = os.volumes_v2_extension_client
- else:
- extensions_client['cinder'] = os.volumes_extension_client
if service not in extensions_client:
print('No tempest extensions client for %s' % service)
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 9319d2a..99a628e 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -64,10 +64,14 @@
# Show header line too
selected.append(l)
# lsblk lists disk type in a column right-aligned with TYPE
- elif pos > 0 and l[pos:pos + 4] == "disk":
+ elif pos is not None and pos > 0 and l[pos:pos + 4] == "disk":
selected.append(l)
- return "\n".join(selected)
+ if selected:
+ return "\n".join(selected)
+ else:
+ msg = "'TYPE' column is requred but the output doesn't have it: "
+ raise tempest.lib.exceptions.TempestException(msg + output)
def get_boot_time(self):
cmd = 'cut -f1 -d. /proc/uptime'
@@ -89,12 +93,12 @@
def get_nic_name_by_mac(self, address):
cmd = "ip -o link | awk '/%s/ {print $2}'" % address
nic = self.exec_command(cmd)
- return nic.strip().strip(":").lower()
+ return nic.strip().strip(":").split('@')[0].lower()
def get_nic_name_by_ip(self, address):
cmd = "ip -o addr | awk '/%s/ {print $2}'" % address
nic = self.exec_command(cmd)
- return nic.strip().strip(":").lower()
+ return nic.strip().strip(":").split('@')[0].lower()
def get_dns_servers(self):
cmd = 'cat /etc/resolv.conf'
diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py
index b15796f..9e83a07 100644
--- a/tempest/common/validation_resources.py
+++ b/tempest/common/validation_resources.py
@@ -80,10 +80,23 @@
validation_data['security_group'] = \
create_ssh_security_group(os, add_rule)
if validation_resources['floating_ip']:
- floating_client = os.compute_floating_ips_client
- validation_data.update(
- floating_client.create_floating_ip(
- pool=CONF.network.floating_network_name))
+ if CONF.service_available.neutron:
+ floatingip = os.floating_ips_client.create_floatingip(
+ floating_network_id=CONF.network.public_network_id)
+ # validation_resources['floating_ip'] has historically looked
+ # like a compute API POST /os-floating-ips response, so we need
+ # to mangle it a bit for a Neutron response with different
+ # fields.
+ validation_data['floating_ip'] = floatingip['floatingip']
+ validation_data['floating_ip']['ip'] = (
+ floatingip['floatingip']['floating_ip_address'])
+ else:
+ # NOTE(mriedem): The os-floating-ips compute API was deprecated
+ # in the 2.36 microversion. Any tests for CRUD operations on
+ # floating IPs using the compute API should be capped at 2.35.
+ validation_data.update(
+ os.compute_floating_ips_client.create_floating_ip(
+ pool=CONF.network.floating_network_name))
return validation_data
diff --git a/tempest/config.py b/tempest/config.py
index c694dc5..7b96281 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -161,7 +161,9 @@
choices=['public', 'admin', 'internal',
'publicURL', 'adminURL', 'internalURL'],
help="The endpoint type to use for OpenStack Identity "
- "(Keystone) API v3"),
+ "(Keystone) API v3. The default value adminURL is "
+ "deprecated and will be modified to publicURL in "
+ "the next release."),
cfg.StrOpt('admin_role',
default='admin',
help="Role required to administrate keystone."),
@@ -645,6 +647,9 @@
cfg.BoolOpt('port_security',
default=False,
help="Does the test environment support port security?"),
+ cfg.BoolOpt('floating_ips',
+ default=True,
+ help='Does the test environment support floating_ips')
]
validation_group = cfg.OptGroup(name='validation',
@@ -763,6 +768,12 @@
"It contains two elements, the first is ref type "
"(like 'source-name', 'source-id', etc), the second is "
"volume name template used in storage backend"),
+ cfg.ListOpt('manage_snapshot_ref',
+ default=['source-name', '_snapshot-%s'],
+ help="A reference to existing snapshot for snapshot manage. "
+ "It contains two elements, the first is ref type "
+ "(like 'source-name', 'source-id', etc), the second is "
+ "snapshot name template used in storage backend"),
cfg.StrOpt('min_microversion',
default=None,
help="Lower version of the test target microversion range. "
@@ -899,38 +910,58 @@
OrchestrationGroup = [
cfg.StrOpt('catalog_type',
default='orchestration',
- help="Catalog type of the Orchestration service."),
+ help="Catalog type of the Orchestration service.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.StrOpt('region',
default='',
help="The orchestration region name to use. If empty, the "
"value of identity.region is used instead. If no such "
"region is found in the service catalog, the first found "
- "one is used."),
+ "one is used.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.StrOpt('endpoint_type',
default='publicURL',
choices=['public', 'admin', 'internal',
'publicURL', 'adminURL', 'internalURL'],
- help="The endpoint type to use for the orchestration service."),
+ help="The endpoint type to use for the orchestration service.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.StrOpt('stack_owner_role', default='heat_stack_owner',
- help='Role required for users to be able to manage stacks'),
+ help='Role required for users to be able to manage stacks',
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.IntOpt('build_interval',
default=1,
- help="Time in seconds between build status checks."),
+ help="Time in seconds between build status checks.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.IntOpt('build_timeout',
default=1200,
- help="Timeout in seconds to wait for a stack to build."),
+ help="Timeout in seconds to wait for a stack to build.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.StrOpt('instance_type',
default='m1.micro',
help="Instance type for tests. Needs to be big enough for a "
- "full OS plus the test workload"),
+ "full OS plus the test workload",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.StrOpt('keypair_name',
- help="Name of existing keypair to launch servers with."),
+ help="Name of existing keypair to launch servers with.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.IntOpt('max_template_size',
default=524288,
- help="Value must match heat configuration of the same name."),
+ help="Value must match heat configuration of the same name.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
cfg.IntOpt('max_resources_per_stack',
default=1000,
- help="Value must match heat configuration of the same name."),
+ help="Value must match heat configuration of the same name.",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
]
@@ -996,7 +1027,9 @@
help="Whether or not nova is expected to be available"),
cfg.BoolOpt('heat',
default=False,
- help="Whether or not Heat is expected to be available"),
+ help="Whether or not Heat is expected to be available",
+ deprecated_for_removal=True,
+ deprecated_reason='Heat support will be removed from Tempest'),
]
debug_group = cfg.OptGroup(name="debug",
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 4123ae5..067da09 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -273,6 +273,27 @@
yield(0, msg)
+def dont_put_admin_tests_on_nonadmin_path(logical_line, physical_line,
+ filename):
+ """Check admin tests should exist under admin path
+
+ T115
+ """
+
+ if 'tempest/api/' not in filename:
+ return
+
+ if pep8.noqa(physical_line):
+ return
+
+ if not re.match('class .*Test.*\(.*Admin.*\):', logical_line):
+ return
+
+ if not re.match('.\/tempest\/api\/.*\/admin\/.*', filename):
+ msg = 'T115: All admin tests should exist under admin path.'
+ yield(0, msg)
+
+
def factory(register):
register(import_no_clients_in_api_and_scenario_tests)
register(scenario_tests_need_service_tags)
@@ -287,3 +308,4 @@
register(dont_import_local_tempest_into_lib)
register(dont_use_config_in_tempest_lib)
register(use_rand_uuid_instead_of_uuid4)
+ register(dont_put_admin_tests_on_nonadmin_path)
diff --git a/tempest/lib/api_schema/response/compute/v2_1/servers.py b/tempest/lib/api_schema/response/compute/v2_1/servers.py
index 33a7757..7360396 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/servers.py
@@ -582,3 +582,10 @@
'required': ['adminPass']
}
}
+
+show_server_diagnostics = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object'
+ }
+}
diff --git a/tempest/api/orchestration/__init__.py b/tempest/lib/api_schema/response/compute/v2_13/__init__.py
similarity index 100%
rename from tempest/api/orchestration/__init__.py
rename to tempest/lib/api_schema/response/compute/v2_13/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_13/servers.py b/tempest/lib/api_schema/response/compute/v2_13/servers.py
new file mode 100644
index 0000000..a90f3e4
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_13/servers.py
@@ -0,0 +1,34 @@
+# Copyright 2017 NTT Corporation. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import servers
+
+
+common_server_group = copy.deepcopy(servers.common_server_group)
+common_server_group['properties']['project_id'] = {'type': 'string'}
+common_server_group['properties']['user_id'] = {'type': 'string'}
+common_server_group['required'].append('project_id')
+common_server_group['required'].append('user_id')
+
+create_show_server_group = copy.deepcopy(servers.create_show_server_group)
+create_show_server_group['response_body']['properties'][
+ 'server_group'] = common_server_group
+
+delete_server_group = copy.deepcopy(servers.delete_server_group)
+
+list_server_groups = copy.deepcopy(servers.list_server_groups)
+list_server_groups['response_body']['properties']['server_groups'][
+ 'items'] = common_server_group
diff --git a/tempest/api/orchestration/__init__.py b/tempest/lib/api_schema/response/compute/v2_47/__init__.py
similarity index 100%
copy from tempest/api/orchestration/__init__.py
copy to tempest/lib/api_schema/response/compute/v2_47/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_47/servers.py b/tempest/lib/api_schema/response/compute/v2_47/servers.py
new file mode 100644
index 0000000..37a084f
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_47/servers.py
@@ -0,0 +1,39 @@
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from tempest.lib.api_schema.response.compute.v2_26 import servers as servers226
+
+flavor = {
+ 'type': 'object',
+ 'properties': {
+ 'original_name': {'type': 'string'},
+ 'disk': {'type': 'integer'},
+ 'ephemeral': {'type': 'integer'},
+ 'ram': {'type': 'integer'},
+ 'swap': {'type': 'integer'},
+ 'vcpus': {'type': 'integer'},
+ 'extra_specs': {
+ 'type': 'object',
+ 'patternProperties': {
+ '^[a-zA-Z0-9_\-\. :]+$': {'type': 'string'}
+ }
+ }
+ },
+ 'additionalProperties': False,
+ 'required': ['original_name', 'disk', 'ephemeral', 'ram', 'swap', 'vcpus']
+}
+
+get_server = copy.deepcopy(servers226.get_server)
+get_server['response_body']['properties']['server'][
+ 'properties'].update({'flavor': flavor})
diff --git a/tempest/api/orchestration/__init__.py b/tempest/lib/api_schema/response/compute/v2_48/__init__.py
similarity index 100%
copy from tempest/api/orchestration/__init__.py
copy to tempest/lib/api_schema/response/compute/v2_48/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_48/servers.py b/tempest/lib/api_schema/response/compute/v2_48/servers.py
new file mode 100644
index 0000000..5904758
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_48/servers.py
@@ -0,0 +1,115 @@
+# Copyright 2017 Mirantis Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+from tempest.lib.api_schema.response.compute.v2_47 import servers as servers247
+
+
+show_server_diagnostics = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'state': {
+ 'type': 'string', 'enum': [
+ 'pending', 'running', 'paused', 'shutdown', 'crashed',
+ 'suspended']
+ },
+ 'driver': {
+ 'type': 'string', 'enum': [
+ 'libvirt', 'xenapi', 'vmwareapi', 'ironic', 'hyperv']
+ },
+ 'hypervisor': {'type': ['string', 'null']},
+ 'hypervisor_os': {'type': ['string', 'null']},
+ 'uptime': {'type': ['integer', 'null']},
+ 'config_drive': {'type': 'boolean'},
+ 'num_cpus': {'type': 'integer'},
+ 'num_nics': {'type': 'integer'},
+ 'num_disks': {'type': 'integer'},
+ 'memory_details': {
+ 'type': 'object',
+ 'properties': {
+ 'maximum': {'type': ['integer', 'null']},
+ 'used': {'type': ['integer', 'null']}
+ },
+ 'additionalProperties': False,
+ 'required': ['maximum', 'used']
+ },
+ 'cpu_details': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'id': {'type': ['integer', 'null']},
+ 'time': {'type': ['integer', 'null']},
+ 'utilisation': {'type': ['integer', 'null']}
+ },
+ 'additionalProperties': False,
+ 'required': ['id', 'time', 'utilisation']
+ }
+ },
+ 'nic_details': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'mac_address': {'oneOf': [parameter_types.mac_address,
+ {'type': 'null'}]},
+ 'rx_octets': {'type': ['integer', 'null']},
+ 'rx_errors': {'type': ['integer', 'null']},
+ 'rx_drop': {'type': ['integer', 'null']},
+ 'rx_packets': {'type': ['integer', 'null']},
+ 'rx_rate': {'type': ['integer', 'null']},
+ 'tx_octets': {'type': ['integer', 'null']},
+ 'tx_errors': {'type': ['integer', 'null']},
+ 'tx_drop': {'type': ['integer', 'null']},
+ 'tx_packets': {'type': ['integer', 'null']},
+ 'tx_rate': {'type': ['integer', 'null']}
+ },
+ 'additionalProperties': False,
+ 'required': ['mac_address', 'rx_octets', 'rx_errors',
+ 'rx_drop',
+ 'rx_packets', 'rx_rate', 'tx_octets',
+ 'tx_errors',
+ 'tx_drop', 'tx_packets', 'tx_rate']
+ }
+ },
+ 'disk_details': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'read_bytes': {'type': ['integer', 'null']},
+ 'read_requests': {'type': ['integer', 'null']},
+ 'write_bytes': {'type': ['integer', 'null']},
+ 'write_requests': {'type': ['integer', 'null']},
+ 'errors_count': {'type': ['integer', 'null']}
+ },
+ 'additionalProperties': False,
+ 'required': ['read_bytes', 'read_requests', 'write_bytes',
+ 'write_requests', 'errors_count']
+ }
+ }
+ },
+ 'additionalProperties': False,
+ 'required': [
+ 'state', 'driver', 'hypervisor', 'hypervisor_os', 'uptime',
+ 'config_drive', 'num_cpus', 'num_nics', 'num_disks',
+ 'memory_details', 'cpu_details', 'nic_details', 'disk_details'],
+ }
+}
+
+get_server = copy.deepcopy(servers247.get_server)
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index d72b4dd..63cf07f 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -474,7 +474,7 @@
# Ensure there are not more than one top-level keys
# NOTE(freerunner): Ensure, that JSON is not nullable to
# to prevent StopIteration Exception
- if len(body.keys()) != 1:
+ if not hasattr(body, "keys") or len(body.keys()) != 1:
return body
# Just return the "wrapped" element
first_key, first_item = six.next(six.iteritems(body))
diff --git a/tempest/lib/common/ssh.py b/tempest/lib/common/ssh.py
index 657c0c1..d4ec6ad 100644
--- a/tempest/lib/common/ssh.py
+++ b/tempest/lib/common/ssh.py
@@ -84,10 +84,6 @@
ssh.set_missing_host_key_policy(
paramiko.AutoAddPolicy())
_start_time = time.time()
- if self.proxy_client is not None:
- proxy_chan = self._get_proxy_channel()
- else:
- proxy_chan = None
if self.pkey is not None:
LOG.info("Creating ssh connection to '%s:%d' as '%s'"
" with public key authentication",
@@ -98,6 +94,10 @@
self.host, self.port, self.username, str(self.password))
attempts = 0
while True:
+ if self.proxy_client is not None:
+ proxy_chan = self._get_proxy_channel()
+ else:
+ proxy_chan = None
try:
ssh.connect(self.host, port=self.port, username=self.username,
password=self.password,
diff --git a/tempest/lib/common/utils/linux/remote_client.py b/tempest/lib/common/utils/linux/remote_client.py
index 64d6be2..aef2ff3 100644
--- a/tempest/lib/common/utils/linux/remote_client.py
+++ b/tempest/lib/common/utils/linux/remote_client.py
@@ -28,29 +28,37 @@
def wrapper(self, *args, **kwargs):
try:
return function(self, *args, **kwargs)
- except tempest.lib.exceptions.SSHTimeout:
- try:
- original_exception = sys.exc_info()
- caller = test_utils.find_test_caller() or "not found"
- if self.server:
- msg = 'Caller: %s. Timeout trying to ssh to server %s'
- LOG.debug(msg, caller, self.server)
- if self.console_output_enabled and self.servers_client:
- try:
- msg = 'Console log for server %s: %s'
- console_log = (
- self.servers_client.get_console_output(
- self.server['id'])['output'])
- LOG.debug(msg, self.server['id'], console_log)
- except Exception:
- msg = 'Could not get console_log for server %s'
- LOG.debug(msg, self.server['id'])
- # re-raise the original ssh timeout exception
- six.reraise(*original_exception)
- finally:
- # Delete the traceback to avoid circular references
- _, _, trace = original_exception
- del trace
+ except Exception as e:
+ caller = test_utils.find_test_caller() or "not found"
+ if not isinstance(e, tempest.lib.exceptions.SSHTimeout):
+ message = ('Initializing SSH connection to %(ip)s failed. '
+ 'Error: %(error)s' % {'ip': self.ip_address,
+ 'error': e})
+ message = '(%s) %s' % (caller, message)
+ LOG.error(message)
+ raise
+ else:
+ try:
+ original_exception = sys.exc_info()
+ if self.server:
+ msg = 'Caller: %s. Timeout trying to ssh to server %s'
+ LOG.debug(msg, caller, self.server)
+ if self.console_output_enabled and self.servers_client:
+ try:
+ msg = 'Console log for server %s: %s'
+ console_log = (
+ self.servers_client.get_console_output(
+ self.server['id'])['output'])
+ LOG.debug(msg, self.server['id'], console_log)
+ except Exception:
+ msg = 'Could not get console_log for server %s'
+ LOG.debug(msg, self.server['id'])
+ # re-raise the original ssh timeout exception
+ six.reraise(*original_exception)
+ finally:
+ # Delete the traceback to avoid circular references
+ _, _, trace = original_exception
+ del trace
return wrapper
@@ -78,6 +86,7 @@
"""
self.server = server
self.servers_client = servers_client
+ self.ip_address = ip_address
self.console_output_enabled = console_output_enabled
self.ssh_shell_prologue = ssh_shell_prologue
self.ping_count = ping_count
diff --git a/tempest/lib/services/compute/server_groups_client.py b/tempest/lib/services/compute/server_groups_client.py
index 3a935b4..03cd645 100644
--- a/tempest/lib/services/compute/server_groups_client.py
+++ b/tempest/lib/services/compute/server_groups_client.py
@@ -17,12 +17,17 @@
from oslo_serialization import jsonutils as json
from tempest.lib.api_schema.response.compute.v2_1 import servers as schema
+from tempest.lib.api_schema.response.compute.v2_13 import servers as schemav213
from tempest.lib.common import rest_client
from tempest.lib.services.compute import base_compute_client
class ServerGroupsClient(base_compute_client.BaseComputeClient):
+ schema_versions_info = [
+ {'min': None, 'max': '2.12', 'schema': schema},
+ {'min': '2.13', 'max': None, 'schema': schemav213}]
+
def create_server_group(self, **kwargs):
"""Create the server group.
@@ -34,12 +39,14 @@
resp, body = self.post('os-server-groups', post_body)
body = json.loads(body)
+ schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.create_show_server_group, resp, body)
return rest_client.ResponseBody(resp, body)
def delete_server_group(self, server_group_id):
"""Delete the given server-group."""
resp, body = self.delete("os-server-groups/%s" % server_group_id)
+ schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.delete_server_group, resp, body)
return rest_client.ResponseBody(resp, body)
@@ -47,6 +54,7 @@
"""List the server-groups."""
resp, body = self.get("os-server-groups")
body = json.loads(body)
+ schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.list_server_groups, resp, body)
return rest_client.ResponseBody(resp, body)
@@ -54,5 +62,6 @@
"""Get the details of given server_group."""
resp, body = self.get("os-server-groups/%s" % server_group_id)
body = json.loads(body)
+ schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.create_show_server_group, resp, body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index ff65b25..598d5a6 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -27,6 +27,8 @@
from tempest.lib.api_schema.response.compute.v2_19 import servers as schemav219
from tempest.lib.api_schema.response.compute.v2_26 import servers as schemav226
from tempest.lib.api_schema.response.compute.v2_3 import servers as schemav23
+from tempest.lib.api_schema.response.compute.v2_47 import servers as schemav247
+from tempest.lib.api_schema.response.compute.v2_48 import servers as schemav248
from tempest.lib.api_schema.response.compute.v2_6 import servers as schemav26
from tempest.lib.api_schema.response.compute.v2_9 import servers as schemav29
from tempest.lib.common import rest_client
@@ -43,7 +45,9 @@
{'min': '2.9', 'max': '2.15', 'schema': schemav29},
{'min': '2.16', 'max': '2.18', 'schema': schemav216},
{'min': '2.19', 'max': '2.25', 'schema': schemav219},
- {'min': '2.26', 'max': None, 'schema': schemav226}]
+ {'min': '2.26', 'max': '2.46', 'schema': schemav226},
+ {'min': '2.47', 'max': '2.47', 'schema': schemav247},
+ {'min': '2.48', 'max': None, 'schema': schemav248}]
def __init__(self, auth_provider, service, region,
enable_instance_password=True, **kwargs):
@@ -656,7 +660,10 @@
def show_server_diagnostics(self, server_id):
"""Get the usage data for a server."""
resp, body = self.get("servers/%s/diagnostics" % server_id)
- return rest_client.ResponseBody(resp, json.loads(body))
+ body = json.loads(body)
+ schema = self.get_schema(self.schema_versions_info)
+ self.validate_response(schema.show_server_diagnostics, resp, body)
+ return rest_client.ResponseBody(resp, body)
def list_instance_actions(self, server_id):
"""List the provided server action."""
diff --git a/tempest/lib/services/identity/v2/identity_client.py b/tempest/lib/services/identity/v2/identity_client.py
index 6caff0e..c610d65 100644
--- a/tempest/lib/services/identity/v2/identity_client.py
+++ b/tempest/lib/services/identity/v2/identity_client.py
@@ -11,6 +11,7 @@
# under the License.
from oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
from tempest.lib.common import rest_client
@@ -45,3 +46,24 @@
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
+
+ def list_endpoints_for_token(self, token_id):
+ """List endpoints for a token """
+ resp, body = self.get("tokens/%s/endpoints" % token_id)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def check_token_existence(self, token_id, **params):
+ """Validates a token and confirms that it belongs to a tenant.
+
+ For a full list of available parameters, please refer to the
+ official API reference:
+ https://developer.openstack.org/api-ref/identity/v2-admin/#validate-token
+ """
+ url = "tokens/%s" % token_id
+ if params:
+ url += '?%s' % urllib.urlencode(params)
+ resp, body = self.head(url)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/identity/v3/__init__.py b/tempest/lib/services/identity/v3/__init__.py
index 6f498d9..ce607ff 100644
--- a/tempest/lib/services/identity/v3/__init__.py
+++ b/tempest/lib/services/identity/v3/__init__.py
@@ -19,6 +19,8 @@
from tempest.lib.services.identity.v3.domains_client import DomainsClient
from tempest.lib.services.identity.v3.endpoint_filter_client import \
EndPointsFilterClient
+from tempest.lib.services.identity.v3.endpoint_groups_client import \
+ EndPointGroupsClient
from tempest.lib.services.identity.v3.endpoints_client import EndPointsClient
from tempest.lib.services.identity.v3.groups_client import GroupsClient
from tempest.lib.services.identity.v3.identity_client import IdentityClient
@@ -39,8 +41,9 @@
from tempest.lib.services.identity.v3.versions_client import VersionsClient
__all__ = ['CredentialsClient', 'DomainsClient', 'DomainConfigurationClient',
- 'EndPointsClient', 'EndPointsFilterClient', 'GroupsClient',
- 'IdentityClient', 'InheritedRolesClient', 'OAUTHConsumerClient',
- 'PoliciesClient', 'ProjectsClient', 'RegionsClient',
- 'RoleAssignmentsClient', 'RolesClient', 'ServicesClient',
- 'V3TokenClient', 'TrustsClient', 'UsersClient', 'VersionsClient']
+ 'EndPointGroupsClient', 'EndPointsClient', 'EndPointsFilterClient',
+ 'GroupsClient', 'IdentityClient', 'InheritedRolesClient',
+ 'OAUTHConsumerClient', 'PoliciesClient', 'ProjectsClient',
+ 'RegionsClient', 'RoleAssignmentsClient', 'RolesClient',
+ 'ServicesClient', 'V3TokenClient', 'TrustsClient', 'UsersClient',
+ 'VersionsClient']
diff --git a/tempest/lib/services/identity/v3/endpoint_groups_client.py b/tempest/lib/services/identity/v3/endpoint_groups_client.py
new file mode 100644
index 0000000..723aeaa
--- /dev/null
+++ b/tempest/lib/services/identity/v3/endpoint_groups_client.py
@@ -0,0 +1,78 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class EndPointGroupsClient(rest_client.RestClient):
+ api_version = "v3"
+
+ def create_endpoint_group(self, **kwargs):
+ """Create endpoint group.
+
+ For a full list of available parameters, please refer to the
+ official API reference:
+ https://developer.openstack.org/api-ref/identity/v3-ext/#create-endpoint-group
+ """
+ post_body = json.dumps({'endpoint_group': kwargs})
+ resp, body = self.post('OS-EP-FILTER/endpoint_groups', post_body)
+ self.expected_success(201, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def update_endpoint_group(self, endpoint_group_id, **kwargs):
+ """Update endpoint group.
+
+ For a full list of available parameters, please refer to the
+ official API reference:
+ https://developer.openstack.org/api-ref/identity/v3-ext/#update-endpoint-group
+ """
+ post_body = json.dumps({'endpoint_group': kwargs})
+ resp, body = self.patch(
+ 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id, post_body)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_endpoint_group(self, endpoint_group_id):
+ """Delete endpoint group."""
+ resp_header, resp_body = self.delete(
+ 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id)
+ self.expected_success(204, resp_header.status)
+ return rest_client.ResponseBody(resp_header, resp_body)
+
+ def show_endpoint_group(self, endpoint_group_id):
+ """Get endpoint group."""
+ resp_header, resp_body = self.get(
+ 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id)
+ self.expected_success(200, resp_header.status)
+ resp_body = json.loads(resp_body)
+ return rest_client.ResponseBody(resp_header, resp_body)
+
+ def check_endpoint_group(self, endpoint_group_id):
+ """Check endpoint group."""
+ resp_header, resp_body = self.head(
+ 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id)
+ self.expected_success(200, resp_header.status)
+ return rest_client.ResponseBody(resp_header, resp_body)
+
+ def list_endpoint_groups(self):
+ """Get endpoint groups."""
+ resp_header, resp_body = self.get('OS-EP-FILTER/endpoint_groups')
+ self.expected_success(200, resp_header.status)
+ resp_body = json.loads(resp_body)
+ return rest_client.ResponseBody(resp_header, resp_body)
diff --git a/tempest/lib/services/identity/v3/services_client.py b/tempest/lib/services/identity/v3/services_client.py
index 17b0f24..7bbe850 100644
--- a/tempest/lib/services/identity/v3/services_client.py
+++ b/tempest/lib/services/identity/v3/services_client.py
@@ -76,7 +76,7 @@
url = 'services'
if params:
url += '?%s' % urllib.urlencode(params)
- resp, body = self.get('services')
+ resp, body = self.get(url)
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/network/__init__.py b/tempest/lib/services/network/__init__.py
index 19e5463..419e593 100644
--- a/tempest/lib/services/network/__init__.py
+++ b/tempest/lib/services/network/__init__.py
@@ -31,11 +31,12 @@
ServiceProvidersClient
from tempest.lib.services.network.subnetpools_client import SubnetpoolsClient
from tempest.lib.services.network.subnets_client import SubnetsClient
+from tempest.lib.services.network.tags_client import TagsClient
from tempest.lib.services.network.versions_client import NetworkVersionsClient
__all__ = ['AgentsClient', 'ExtensionsClient', 'FloatingIPsClient',
'MeteringLabelRulesClient', 'MeteringLabelsClient',
- 'NetworksClient', 'PortsClient', 'QuotasClient', 'RoutersClient',
- 'SecurityGroupRulesClient', 'SecurityGroupsClient',
- 'ServiceProvidersClient', 'SubnetpoolsClient', 'SubnetsClient',
- 'NetworkVersionsClient']
+ 'NetworksClient', 'NetworkVersionsClient', 'PortsClient',
+ 'QuotasClient', 'RoutersClient', 'SecurityGroupRulesClient',
+ 'SecurityGroupsClient', 'ServiceProvidersClient',
+ 'SubnetpoolsClient', 'SubnetsClient', 'TagsClient']
diff --git a/tempest/lib/services/network/tags_client.py b/tempest/lib/services/network/tags_client.py
new file mode 100644
index 0000000..20c2c11
--- /dev/null
+++ b/tempest/lib/services/network/tags_client.py
@@ -0,0 +1,88 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+from tempest.lib.services.network import base
+
+
+class TagsClient(base.BaseNetworkClient):
+
+ def create_tag(self, resource_type, resource_id, tag):
+ """Adds a tag on the resource.
+
+ For more information, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#add-a-tag
+ """
+ # NOTE(felipemonteiro): Cannot use ``update_resource`` method because
+ # this API requires self.put but returns 201 instead of 200 expected
+ # by ``update_resource``.
+ uri = '%s/%s/%s/tags/%s' % (
+ self.uri_prefix, resource_type, resource_id, tag)
+ resp, _ = self.put(uri, json.dumps({}))
+ self.expected_success(201, resp.status)
+ return rest_client.ResponseBody(resp)
+
+ def check_tag_existence(self, resource_type, resource_id, tag):
+ """Confirm that a given tag is set on the resource.
+
+ For more information, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#confirm-a-tag
+ """
+ # TODO(felipemonteiro): Use the "check_resource" method in
+ # ``BaseNetworkClient`` once it has been implemented.
+ uri = '%s/%s/%s/tags/%s' % (
+ self.uri_prefix, resource_type, resource_id, tag)
+ resp, _ = self.get(uri)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp)
+
+ def update_all_tags(self, resource_type, resource_id, tags):
+ """Replace all tags on the resource.
+
+ For more information, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#replace-all-tags
+ """
+ uri = '/%s/%s/tags' % (resource_type, resource_id)
+ put_body = {"tags": tags}
+ return self.update_resource(uri, put_body)
+
+ def delete_tag(self, resource_type, resource_id, tag):
+ """Removes a tag on the resource.
+
+ For more information, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#remove-a-tag
+ """
+ uri = '/%s/%s/tags/%s' % (resource_type, resource_id, tag)
+ return self.delete_resource(uri)
+
+ def delete_all_tags(self, resource_type, resource_id):
+ """Removes all tags on the resource.
+
+ For more information, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#remove-all-tags
+ """
+ uri = '/%s/%s/tags' % (resource_type, resource_id)
+ return self.delete_resource(uri)
+
+ def list_tags(self, resource_type, resource_id):
+ """Retrieves the tags for a resource.
+
+ For more information, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#obtain-tag-list
+ """
+ uri = '/%s/%s/tags' % (resource_type, resource_id)
+ return self.list_resources(uri)
diff --git a/tempest/lib/services/volume/v2/backups_client.py b/tempest/lib/services/volume/v2/backups_client.py
index 197d57e..2b5e82d 100644
--- a/tempest/lib/services/volume/v2/backups_client.py
+++ b/tempest/lib/services/volume/v2/backups_client.py
@@ -55,14 +55,6 @@
self.expected_success(202, resp.status)
return rest_client.ResponseBody(resp, body)
- def force_delete_backup(self, backup_id):
- """Force delete a backup volume."""
- post_body = json.dumps({'os-force_delete': {}})
- url = 'backups/%s/action' % backup_id
- resp, body = self.post(url, post_body)
- self.expected_success(202, resp.status)
- return rest_client.ResponseBody(resp)
-
def show_backup(self, backup_id):
"""Returns the details of a single backup."""
url = "backups/%s" % backup_id
diff --git a/tempest/lib/services/volume/v2/encryption_types_client.py b/tempest/lib/services/volume/v2/encryption_types_client.py
index eeff537..20f3356 100755
--- a/tempest/lib/services/volume/v2/encryption_types_client.py
+++ b/tempest/lib/services/volume/v2/encryption_types_client.py
@@ -50,9 +50,9 @@
def create_encryption_type(self, volume_type_id, **kwargs):
"""Create encryption type.
- TODO: Current api-site doesn't contain this API description.
- After fixing the api-site, we need to fix here also for putting
- the link to api-site.
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/block-storage/v2/#create-an-encryption-type-for-v2
"""
url = "/types/%s/encryption" % volume_type_id
post_body = json.dumps({'encryption': kwargs})
@@ -71,9 +71,9 @@
def update_encryption_type(self, volume_type_id, **kwargs):
"""Update an encryption type for an existing volume type.
- TODO: Current api-site doesn't contain this API description.
- After fixing the api-site, we need to fix here also for putting
- the link to api-site.
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/block-storage/v2/#update-an-encryption-type-for-v2
"""
url = "/types/%s/encryption/provider" % volume_type_id
put_body = json.dumps({'encryption': kwargs})
diff --git a/tempest/lib/services/volume/v2/hosts_client.py b/tempest/lib/services/volume/v2/hosts_client.py
index dd7c482..f44bda3 100644
--- a/tempest/lib/services/volume/v2/hosts_client.py
+++ b/tempest/lib/services/volume/v2/hosts_client.py
@@ -24,8 +24,12 @@
api_version = "v2"
def list_hosts(self, **params):
- """Lists all hosts."""
+ """Lists all hosts.
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/block-storage/v2/#list-all-hosts
+ """
url = 'os-hosts'
if params:
url += '?%s' % urllib.urlencode(params)
@@ -34,3 +38,11 @@
body = json.loads(body)
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
+
+ def show_host(self, host_name):
+ """Show host details."""
+ url = 'os-hosts/%s' % host_name
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v2/snapshots_client.py b/tempest/lib/services/volume/v2/snapshots_client.py
index 983ed89..5f4e7de 100644
--- a/tempest/lib/services/volume/v2/snapshots_client.py
+++ b/tempest/lib/services/volume/v2/snapshots_client.py
@@ -124,7 +124,12 @@
return rest_client.ResponseBody(resp, body)
def create_snapshot_metadata(self, snapshot_id, metadata):
- """Create metadata for the snapshot."""
+ """Create metadata for the snapshot.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/block-storage/v2/#create-snapshot-metadata
+ """
put_body = json.dumps({'metadata': metadata})
url = "snapshots/%s/metadata" % snapshot_id
resp, body = self.post(url, put_body)
diff --git a/tempest/lib/services/volume/v2/types_client.py b/tempest/lib/services/volume/v2/types_client.py
index 5d30615..af4fd8c 100644
--- a/tempest/lib/services/volume/v2/types_client.py
+++ b/tempest/lib/services/volume/v2/types_client.py
@@ -41,7 +41,7 @@
For a full list of available parameters, please refer to the official
API reference:
- http://developer.openstack.org/api-ref/block-storage/v2/#list-volume-types
+ https://developer.openstack.org/api-ref/block-storage/v2/#list-all-volume-types-for-v2
"""
url = 'types'
if params:
@@ -57,7 +57,7 @@
For a full list of available parameters, please refer to the official
API reference:
- http://developer.openstack.org/api-ref/block-storage/v2/#show-volume-type-details
+ https://developer.openstack.org/api-ref/block-storage/v2/#show-volume-type-details-for-v2
"""
url = "types/%s" % volume_type_id
resp, body = self.get(url)
@@ -70,7 +70,7 @@
For a full list of available parameters, please refer to the official
API reference:
- http://developer.openstack.org/api-ref/block-storage/v2/#create-volume-type
+ https://developer.openstack.org/api-ref/block-storage/v2/#create-volume-type-for-v2
"""
post_body = json.dumps({'volume_type': kwargs})
resp, body = self.post('types', post_body)
diff --git a/tempest/lib/services/volume/v2/volumes_client.py b/tempest/lib/services/volume/v2/volumes_client.py
index 8b5c96f..86e3836 100644
--- a/tempest/lib/services/volume/v2/volumes_client.py
+++ b/tempest/lib/services/volume/v2/volumes_client.py
@@ -72,6 +72,10 @@
"""List all the volumes created.
Params can be a string (must be urlencoded) or a dictionary.
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/block-storage/v2/#list-volumes-with-details
+ http://developer.openstack.org/api-ref/block-storage/v2/#list-volumes
"""
url = 'volumes'
if detail:
@@ -155,7 +159,12 @@
return rest_client.ResponseBody(resp, body)
def set_bootable_volume(self, volume_id, **kwargs):
- """set a bootable flag for a volume - true or false."""
+ """Set a bootable flag for a volume - true or false.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-bootable-status
+ """
post_body = json.dumps({'os-set_bootable': kwargs})
url = 'volumes/%s/action' % (volume_id)
resp, body = self.post(url, post_body)
@@ -239,7 +248,12 @@
return rest_client.ResponseBody(resp, body)
def create_volume_metadata(self, volume_id, metadata):
- """Create metadata for the volume."""
+ """Create metadata for the volume.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/block-storage/v2/#create-volume-metadata
+ """
put_body = json.dumps({'metadata': metadata})
url = "volumes/%s/metadata" % volume_id
resp, body = self.post(url, put_body)
@@ -256,7 +270,12 @@
return rest_client.ResponseBody(resp, body)
def update_volume_metadata(self, volume_id, metadata):
- """Update metadata for the volume."""
+ """Update metadata for the volume.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-metadata
+ """
put_body = json.dumps({'metadata': metadata})
url = "volumes/%s/metadata" % volume_id
resp, body = self.put(url, put_body)
@@ -281,7 +300,12 @@
return rest_client.ResponseBody(resp, body)
def retype_volume(self, volume_id, **kwargs):
- """Updates volume with new volume type."""
+ """Updates volume with new volume type.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/block-storage/v2/#retype-volume
+ """
post_body = json.dumps({'os-retype': kwargs})
resp, body = self.post('volumes/%s/action' % volume_id, post_body)
self.expected_success(202, resp.status)
@@ -321,7 +345,7 @@
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
- @removals.remove(message="use show_pools from tempest.lib.services."
+ @removals.remove(message="use list_pools from tempest.lib.services."
"volume.v2.scheduler_stats_client")
def show_pools(self, detail=False):
# List all the volumes pools (hosts)
diff --git a/tempest/lib/services/volume/v3/__init__.py b/tempest/lib/services/volume/v3/__init__.py
index 72ab785..07ae917 100644
--- a/tempest/lib/services/volume/v3/__init__.py
+++ b/tempest/lib/services/volume/v3/__init__.py
@@ -15,5 +15,6 @@
from tempest.lib.services.volume.v3.base_client import BaseClient
from tempest.lib.services.volume.v3.messages_client import MessagesClient
from tempest.lib.services.volume.v3.versions_client import VersionsClient
+from tempest.lib.services.volume.v3.volumes_client import VolumesClient
-__all__ = ['MessagesClient', 'BaseClient', 'VersionsClient']
+__all__ = ['MessagesClient', 'BaseClient', 'VersionsClient', 'VolumesClient']
diff --git a/tempest/lib/services/volume/v3/volumes_client.py b/tempest/lib/services/volume/v3/volumes_client.py
new file mode 100644
index 0000000..aec0205
--- /dev/null
+++ b/tempest/lib/services/volume/v3/volumes_client.py
@@ -0,0 +1,42 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
+
+from tempest.lib.common import rest_client
+from tempest.lib.services.volume.v2 import volumes_client
+from tempest.lib.services.volume.v3 import base_client
+
+
+class VolumesClient(base_client.BaseClient,
+ volumes_client.VolumesClient):
+ """Client class to send CRUD Volume V3 API requests"""
+ api_version = "v3"
+
+ def show_volume_summary(self, **params):
+ """Get volumes summary.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/block-storage/v3/#get-volumes-summary
+ """
+ url = 'volumes/summary'
+ if params:
+ url += '?%s' % urllib.urlencode(params)
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index ef4506c..38e03c7 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -47,40 +47,40 @@
def setup_clients(cls):
super(ScenarioTest, cls).setup_clients()
# Clients (in alphabetical order)
- cls.flavors_client = cls.manager.flavors_client
+ cls.flavors_client = cls.os_primary.flavors_client
cls.compute_floating_ips_client = (
- cls.manager.compute_floating_ips_client)
+ cls.os_primary.compute_floating_ips_client)
if CONF.service_available.glance:
# Check if glance v1 is available to determine which client to use.
if CONF.image_feature_enabled.api_v1:
- cls.image_client = cls.manager.image_client
+ cls.image_client = cls.os_primary.image_client
elif CONF.image_feature_enabled.api_v2:
- cls.image_client = cls.manager.image_client_v2
+ cls.image_client = cls.os_primary.image_client_v2
else:
raise lib_exc.InvalidConfiguration(
'Either api_v1 or api_v2 must be True in '
'[image-feature-enabled].')
# Compute image client
- cls.compute_images_client = cls.manager.compute_images_client
- cls.keypairs_client = cls.manager.keypairs_client
+ cls.compute_images_client = cls.os_primary.compute_images_client
+ cls.keypairs_client = cls.os_primary.keypairs_client
# Nova security groups client
cls.compute_security_groups_client = (
- cls.manager.compute_security_groups_client)
+ cls.os_primary.compute_security_groups_client)
cls.compute_security_group_rules_client = (
- cls.manager.compute_security_group_rules_client)
- cls.servers_client = cls.manager.servers_client
- cls.interface_client = cls.manager.interfaces_client
+ cls.os_primary.compute_security_group_rules_client)
+ cls.servers_client = cls.os_primary.servers_client
+ cls.interface_client = cls.os_primary.interfaces_client
# Neutron network client
- cls.networks_client = cls.manager.networks_client
- cls.ports_client = cls.manager.ports_client
- cls.routers_client = cls.manager.routers_client
- cls.subnets_client = cls.manager.subnets_client
- cls.floating_ips_client = cls.manager.floating_ips_client
- cls.security_groups_client = cls.manager.security_groups_client
+ cls.networks_client = cls.os_primary.networks_client
+ cls.ports_client = cls.os_primary.ports_client
+ cls.routers_client = cls.os_primary.routers_client
+ cls.subnets_client = cls.os_primary.subnets_client
+ cls.floating_ips_client = cls.os_primary.floating_ips_client
+ cls.security_groups_client = cls.os_primary.security_groups_client
cls.security_group_rules_client = (
- cls.manager.security_group_rules_client)
- cls.volumes_client = cls.manager.volumes_v2_client
- cls.snapshots_client = cls.manager.snapshots_v2_client
+ cls.os_primary.security_group_rules_client)
+ cls.volumes_client = cls.os_primary.volumes_v2_client
+ cls.snapshots_client = cls.os_primary.snapshots_v2_client
# ## Test functions library
#
@@ -133,7 +133,7 @@
# Needed for the cross_tenant_traffic test:
if clients is None:
- clients = self.manager
+ clients = self.os_primary
if name is None:
name = data_utils.rand_name(self.__class__.__name__ + "-server")
@@ -195,7 +195,7 @@
tenant_network = self.get_tenant_network()
- body, servers = compute.create_test_server(
+ body, _ = compute.create_test_server(
clients,
tenant_network=tenant_network,
wait_until=wait_until,
@@ -313,13 +313,15 @@
return secgroup
- def get_remote_client(self, ip_address, username=None, private_key=None):
+ def get_remote_client(self, ip_address, username=None, private_key=None,
+ server=None):
"""Get a SSH client to a remote server
@param ip_address the server floating or fixed IP address to use
for ssh validation
@param username name of the Linux account on the remote server
@param private_key the SSH private key to use
+ @param server: server dict, used for debugging purposes
@return a RemoteClient object
"""
@@ -334,22 +336,10 @@
else:
password = CONF.validation.image_ssh_password
private_key = None
- linux_client = remote_client.RemoteClient(ip_address, username,
- pkey=private_key,
- password=password)
- try:
- linux_client.validate_authentication()
- except Exception as e:
- message = ('Initializing SSH connection to %(ip)s failed. '
- 'Error: %(error)s' % {'ip': ip_address,
- 'error': e})
- caller = test_utils.find_test_caller()
- if caller:
- message = '(%s) %s' % (caller, message)
- LOG.exception(message)
- self._log_console_output()
- raise
-
+ linux_client = remote_client.RemoteClient(
+ ip_address, username, pkey=private_key, password=password,
+ server=server, servers_client=self.servers_client)
+ linux_client.validate_authentication()
return linux_client
def _image_create(self, name, fmt, path,
@@ -741,7 +731,7 @@
:returns: True if subnet with cidr already exist in tenant
False else
"""
- cidr_in_use = self.admin_manager.subnets_client.list_subnets(
+ cidr_in_use = self.os_admin.subnets_client.list_subnets(
tenant_id=tenant_id, cidr=cidr)['subnets']
return len(cidr_in_use) != 0
@@ -790,7 +780,7 @@
return subnet
def _get_server_port_id_and_ip4(self, server, ip_addr=None):
- ports = self.admin_manager.ports_client.list_ports(
+ ports = self.os_admin.ports_client.list_ports(
device_id=server['id'], fixed_ip=ip_addr)['ports']
# A port can have more than one IP address in some cases.
# If the network is dual-stack (IPv4 + IPv6), this port is associated
@@ -811,7 +801,7 @@
if inactive:
LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
- self.assertNotEqual(0, len(port_map),
+ self.assertNotEmpty(port_map,
"No IPv4 addresses found in: %s" % ports)
self.assertEqual(len(port_map), 1,
"Found multiple IPv4 addresses: %s. "
@@ -820,9 +810,9 @@
return port_map[0]
def _get_network_by_name(self, network_name):
- net = self.admin_manager.networks_client.list_networks(
+ net = self.os_admin.networks_client.list_networks(
name=network_name)['networks']
- self.assertNotEqual(len(net), 0,
+ self.assertNotEmpty(net,
"Unable to get network by name: %s" % network_name)
return net[0]
@@ -1029,7 +1019,7 @@
if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
]
msg = "No default security group for tenant %s." % (tenant_id)
- self.assertGreater(len(sgs), 0, msg)
+ self.assertNotEmpty(sgs, msg)
return sgs[0]
def _create_security_group_rule(self, secgroup=None,
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 8408a1e..25227be 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -36,8 +36,8 @@
def setup_clients(cls):
super(TestAggregatesBasicOps, cls).setup_clients()
# Use admin client by default
- cls.aggregates_client = cls.admin_manager.aggregates_client
- cls.hosts_client = cls.admin_manager.hosts_client
+ cls.aggregates_client = cls.os_admin.aggregates_client
+ cls.hosts_client = cls.os_admin.hosts_client
def _create_aggregate(self, **kwargs):
aggregate = (self.aggregates_client.create_aggregate(**kwargs)
@@ -52,7 +52,7 @@
def _get_host_name(self):
hosts = self.hosts_client.list_hosts()['hosts']
- self.assertGreaterEqual(len(hosts), 1)
+ self.assertNotEmpty(hosts)
computes = [x for x in hosts if x['service'] == 'compute']
return computes[0]['host_name']
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 5fee801..26a834b 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -103,6 +103,8 @@
@decorators.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
+ @testtools.skipUnless(CONF.network_feature_enabled.floating_ips,
+ 'Floating ips are not available')
@test.services('compute', 'volume', 'image', 'network')
def test_minimum_basic_scenario(self):
image = self.glance_image_create()
@@ -139,14 +141,16 @@
# check that we can SSH to the server before reboot
self.linux_client = self.get_remote_client(
- floating_ip['ip'], private_key=keypair['private_key'])
+ floating_ip['ip'], private_key=keypair['private_key'],
+ server=server)
self.nova_reboot(server)
# check that we can SSH to the server after reboot
# (both connections are part of the scenario)
self.linux_client = self.get_remote_client(
- floating_ip['ip'], private_key=keypair['private_key'])
+ floating_ip['ip'], private_key=keypair['private_key'],
+ server=server)
self.check_disks()
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index c2fc1a7..c8add8b 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -48,6 +48,8 @@
msg = ('Either project_networks_reachable must be "true", or '
'public_network_id must be defined.')
raise cls.skipException(msg)
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
@classmethod
def setup_credentials(cls):
@@ -60,7 +62,7 @@
if test.is_extension_enabled('security-group', 'network'):
security_group = self._create_security_group()
security_groups = [{'name': security_group['name']}]
- network, subnet, router = self.create_networks()
+ network, _, _ = self.create_networks()
server = self.create_server(
networks=[{'uuid': network['id']}],
key_name=keypair['name'],
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 756ca4d..48ddac6 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -90,6 +90,8 @@
if not test.is_extension_enabled(ext, 'network'):
msg = "%s extension not enabled." % ext
raise cls.skipException(msg)
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
@classmethod
def setup_credentials(cls):
@@ -126,21 +128,21 @@
via checking the result of list_[networks,routers,subnets]
"""
- seen_nets = self.admin_manager.networks_client.list_networks()
+ seen_nets = self.os_admin.networks_client.list_networks()
seen_names = [n['name'] for n in seen_nets['networks']]
seen_ids = [n['id'] for n in seen_nets['networks']]
self.assertIn(self.network['name'], seen_names)
self.assertIn(self.network['id'], seen_ids)
if self.subnet:
- seen_subnets = self.admin_manager.subnets_client.list_subnets()
+ seen_subnets = self.os_admin.subnets_client.list_subnets()
seen_net_ids = [n['network_id'] for n in seen_subnets['subnets']]
seen_subnet_ids = [n['id'] for n in seen_subnets['subnets']]
self.assertIn(self.network['id'], seen_net_ids)
self.assertIn(self.subnet['id'], seen_subnet_ids)
if self.router:
- seen_routers = self.admin_manager.routers_client.list_routers()
+ seen_routers = self.os_admin.routers_client.list_routers()
seen_router_ids = [n['id'] for n in seen_routers['routers']]
seen_router_names = [n['name'] for n in seen_routers['routers']]
self.assertIn(self.router['name'],
@@ -210,7 +212,7 @@
self.servers, mtu=mtu)
def _disassociate_floating_ips(self):
- floating_ip, server = self.floating_ip_tuple
+ floating_ip, _ = self.floating_ip_tuple
self._disassociate_floating_ip(floating_ip)
self.floating_ip_tuple = Floating_IP_tuple(
floating_ip, None)
@@ -238,10 +240,10 @@
ip_address = old_floating_ip['floating_ip_address']
private_key = self._get_server_key(server)
ssh_client = self.get_remote_client(
- ip_address, private_key=private_key)
+ ip_address, private_key=private_key, server=server)
old_nic_list = self._get_server_nics(ssh_client)
# get a port from a list of one item
- port_list = self.admin_manager.ports_client.list_ports(
+ port_list = self.os_admin.ports_client.list_ports(
device_id=server['id'])['ports']
self.assertEqual(1, len(port_list))
old_port = port_list[0]
@@ -257,7 +259,7 @@
def check_ports():
self.new_port_list = [
port for port in
- self.admin_manager.ports_client.list_ports(
+ self.os_admin.ports_client.list_ports(
device_id=server['id'])['ports']
if port['id'] != old_port['id']
]
@@ -285,7 +287,7 @@
"guest after %s sec"
% CONF.network.build_timeout)
- num, new_nic = self.diff_list[0]
+ _, new_nic = self.diff_list[0]
ssh_client.exec_command("sudo ip addr add %s/%s dev %s" % (
new_port['fixed_ips'][0]['ip_address'],
CONF.network.project_network_mask_bits,
@@ -293,7 +295,7 @@
ssh_client.exec_command("sudo ip link set %s up" % new_nic)
def _get_server_nics(self, ssh_client):
- reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+):')
+ reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+)[@]?.*:')
ipatxt = ssh_client.exec_command("ip address")
return reg.findall(ipatxt)
@@ -309,7 +311,7 @@
# get all network ports in the new network
internal_ips = (
p['fixed_ips'][0]['ip_address'] for p in
- self.admin_manager.ports_client.list_ports(
+ self.os_admin.ports_client.list_ports(
tenant_id=server['tenant_id'],
network_id=network['id'])['ports']
if p['device_owner'].startswith('network')
@@ -330,7 +332,7 @@
# which is always IPv4, so we must only test connectivity to
# external IPv4 IPs if the external network is dualstack.
v4_subnets = [
- s for s in self.admin_manager.subnets_client.list_subnets(
+ s for s in self.os_admin.subnets_client.list_subnets(
network_id=CONF.network.public_network_id)['subnets']
if s['ip_version'] == 4
]
@@ -346,7 +348,8 @@
ip_address = floating_ip['floating_ip_address']
private_key = self._get_server_key(self.floating_ip_tuple.server)
ssh_source = self.get_remote_client(
- ip_address, private_key=private_key)
+ ip_address, private_key=private_key,
+ server=self.floating_ip_tuple.server)
for remote_ip in address_list:
self.check_remote_connectivity(ssh_source, remote_ip,
@@ -573,7 +576,7 @@
ip_address = floating_ip['floating_ip_address']
private_key = self._get_server_key(server)
ssh_client = self.get_remote_client(
- ip_address, private_key=private_key)
+ ip_address, private_key=private_key, server=server)
dns_servers = [initial_dns_server]
servers = ssh_client.get_dns_servers()
@@ -628,9 +631,9 @@
admin_state_up attribute of instance port to True
"""
self._setup_network_and_servers()
- floating_ip, server = self.floating_ip_tuple
+ _, server = self.floating_ip_tuple
server_id = server['id']
- port_id = self.admin_manager.ports_client.list_ports(
+ port_id = self.os_admin.ports_client.list_ports(
device_id=server_id)['ports'][0]['id']
server_pip = server['addresses'][self.network['name']][0]['addr']
@@ -639,7 +642,8 @@
private_key = self._get_server_key(server2)
ssh_client = self.get_remote_client(server2_fip['floating_ip_address'],
- private_key=private_key)
+ private_key=private_key,
+ server=server2)
self.check_public_network_connectivity(
should_connect=True, msg="before updating "
@@ -685,7 +689,7 @@
'Server should have been created from a '
'pre-existing port.')
# Assert the port is bound to the server.
- port_list = self.admin_manager.ports_client.list_ports(
+ port_list = self.os_admin.ports_client.list_ports(
device_id=server['id'], network_id=self.network['id'])['ports']
self.assertEqual(1, len(port_list),
'There should only be one port created for '
@@ -704,7 +708,7 @@
# Boot another server with the same port to make sure nothing was
# left around that could cause issues.
server = self._create_server(self.network, port['id'])
- port_list = self.admin_manager.ports_client.list_ports(
+ port_list = self.os_admin.ports_client.list_ports(
device_id=server['id'], network_id=self.network['id'])['ports']
self.assertEqual(1, len(port_list),
'There should only be one port created for '
@@ -729,23 +733,23 @@
# TODO(yfried): refactor this test to be used for other agents (dhcp)
# as well
- list_hosts = (self.admin_manager.routers_client.
+ list_hosts = (self.os_admin.routers_client.
list_l3_agents_hosting_router)
- schedule_router = (self.admin_manager.network_agents_client.
+ schedule_router = (self.os_admin.network_agents_client.
create_router_on_l3_agent)
- unschedule_router = (self.admin_manager.network_agents_client.
+ unschedule_router = (self.os_admin.network_agents_client.
delete_router_from_l3_agent)
agent_list_alive = set(
a["id"] for a in
- self.admin_manager.network_agents_client.list_agents(
+ self.os_admin.network_agents_client.list_agents(
agent_type="L3 agent")['agents'] if a["alive"] is True
)
self._setup_network_and_servers()
# NOTE(kevinbenton): we have to use the admin credentials to check
# for the distributed flag because self.router only has a project view.
- admin = self.admin_manager.routers_client.show_router(
+ admin = self.os_admin.routers_client.show_router(
self.router['id'])
if admin['router'].get('distributed', False):
msg = "Rescheduling test does not apply to distributed routers."
@@ -823,12 +827,13 @@
self._create_new_network()
self._hotplug_server()
fip, server = self.floating_ip_tuple
- new_ports = self.admin_manager.ports_client.list_ports(
+ new_ports = self.os_admin.ports_client.list_ports(
device_id=server["id"], network_id=self.new_net["id"])['ports']
spoof_port = new_ports[0]
private_key = self._get_server_key(server)
ssh_client = self.get_remote_client(fip['floating_ip_address'],
- private_key=private_key)
+ private_key=private_key,
+ server=server)
spoof_nic = ssh_client.get_nic_name_by_mac(spoof_port["mac_address"])
peer = self._create_server(self.new_net)
peer_address = peer['addresses'][self.new_net['name']][0]['addr']
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index daf4d13..bf26c2e 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -51,6 +51,8 @@
if CONF.network.shared_physical_network:
msg = 'Deployment uses a shared physical network'
raise cls.skipException(msg)
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
@classmethod
def setup_credentials(cls):
@@ -129,7 +131,7 @@
ips = self.define_server_ips(srv=srv)
ssh = self.get_remote_client(
ip_address=fip['floating_ip_address'],
- username=username)
+ username=username, server=srv)
return ssh, ips, srv["id"]
def turn_nic6_on(self, ssh, sid, network_id):
@@ -144,7 +146,7 @@
"""
ports = [
p["mac_address"] for p in
- self.admin_manager.ports_client.list_ports(
+ self.os_admin.ports_client.list_ports(
device_id=sid, network_id=network_id)['ports']
]
@@ -169,7 +171,7 @@
# Turn on 2nd NIC for Cirros when dualnet
if dualnet:
- network, network_v6 = net_list
+ _, network_v6 = net_list
self.turn_nic6_on(sshv4_1, sid1, network_v6['id'])
self.turn_nic6_on(sshv4_2, sid2, network_v6['id'])
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 2116fe8..41c60f1 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -148,6 +148,8 @@
msg = ('Deployment uses a shared physical network, security '
'groups not supported')
raise cls.skipException(msg)
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
@classmethod
def setup_credentials(cls):
@@ -168,7 +170,7 @@
cls.floating_ips = {}
cls.tenants = {}
- cls.primary_tenant = cls.TenantProperties(cls.os)
+ cls.primary_tenant = cls.TenantProperties(cls.os_primary)
cls.alt_tenant = cls.TenantProperties(cls.os_alt)
for tenant in [cls.primary_tenant, cls.alt_tenant]:
cls.tenants[tenant.creds.tenant_id] = tenant
@@ -221,7 +223,7 @@
# Checks that we see the newly created network/subnet/router via
# checking the result of list_[networks,routers,subnets]
# Check that (router, subnet) couple exist in port_list
- seen_nets = self.admin_manager.networks_client.list_networks()
+ seen_nets = self.os_admin.networks_client.list_networks()
seen_names = [n['name'] for n in seen_nets['networks']]
seen_ids = [n['id'] for n in seen_nets['networks']]
@@ -230,13 +232,13 @@
seen_subnets = [
(n['id'], n['cidr'], n['network_id']) for n in
- self.admin_manager.subnets_client.list_subnets()['subnets']
+ self.os_admin.subnets_client.list_subnets()['subnets']
]
mysubnet = (tenant.subnet['id'], tenant.subnet['cidr'],
tenant.network['id'])
self.assertIn(mysubnet, seen_subnets)
- seen_routers = self.admin_manager.routers_client.list_routers()
+ seen_routers = self.os_admin.routers_client.list_routers()
seen_router_ids = [n['id'] for n in seen_routers['routers']]
seen_router_names = [n['name'] for n in seen_routers['routers']]
@@ -246,7 +248,7 @@
myport = (tenant.router['id'], tenant.subnet['id'])
router_ports = [
(i['device_id'], f['subnet_id'])
- for i in self.admin_manager.ports_client.list_ports(
+ for i in self.os_admin.ports_client.list_ports(
device_id=tenant.router['id'])['ports']
if net_info.is_router_interface_port(i)
for f in i['fixed_ips']
@@ -279,7 +281,7 @@
# Verify servers are on different compute nodes
if self.multi_node:
- adm_get_server = self.admin_manager.servers_client.show_server
+ adm_get_server = self.os_admin.servers_client.show_server
new_host = adm_get_server(server["id"])["server"][
"OS-EXT-SRV-ATTR:host"]
host_list = [adm_get_server(s)["server"]["OS-EXT-SRV-ATTR:host"]
@@ -447,7 +449,7 @@
mac_addr = mac_addr.strip().lower()
# Get the fixed_ips and mac_address fields of all ports. Select
# only those two columns to reduce the size of the response.
- port_list = self.admin_manager.ports_client.list_ports(
+ port_list = self.os_admin.ports_client.list_ports(
fields=['fixed_ips', 'mac_address'])['ports']
port_detail_list = [
(port['fixed_ips'][0]['subnet_id'],
@@ -541,7 +543,7 @@
dest=self._get_server_ip(server),
should_succeed=False)
server_id = server['id']
- port_id = self.admin_manager.ports_client.list_ports(
+ port_id = self.os_admin.ports_client.list_ports(
device_id=server_id)['ports'][0]['id']
# update port with new security group and check connectivity
@@ -605,7 +607,7 @@
access_point_ssh = self._connect_to_access_point(new_tenant)
server_id = server['id']
- port_id = self.admin_manager.ports_client.list_ports(
+ port_id = self.os_admin.ports_client.list_ports(
device_id=server_id)['ports'][0]['id']
# Flip the port's port security and check connectivity
@@ -647,7 +649,7 @@
sec_groups = []
server = self._create_server(name, tenant, sec_groups)
server_id = server['id']
- ports = self.admin_manager.ports_client.list_ports(
+ ports = self.os_admin.ports_client.list_ports(
device_id=server_id)['ports']
self.assertEqual(1, len(ports))
for port in ports:
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 2be9e06..0c441ab 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -43,6 +43,12 @@
* Terminate the instance
"""
+ @classmethod
+ def skip_checks(cls):
+ super(TestServerBasicOps, cls).skip_checks()
+ if not CONF.network_feature_enabled.floating_ips:
+ raise cls.skipException("Floating ips are not available")
+
def setUp(self):
super(TestServerBasicOps, self).setUp()
self.run_ssh = CONF.validation.run_validation
@@ -56,7 +62,8 @@
self.ssh_client = self.get_remote_client(
ip_address=self.fip,
username=self.ssh_user,
- private_key=keypair['private_key'])
+ private_key=keypair['private_key'],
+ server=self.instance)
def verify_metadata(self):
if self.run_ssh and CONF.compute_feature_enabled.metadata_service:
diff --git a/tempest/scenario/test_server_multinode.py b/tempest/scenario/test_server_multinode.py
index d9bff09..552ab27 100644
--- a/tempest/scenario/test_server_multinode.py
+++ b/tempest/scenario/test_server_multinode.py
@@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-
from tempest import config
from tempest.lib import decorators
from tempest.lib import exceptions
@@ -35,15 +34,6 @@
raise cls.skipException(
"Less than 2 compute nodes, skipping multinode tests.")
- @classmethod
- def setup_clients(cls):
- super(TestServerMultinode, cls).setup_clients()
- # Use admin client by default
- cls.manager = cls.admin_manager
- # this is needed so that we can use the availability_zone:host
- # scheduler hint, which is admin_only by default
- cls.servers_client = cls.admin_manager.servers_client
-
@decorators.idempotent_id('9cecbe35-b9d4-48da-a37e-7ce70aa43d30')
@decorators.attr(type='smoke')
@test.services('compute', 'network')
@@ -74,9 +64,13 @@
for host in hosts[:CONF.compute.min_compute_nodes]:
# by getting to active state here, this means this has
# landed on the host in question.
+ # in order to use the availability_zone:host scheduler hint,
+ # admin client is need here.
inst = self.create_server(
+ clients=self.os_admin,
availability_zone='%(zone)s:%(host_name)s' % host)
- server = self.servers_client.show_server(inst['id'])['server']
+ server = self.os_admin.servers_client.show_server(
+ inst['id'])['server']
# ensure server is located on the requested host
self.assertEqual(host['host_name'], server['OS-EXT-SRV-ATTR:host'])
servers.append(server)
diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py
index 63dc23d..81b71b1 100644
--- a/tempest/scenario/test_volume_migrate_attached.py
+++ b/tempest/scenario/test_volume_migrate_attached.py
@@ -41,6 +41,7 @@
def setup_clients(cls):
super(TestVolumeMigrateRetypeAttached, cls).setup_clients()
cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client
+ cls.admin_volumes_client = cls.os_admin.volumes_v2_client
@classmethod
def skip_checks(cls):
@@ -82,7 +83,7 @@
def _volume_retype_with_migration(self, volume_id, new_volume_type):
migration_policy = 'on-demand'
- self.volumes_client.retype_volume(
+ self.admin_volumes_client.retype_volume(
volume_id, new_type=new_volume_type,
migration_policy=migration_policy)
waiters.wait_for_volume_retype(self.volumes_client,
diff --git a/tempest/test.py b/tempest/test.py
index f6b17ad..f07c071 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -339,24 +339,24 @@
if credentials_type == 'primary':
cls.os = debtcollector.moves.moved_read_only_property(
'os', 'os_primary', version='Pike',
- removal_version='Ocata')
+ removal_version='Queens')
cls.manager =\
debtcollector.moves.moved_read_only_property(
'manager', 'os_primary', version='Pike',
- removal_version='Ocata')
+ removal_version='Queens')
if credentials_type == 'admin':
cls.os_adm = debtcollector.moves.moved_read_only_property(
'os_adm', 'os_admin', version='Pike',
- removal_version='Ocata')
+ removal_version='Queens')
cls.admin_manager =\
debtcollector.moves.moved_read_only_property(
'admin_manager', 'os_admin', version='Pike',
- removal_version='Ocata')
+ removal_version='Queens')
if credentials_type == 'alt':
cls.alt_manager =\
debtcollector.moves.moved_read_only_property(
'alt_manager', 'os_alt', version='Pike',
- removal_version='Ocata')
+ removal_version='Queens')
elif isinstance(credentials_type, list):
manager = cls.get_client_manager(roles=credentials_type[1:],
force_new=True)
@@ -373,9 +373,9 @@
@classmethod
def resource_setup(cls):
"""Class level resource setup for test cases."""
- if hasattr(cls, "os"):
+ if hasattr(cls, "os_primary"):
cls.validation_resources = vresources.create_validation_resources(
- cls.os, cls.validation_resources)
+ cls.os_primary, cls.validation_resources)
else:
LOG.warning("Client manager not found, validation resources not"
" created")
@@ -388,8 +388,8 @@
resources, in case a failure during `resource_setup` should happen.
"""
if cls.validation_resources:
- if hasattr(cls, "os"):
- vresources.clear_validation_resources(cls.os,
+ if hasattr(cls, "os_primary"):
+ vresources.clear_validation_resources(cls.os_primary,
cls.validation_resources)
cls.validation_resources = {}
else:
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index 36062e7..b0e74fb 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -12,9 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
+import fixtures
import mock
from oslo_serialization import jsonutils as json
-from oslotest import mockpatch
from tempest.cmd import verify_tempest_config
from tempest import config
@@ -73,12 +73,12 @@
fake_config.FakePrivate)
def test_get_keystone_api_versions(self):
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, '_get_unversioned_endpoint',
return_value='http://fake_endpoint:5000'))
fake_resp = {'versions': {'values': [{'id': 'v2.0'}, {'id': 'v3.0'}]}}
fake_resp = json.dumps(fake_resp)
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.lib.common.http.ClosingHttp.request',
return_value=(None, fake_resp)))
fake_os = mock.MagicMock()
@@ -87,12 +87,12 @@
self.assertIn('v3.0', versions)
def test_get_cinder_api_versions(self):
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, '_get_unversioned_endpoint',
return_value='http://fake_endpoint:5000'))
fake_resp = {'versions': [{'id': 'v1.0'}, {'id': 'v2.0'}]}
fake_resp = json.dumps(fake_resp)
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.lib.common.http.ClosingHttp.request',
return_value=(None, fake_resp)))
fake_os = mock.MagicMock()
@@ -101,12 +101,12 @@
self.assertIn('v2.0', versions)
def test_get_nova_versions(self):
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, '_get_unversioned_endpoint',
return_value='http://fake_endpoint:5000'))
fake_resp = {'versions': [{'id': 'v2.0'}, {'id': 'v3.0'}]}
fake_resp = json.dumps(fake_resp)
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.lib.common.http.ClosingHttp.request',
return_value=(None, fake_resp)))
fake_os = mock.MagicMock()
@@ -117,17 +117,17 @@
def test_get_versions_invalid_response(self):
# When the response doesn't contain a JSON response, an error is
# logged.
- mock_log_error = self.useFixture(mockpatch.PatchObject(
+ mock_log_error = self.useFixture(fixtures.MockPatchObject(
verify_tempest_config.LOG, 'error')).mock
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, '_get_unversioned_endpoint'))
# Simulated response is not JSON.
sample_body = (
'<html><head>Sample Response</head><body>This is the sample page '
'for the web server. Why are you requesting it?</body></html>')
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.lib.common.http.ClosingHttp.request',
return_value=(None, sample_body)))
@@ -157,7 +157,7 @@
@mock.patch('tempest.lib.common.http.ClosingHttp.request')
def test_verify_keystone_api_versions_no_v3(self, mock_request):
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, '_get_unversioned_endpoint',
return_value='http://fake_endpoint:5000'))
fake_resp = {'versions': {'values': [{'id': 'v2.0'}]}}
@@ -173,7 +173,7 @@
@mock.patch('tempest.lib.common.http.ClosingHttp.request')
def test_verify_keystone_api_versions_no_v2(self, mock_request):
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, '_get_unversioned_endpoint',
return_value='http://fake_endpoint:5000'))
fake_resp = {'versions': {'values': [{'id': 'v3.0'}]}}
@@ -189,7 +189,7 @@
@mock.patch('tempest.lib.common.http.ClosingHttp.request')
def test_verify_cinder_api_versions_no_v3(self, mock_request):
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, '_get_unversioned_endpoint',
return_value='http://fake_endpoint:5000'))
fake_resp = {'versions': [{'id': 'v2.0'}]}
@@ -205,7 +205,7 @@
@mock.patch('tempest.lib.common.http.ClosingHttp.request')
def test_verify_cinder_api_versions_no_v2(self, mock_request):
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, '_get_unversioned_endpoint',
return_value='http://fake_endpoint:5000'))
fake_resp = {'versions': [{'id': 'v3.0'}]}
@@ -221,7 +221,7 @@
@mock.patch('tempest.lib.common.http.ClosingHttp.request')
def test_verify_cinder_api_versions_no_v1(self, mock_request):
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, '_get_unversioned_endpoint',
return_value='http://fake_endpoint:5000'))
fake_resp = {'versions': [{'id': 'v2.0'}, {'id': 'v3.0'}]}
@@ -274,7 +274,7 @@
fake_os = mock.MagicMock()
fake_os.network_extensions_client.list_extensions = (
fake_list_extensions)
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, 'get_enabled_extensions',
return_value=(['fake1', 'fake2', 'fake3'])))
results = verify_tempest_config.verify_extensions(fake_os,
@@ -297,7 +297,7 @@
fake_os = mock.MagicMock()
fake_os.network_extensions_client.list_extensions = (
fake_list_extensions)
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, 'get_enabled_extensions',
return_value=(['all'])))
results = verify_tempest_config.verify_extensions(fake_os,
@@ -317,7 +317,7 @@
fake_os.volumes_extension_client.list_extensions = fake_list_extensions
fake_os.volumes_v2_extension_client.list_extensions = (
fake_list_extensions)
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, 'get_enabled_extensions',
return_value=(['fake1', 'fake2', 'fake3'])))
results = verify_tempest_config.verify_extensions(fake_os,
@@ -342,7 +342,7 @@
fake_os.volumes_extension_client.list_extensions = fake_list_extensions
fake_os.volumes_v2_extension_client.list_extensions = (
fake_list_extensions)
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, 'get_enabled_extensions',
return_value=(['all'])))
results = verify_tempest_config.verify_extensions(fake_os,
@@ -358,7 +358,7 @@
{'alias': 'not_fake'}])
fake_os = mock.MagicMock()
fake_os.extensions_client.list_extensions = fake_list_extensions
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, 'get_enabled_extensions',
return_value=(['fake1', 'fake2', 'fake3'])))
results = verify_tempest_config.verify_extensions(fake_os,
@@ -380,7 +380,7 @@
{'alias': 'not_fake'}]})
fake_os = mock.MagicMock()
fake_os.extensions_client.list_extensions = fake_list_extensions
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, 'get_enabled_extensions',
return_value=(['all'])))
results = verify_tempest_config.verify_extensions(fake_os,
@@ -398,7 +398,7 @@
'swift': 'metadata'})
fake_os = mock.MagicMock()
fake_os.capabilities_client.list_capabilities = fake_list_extensions
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, 'get_enabled_extensions',
return_value=(['fake1', 'fake2', 'fake3'])))
results = verify_tempest_config.verify_extensions(fake_os, 'swift', {})
@@ -420,7 +420,7 @@
'swift': 'metadata'})
fake_os = mock.MagicMock()
fake_os.capabilities_client.list_capabilities = fake_list_extensions
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
verify_tempest_config, 'get_enabled_extensions',
return_value=(['all'])))
results = verify_tempest_config.verify_extensions(fake_os,
diff --git a/tempest/tests/common/test_admin_available.py b/tempest/tests/common/test_admin_available.py
index 01a9cd0..c3d248c 100644
--- a/tempest/tests/common/test_admin_available.py
+++ b/tempest/tests/common/test_admin_available.py
@@ -12,8 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import fixtures
from oslo_config import cfg
-from oslotest import mockpatch
from tempest.common import credentials_factory as credentials
from tempest import config
@@ -52,16 +52,16 @@
'project_name': 'admin',
'password': 'p',
'types': ['admin']})
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.common.preprov_creds.read_accounts_yaml',
return_value=accounts))
cfg.CONF.set_default('test_accounts_file',
use_accounts_file, group='auth')
- self.useFixture(mockpatch.Patch('os.path.isfile',
- return_value=True))
+ self.useFixture(fixtures.MockPatch('os.path.isfile',
+ return_value=True))
else:
- self.useFixture(mockpatch.Patch('os.path.isfile',
- return_value=False))
+ self.useFixture(fixtures.MockPatch('os.path.isfile',
+ return_value=False))
if admin_creds:
username = 'u'
project = 't'
diff --git a/tempest/tests/common/test_alt_available.py b/tempest/tests/common/test_alt_available.py
index 27db95c..b9a8967 100644
--- a/tempest/tests/common/test_alt_available.py
+++ b/tempest/tests/common/test_alt_available.py
@@ -12,8 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import fixtures
from oslo_config import cfg
-from oslotest import mockpatch
from tempest.common import credentials_factory as credentials
from tempest import config
@@ -39,16 +39,16 @@
accounts = [dict(username="u%s" % ii,
project_name="t%s" % ii,
password="p") for ii in creds]
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.common.preprov_creds.read_accounts_yaml',
return_value=accounts))
cfg.CONF.set_default('test_accounts_file',
use_accounts_file, group='auth')
- self.useFixture(mockpatch.Patch('os.path.isfile',
- return_value=True))
+ self.useFixture(fixtures.MockPatch('os.path.isfile',
+ return_value=True))
else:
- self.useFixture(mockpatch.Patch('os.path.isfile',
- return_value=False))
+ self.useFixture(fixtures.MockPatch('os.path.isfile',
+ return_value=False))
expected = len(set(creds)) > 1 or dynamic_creds
observed = credentials.is_alt_available(
identity_version=self.identity_version)
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index b4fbd50..c739619 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -12,9 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
+import fixtures
import mock
from oslo_config import cfg
-from oslotest import mockpatch
from tempest.common import credentials_factory as credentials
from tempest.common import dynamic_creds
@@ -84,7 +84,7 @@
tenant_name='fake_tenant')
def _mock_user_create(self, id, name):
- user_fix = self.useFixture(mockpatch.PatchObject(
+ user_fix = self.useFixture(fixtures.MockPatchObject(
self.users_client.UsersClient,
'create_user',
return_value=(rest_client.ResponseBody
@@ -92,7 +92,7 @@
return user_fix
def _mock_tenant_create(self, id, name):
- tenant_fix = self.useFixture(mockpatch.PatchObject(
+ tenant_fix = self.useFixture(fixtures.MockPatchObject(
self.tenants_client.TenantsClient,
'create_tenant',
return_value=(rest_client.ResponseBody
@@ -100,7 +100,7 @@
return tenant_fix
def _mock_list_roles(self, id, name):
- roles_fix = self.useFixture(mockpatch.PatchObject(
+ roles_fix = self.useFixture(fixtures.MockPatchObject(
self.roles_client.RolesClient,
'list_roles',
return_value=(rest_client.ResponseBody
@@ -111,7 +111,7 @@
return roles_fix
def _mock_list_2_roles(self):
- roles_fix = self.useFixture(mockpatch.PatchObject(
+ roles_fix = self.useFixture(fixtures.MockPatchObject(
self.roles_client.RolesClient,
'list_roles',
return_value=(rest_client.ResponseBody
@@ -122,7 +122,7 @@
return roles_fix
def _mock_assign_user_role(self):
- tenant_fix = self.useFixture(mockpatch.PatchObject(
+ tenant_fix = self.useFixture(fixtures.MockPatchObject(
self.roles_client.RolesClient,
'create_user_role_on_project',
return_value=(rest_client.ResponseBody
@@ -130,7 +130,7 @@
return tenant_fix
def _mock_list_role(self):
- roles_fix = self.useFixture(mockpatch.PatchObject(
+ roles_fix = self.useFixture(fixtures.MockPatchObject(
self.roles_client.RolesClient,
'list_roles',
return_value=(rest_client.ResponseBody
@@ -140,7 +140,7 @@
return roles_fix
def _mock_list_ec2_credentials(self, user_id, tenant_id):
- ec2_creds_fix = self.useFixture(mockpatch.PatchObject(
+ ec2_creds_fix = self.useFixture(fixtures.MockPatchObject(
self.users_client.UsersClient,
'list_user_ec2_credentials',
return_value=(rest_client.ResponseBody
@@ -153,21 +153,21 @@
return ec2_creds_fix
def _mock_network_create(self, iso_creds, id, name):
- net_fix = self.useFixture(mockpatch.PatchObject(
+ net_fix = self.useFixture(fixtures.MockPatchObject(
iso_creds.networks_admin_client,
'create_network',
return_value={'network': {'id': id, 'name': name}}))
return net_fix
def _mock_subnet_create(self, iso_creds, id, name):
- subnet_fix = self.useFixture(mockpatch.PatchObject(
+ subnet_fix = self.useFixture(fixtures.MockPatchObject(
iso_creds.subnets_admin_client,
'create_subnet',
return_value={'subnet': {'id': id, 'name': name}}))
return subnet_fix
def _mock_router_create(self, id, name):
- router_fix = self.useFixture(mockpatch.PatchObject(
+ router_fix = self.useFixture(fixtures.MockPatchObject(
routers_client.RoutersClient,
'create_router',
return_value={'router': {'id': id, 'name': name}}))
@@ -634,7 +634,7 @@
def setUp(self):
super(TestDynamicCredentialProviderV3, self).setUp()
self.useFixture(fake_config.ConfigFixture())
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
domains_client.DomainsClient, 'list_domains',
return_value=dict(domains=[dict(id='default',
name='Default')])))
@@ -645,7 +645,7 @@
pass
def _mock_tenant_create(self, id, name):
- project_fix = self.useFixture(mockpatch.PatchObject(
+ project_fix = self.useFixture(fixtures.MockPatchObject(
self.tenants_client.ProjectsClient,
'create_project',
return_value=(rest_client.ResponseBody
diff --git a/tempest/tests/common/test_preprov_creds.py b/tempest/tests/common/test_preprov_creds.py
index 2fd375d..414b106 100644
--- a/tempest/tests/common/test_preprov_creds.py
+++ b/tempest/tests/common/test_preprov_creds.py
@@ -20,9 +20,9 @@
import six
import testtools
+import fixtures
from oslo_concurrency.fixture import lockutils as lockutils_fixtures
from oslo_config import cfg
-from oslotest import mockpatch
from tempest.common import preprov_creds
from tempest import config
@@ -86,10 +86,11 @@
self.patch(self.token_client, side_effect=self.identity_response)
self.useFixture(lockutils_fixtures.ExternalLockFixture())
self.test_accounts = self._fake_accounts(cfg.CONF.identity.admin_role)
- self.accounts_mock = self.useFixture(mockpatch.Patch(
+ self.accounts_mock = self.useFixture(fixtures.MockPatch(
'tempest.common.preprov_creds.read_accounts_yaml',
return_value=self.test_accounts))
- self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+ self.useFixture(fixtures.MockPatch(
+ 'os.path.isfile', return_value=True))
def tearDown(self):
super(TestPreProvisionedCredentials, self).tearDown()
@@ -138,7 +139,8 @@
def test_create_hash_file_previous_file(self):
# Emulate the lock existing on the filesystem
- self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+ self.useFixture(fixtures.MockPatch(
+ 'os.path.isfile', return_value=True))
with mock.patch('six.moves.builtins.open', mock.mock_open(),
create=True):
test_account_class = (
@@ -150,7 +152,8 @@
def test_create_hash_file_no_previous_file(self):
# Emulate the lock not existing on the filesystem
- self.useFixture(mockpatch.Patch('os.path.isfile', return_value=False))
+ self.useFixture(fixtures.MockPatch(
+ 'os.path.isfile', return_value=False))
with mock.patch('six.moves.builtins.open', mock.mock_open(),
create=True):
test_account_class = (
@@ -163,10 +166,12 @@
@mock.patch('oslo_concurrency.lockutils.lock')
def test_get_free_hash_no_previous_accounts(self, lock_mock):
# Emulate no pre-existing lock
- self.useFixture(mockpatch.Patch('os.path.isdir', return_value=False))
+ self.useFixture(fixtures.MockPatch(
+ 'os.path.isdir', return_value=False))
hash_list = self._get_hash_list(self.test_accounts)
- mkdir_mock = self.useFixture(mockpatch.Patch('os.mkdir'))
- self.useFixture(mockpatch.Patch('os.path.isfile', return_value=False))
+ mkdir_mock = self.useFixture(fixtures.MockPatch('os.mkdir'))
+ self.useFixture(fixtures.MockPatch(
+ 'os.path.isfile', return_value=False))
test_account_class = preprov_creds.PreProvisionedCredentialProvider(
**self.fixed_params)
with mock.patch('six.moves.builtins.open', mock.mock_open(),
@@ -182,9 +187,10 @@
def test_get_free_hash_no_free_accounts(self, lock_mock):
hash_list = self._get_hash_list(self.test_accounts)
# Emulate pre-existing lock dir
- self.useFixture(mockpatch.Patch('os.path.isdir', return_value=True))
- # Emulate all lcoks in list are in use
- self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+ self.useFixture(fixtures.MockPatch('os.path.isdir', return_value=True))
+ # Emulate all locks in list are in use
+ self.useFixture(fixtures.MockPatch(
+ 'os.path.isfile', return_value=True))
test_account_class = preprov_creds.PreProvisionedCredentialProvider(
**self.fixed_params)
with mock.patch('six.moves.builtins.open', mock.mock_open(),
@@ -195,7 +201,7 @@
@mock.patch('oslo_concurrency.lockutils.lock')
def test_get_free_hash_some_in_use_accounts(self, lock_mock):
# Emulate no pre-existing lock
- self.useFixture(mockpatch.Patch('os.path.isdir', return_value=True))
+ self.useFixture(fixtures.MockPatch('os.path.isdir', return_value=True))
hash_list = self._get_hash_list(self.test_accounts)
test_account_class = preprov_creds.PreProvisionedCredentialProvider(
**self.fixed_params)
@@ -219,13 +225,14 @@
def test_remove_hash_last_account(self, lock_mock):
hash_list = self._get_hash_list(self.test_accounts)
# Pretend the pseudo-lock is there
- self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+ self.useFixture(
+ fixtures.MockPatch('os.path.isfile', return_value=True))
# Pretend the lock dir is empty
- self.useFixture(mockpatch.Patch('os.listdir', return_value=[]))
+ self.useFixture(fixtures.MockPatch('os.listdir', return_value=[]))
test_account_class = preprov_creds.PreProvisionedCredentialProvider(
**self.fixed_params)
- remove_mock = self.useFixture(mockpatch.Patch('os.remove'))
- rmdir_mock = self.useFixture(mockpatch.Patch('os.rmdir'))
+ remove_mock = self.useFixture(fixtures.MockPatch('os.remove'))
+ rmdir_mock = self.useFixture(fixtures.MockPatch('os.rmdir'))
test_account_class.remove_hash(hash_list[2])
hash_path = os.path.join(self.fixed_params['accounts_lock_dir'],
hash_list[2])
@@ -237,14 +244,15 @@
def test_remove_hash_not_last_account(self, lock_mock):
hash_list = self._get_hash_list(self.test_accounts)
# Pretend the pseudo-lock is there
- self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+ self.useFixture(fixtures.MockPatch(
+ 'os.path.isfile', return_value=True))
# Pretend the lock dir is empty
- self.useFixture(mockpatch.Patch('os.listdir', return_value=[
+ self.useFixture(fixtures.MockPatch('os.listdir', return_value=[
hash_list[1], hash_list[4]]))
test_account_class = preprov_creds.PreProvisionedCredentialProvider(
**self.fixed_params)
- remove_mock = self.useFixture(mockpatch.Patch('os.remove'))
- rmdir_mock = self.useFixture(mockpatch.Patch('os.rmdir'))
+ remove_mock = self.useFixture(fixtures.MockPatch('os.remove'))
+ rmdir_mock = self.useFixture(fixtures.MockPatch('os.rmdir'))
test_account_class.remove_hash(hash_list[2])
hash_path = os.path.join(self.fixed_params['accounts_lock_dir'],
hash_list[2])
@@ -258,7 +266,7 @@
def test_is_not_multi_user(self):
self.test_accounts = [self.test_accounts[0]]
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.common.preprov_creds.read_accounts_yaml',
return_value=self.test_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
@@ -270,7 +278,7 @@
**self.fixed_params)
hashes = test_accounts_class.hash_dict['roles']['role4']
temp_hash = hashes[0]
- get_free_hash_mock = self.useFixture(mockpatch.PatchObject(
+ get_free_hash_mock = self.useFixture(fixtures.MockPatchObject(
test_accounts_class, '_get_free_hash', return_value=temp_hash))
# Test a single role returns all matching roles
test_accounts_class._get_creds(roles=['role4'])
@@ -287,7 +295,7 @@
hashes2 = test_accounts_class.hash_dict['roles']['role2']
hashes = list(set(hashes) & set(hashes2))
temp_hash = hashes[0]
- get_free_hash_mock = self.useFixture(mockpatch.PatchObject(
+ get_free_hash_mock = self.useFixture(fixtures.MockPatchObject(
test_accounts_class, '_get_free_hash', return_value=temp_hash))
# Test an intersection of multiple roles
test_accounts_class._get_creds(roles=['role2', 'role4'])
@@ -304,7 +312,7 @@
admin_hashes = test_accounts_class.hash_dict['roles'][
cfg.CONF.identity.admin_role]
temp_hash = hashes[0]
- get_free_hash_mock = self.useFixture(mockpatch.PatchObject(
+ get_free_hash_mock = self.useFixture(fixtures.MockPatchObject(
test_accounts_class, '_get_free_hash', return_value=temp_hash))
# Test an intersection of multiple roles
test_accounts_class._get_creds()
@@ -322,7 +330,7 @@
{'username': 'test_user14', 'tenant_name': 'test_tenant14',
'password': 'p', 'roles': ['role-7', 'role-11'],
'resources': {'network': 'network-2'}}]
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.common.preprov_creds.read_accounts_yaml',
return_value=test_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
@@ -350,7 +358,7 @@
def test_get_primary_creds_none_available(self):
admin_accounts = [x for x in self.test_accounts if 'test_admin'
in x['username']]
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.common.preprov_creds.read_accounts_yaml',
return_value=admin_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
@@ -368,7 +376,7 @@
def test_get_alt_creds_none_available(self):
admin_accounts = [x for x in self.test_accounts if 'test_admin'
in x['username']]
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.common.preprov_creds.read_accounts_yaml',
return_value=admin_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
@@ -389,7 +397,7 @@
'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']},
{'username': 'test_admin1', 'tenant_name': 'test_tenant11',
'password': 'p', 'types': ['admin']}]
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.common.preprov_creds.read_accounts_yaml',
return_value=test_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
@@ -403,7 +411,7 @@
'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']},
{'username': 'test_admin1', 'tenant_name': 'test_tenant11',
'password': 'p', 'roles': [cfg.CONF.identity.admin_role]}]
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.common.preprov_creds.read_accounts_yaml',
return_value=test_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
@@ -414,7 +422,7 @@
def test_get_admin_creds_none_available(self):
non_admin_accounts = [x for x in self.test_accounts if 'test_admin'
not in x['username']]
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.common.preprov_creds.read_accounts_yaml',
return_value=non_admin_accounts))
test_accounts_class = preprov_creds.PreProvisionedCredentialProvider(
diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py
index ecb8e64..739357b 100644
--- a/tempest/tests/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/common/utils/linux/test_remote_client.py
@@ -16,7 +16,6 @@
import fixtures
from oslo_config import cfg
-from oslotest import mockpatch
from tempest.common.utils.linux import remote_client
from tempest import config
@@ -64,8 +63,8 @@
cfg.CONF.set_default('connect_timeout', 1, group='validation')
self.conn = remote_client.RemoteClient('127.0.0.1', 'user', 'pass')
- self.ssh_mock = self.useFixture(mockpatch.PatchObject(self.conn,
- 'ssh_client'))
+ self.ssh_mock = self.useFixture(fixtures.MockPatchObject(self.conn,
+ 'ssh_client'))
def test_write_to_console_regular_str(self):
self.conn.write_to_console('test')
@@ -111,7 +110,7 @@
booted_at = 10000
uptime_sec = 5000.02
self.ssh_mock.mock.exec_command.return_value = uptime_sec
- self.useFixture(mockpatch.PatchObject(
+ self.useFixture(fixtures.MockPatchObject(
time, 'time', return_value=booted_at + uptime_sec))
self.assertEqual(self.conn.get_boot_time(),
time.localtime(booted_at))
diff --git a/tempest/tests/lib/test_rest_client.py b/tempest/tests/lib/common/test_rest_client.py
similarity index 96%
rename from tempest/tests/lib/test_rest_client.py
rename to tempest/tests/lib/common/test_rest_client.py
index 43bb6d0..4c0bb57 100644
--- a/tempest/tests/lib/test_rest_client.py
+++ b/tempest/tests/lib/common/test_rest_client.py
@@ -15,8 +15,8 @@
import copy
import json
+import fixtures
import jsonschema
-from oslotest import mockpatch
import six
from tempest.lib.common import http
@@ -38,16 +38,16 @@
self.rest_client = rest_client.RestClient(
self.fake_auth_provider, None, None)
self.patchobject(http.ClosingHttp, 'request', self.fake_http.request)
- self.useFixture(mockpatch.PatchObject(self.rest_client,
- '_log_request'))
+ self.useFixture(fixtures.MockPatchObject(self.rest_client,
+ '_log_request'))
class TestRestClientHTTPMethods(BaseRestClientTestClass):
def setUp(self):
self.fake_http = fake_http.fake_httplib2()
super(TestRestClientHTTPMethods, self).setUp()
- self.useFixture(mockpatch.PatchObject(self.rest_client,
- '_error_checker'))
+ self.useFixture(fixtures.MockPatchObject(self.rest_client,
+ '_error_checker'))
def test_post(self):
__, return_dict = self.rest_client.post(self.url, {}, {})
@@ -70,8 +70,8 @@
self.assertEqual('PUT', return_dict['method'])
def test_head(self):
- self.useFixture(mockpatch.PatchObject(self.rest_client,
- 'response_checker'))
+ self.useFixture(fixtures.MockPatchObject(self.rest_client,
+ 'response_checker'))
__, return_dict = self.rest_client.head(self.url)
self.assertEqual('HEAD', return_dict['method'])
@@ -122,8 +122,8 @@
self._verify_headers(resp)
def test_head(self):
- self.useFixture(mockpatch.PatchObject(self.rest_client,
- 'response_checker'))
+ self.useFixture(fixtures.MockPatchObject(self.rest_client,
+ 'response_checker'))
resp, __ = self.rest_client.head(self.url)
self._verify_headers(resp)
@@ -136,8 +136,8 @@
def setUp(self):
self.fake_http = fake_http.fake_httplib2()
super(TestRestClientUpdateHeaders, self).setUp()
- self.useFixture(mockpatch.PatchObject(self.rest_client,
- '_error_checker'))
+ self.useFixture(fixtures.MockPatchObject(self.rest_client,
+ '_error_checker'))
self.headers = {'X-Configuration-Session': 'session_id'}
def test_post_update_headers(self):
@@ -201,8 +201,8 @@
)
def test_head_update_headers(self):
- self.useFixture(mockpatch.PatchObject(self.rest_client,
- 'response_checker'))
+ self.useFixture(fixtures.MockPatchObject(self.rest_client,
+ 'response_checker'))
__, return_dict = self.rest_client.head(self.url,
extra_headers=True,
@@ -276,6 +276,11 @@
body = self.rest_client._parse_resp(json.dumps(self.null_dict))
self.assertEqual(self.null_dict, body)
+ def test_parse_empty_list(self):
+ empty_list = []
+ body = self.rest_client._parse_resp(json.dumps(empty_list))
+ self.assertEqual(empty_list, body)
+
class TestRestClientErrorCheckerJSON(base.TestCase):
c_type = "application/json"
@@ -1145,8 +1150,8 @@
}
def test_current_json_schema_validator_version(self):
- with mockpatch.PatchObject(jsonschema.Draft4Validator,
- "check_schema") as chk_schema:
+ with fixtures.MockPatchObject(jsonschema.Draft4Validator,
+ "check_schema") as chk_schema:
body = {'foo': 'test'}
self._test_validate_pass(self.schema, body)
chk_schema.mock.assert_called_once_with(
diff --git a/tempest/tests/lib/services/base.py b/tempest/tests/lib/services/base.py
index a244aa2..90c9f63 100644
--- a/tempest/tests/lib/services/base.py
+++ b/tempest/tests/lib/services/base.py
@@ -12,8 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import fixtures
from oslo_serialization import jsonutils as json
-from oslotest import mockpatch
from tempest.tests import base
from tempest.tests.lib import fake_http
@@ -31,12 +31,42 @@
def check_service_client_function(self, function, function2mock,
body, to_utf=False, status=200,
- headers=None, **kwargs):
+ headers=None, mock_args=None,
+ **kwargs):
+ """Mock a service client function for unit testing.
+
+ :param function: The service client function to call.
+ :param function2mock: The REST call to mock inside the service client
+ function.
+ :param body: Expected response body returned by the service client
+ function.
+ :param to_utf: Whether to use UTF-8 encoding for request.
+ :param status: Expected response status returned by the service client
+ function.
+ :param headers: Expected headers returned by the service client
+ function.
+ :param mock_args: List/dict/value of expected args/kwargs called by
+ function2mock. For example:
+ * If mock_args=['foo'] then ``assert_called_once_with('foo')``
+ is called.
+ * If mock_args={'foo': 'bar'} then
+ ``assert_called_once_with(foo='bar')`` is called.
+ * If mock_args='foo' then ``assert_called_once_with('foo')``
+ is called.
+ :param kwargs: kwargs that are passed to function.
+ """
mocked_response = self.create_response(body, to_utf, status, headers)
- self.useFixture(mockpatch.Patch(
+ fixture = self.useFixture(fixtures.MockPatch(
function2mock, return_value=mocked_response))
if kwargs:
resp = function(**kwargs)
else:
resp = function()
self.assertEqual(body, resp)
+
+ if isinstance(mock_args, list):
+ fixture.mock.assert_called_once_with(*mock_args)
+ elif isinstance(mock_args, dict):
+ fixture.mock.assert_called_once_with(**mock_args)
+ elif mock_args is not None:
+ fixture.mock.assert_called_once_with(mock_args)
diff --git a/tempest/tests/lib/services/compute/test_flavors_client.py b/tempest/tests/lib/services/compute/test_flavors_client.py
index 445ee22..cbd17c6 100644
--- a/tempest/tests/lib/services/compute/test_flavors_client.py
+++ b/tempest/tests/lib/services/compute/test_flavors_client.py
@@ -14,8 +14,8 @@
import copy
+import fixtures
from oslo_serialization import jsonutils as json
-from oslotest import mockpatch
from tempest.lib.services.compute import flavors_client
from tempest.tests.lib import fake_auth_provider
@@ -118,7 +118,7 @@
if bytes_body:
body = body.encode('utf-8')
response = fake_http.fake_http_response({}, status=200), body
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.lib.common.rest_client.RestClient.get',
return_value=response))
self.assertEqual(is_deleted,
diff --git a/tempest/tests/lib/services/compute/test_floating_ips_client.py b/tempest/tests/lib/services/compute/test_floating_ips_client.py
index 92737f2..950f9ce 100644
--- a/tempest/tests/lib/services/compute/test_floating_ips_client.py
+++ b/tempest/tests/lib/services/compute/test_floating_ips_client.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from oslotest import mockpatch
+import fixtures
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import floating_ips_client
@@ -99,14 +99,14 @@
server_id='c782b7a9-33cd-45f0-b795-7f87f456408b')
def test_is_resource_deleted_true(self):
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.lib.services.compute.floating_ips_client.'
'FloatingIPsClient.show_floating_ip',
side_effect=lib_exc.NotFound()))
self.assertTrue(self.client.is_resource_deleted('fake-id'))
def test_is_resource_deleted_false(self):
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.lib.services.compute.floating_ips_client.'
'FloatingIPsClient.show_floating_ip',
return_value={"floating_ip": TestFloatingIpsClient.floating_ip}))
diff --git a/tempest/tests/lib/services/compute/test_images_client.py b/tempest/tests/lib/services/compute/test_images_client.py
index a9a570d..c2c3b76 100644
--- a/tempest/tests/lib/services/compute/test_images_client.py
+++ b/tempest/tests/lib/services/compute/test_images_client.py
@@ -14,8 +14,7 @@
import copy
-from oslotest import mockpatch
-
+import fixtures
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import images_client
from tempest.tests.lib import fake_auth_provider
@@ -187,15 +186,15 @@
def _test_resource_deleted(self, bytes_body=False):
params = {"id": self.FAKE_IMAGE_ID}
expected_op = self.FAKE_IMAGE_DATA['show']
- self.useFixture(mockpatch.Patch('tempest.lib.services.compute'
+ self.useFixture(fixtures.MockPatch('tempest.lib.services.compute'
'.images_client.ImagesClient.show_image',
- side_effect=lib_exc.NotFound))
+ side_effect=lib_exc.NotFound))
self.assertEqual(True, self.client.is_resource_deleted(**params))
tempdata = copy.deepcopy(self.FAKE_IMAGE_DATA['show'])
tempdata['image']['id'] = None
- self.useFixture(mockpatch.Patch('tempest.lib.services.compute'
+ self.useFixture(fixtures.MockPatch('tempest.lib.services.compute'
'.images_client.ImagesClient.show_image',
- return_value=expected_op))
+ return_value=expected_op))
self.assertEqual(False, self.client.is_resource_deleted(**params))
def test_list_images_with_str_body(self):
diff --git a/tempest/tests/lib/services/compute/test_security_groups_client.py b/tempest/tests/lib/services/compute/test_security_groups_client.py
index d293a08..7bbf20e 100644
--- a/tempest/tests/lib/services/compute/test_security_groups_client.py
+++ b/tempest/tests/lib/services/compute/test_security_groups_client.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from oslotest import mockpatch
+import fixtures
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import security_groups_client
@@ -103,11 +103,11 @@
def test_is_resource_deleted_true(self):
mod = ('tempest.lib.services.compute.security_groups_client.'
'SecurityGroupsClient.show_security_group')
- self.useFixture(mockpatch.Patch(mod, side_effect=lib_exc.NotFound))
+ self.useFixture(fixtures.MockPatch(mod, side_effect=lib_exc.NotFound))
self.assertTrue(self.client.is_resource_deleted('fake-id'))
def test_is_resource_deleted_false(self):
mod = ('tempest.lib.services.compute.security_groups_client.'
'SecurityGroupsClient.show_security_group')
- self.useFixture(mockpatch.Patch(mod, return_value='success'))
+ self.useFixture(fixtures.MockPatch(mod, return_value='success'))
self.assertFalse(self.client.is_resource_deleted('fake-id'))
diff --git a/tempest/tests/lib/services/compute/test_server_groups_client.py b/tempest/tests/lib/services/compute/test_server_groups_client.py
index bf03b84..9055a36 100644
--- a/tempest/tests/lib/services/compute/test_server_groups_client.py
+++ b/tempest/tests/lib/services/compute/test_server_groups_client.py
@@ -12,10 +12,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-from oslotest import mockpatch
-from tempest.tests.lib import fake_auth_provider
+import fixtures
+from tempest.lib.services.compute import base_compute_client
from tempest.lib.services.compute import server_groups_client
+from tempest.tests.lib import fake_auth_provider
from tempest.tests.lib import fake_http
from tempest.tests.lib.services import base
@@ -36,7 +37,7 @@
fake_auth, 'compute', 'regionOne')
def _test_create_server_group(self, bytes_body=False):
- expected = {"server_group": TestServerGroupsClient.server_group}
+ expected = {"server_group": self.server_group}
self.check_service_client_function(
self.client.create_server_group,
'tempest.lib.common.rest_client.RestClient.post', expected,
@@ -50,13 +51,13 @@
def test_delete_server_group(self):
response = fake_http.fake_http_response({}, status=204), ''
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
'tempest.lib.common.rest_client.RestClient.delete',
return_value=response))
self.client.delete_server_group('fake-group')
def _test_list_server_groups(self, bytes_body=False):
- expected = {"server_groups": [TestServerGroupsClient.server_group]}
+ expected = {"server_groups": [self.server_group]}
self.check_service_client_function(
self.client.list_server_groups,
'tempest.lib.common.rest_client.RestClient.get',
@@ -69,7 +70,7 @@
self._test_list_server_groups(bytes_body=True)
def _test_show_server_group(self, bytes_body=False):
- expected = {"server_group": TestServerGroupsClient.server_group}
+ expected = {"server_group": self.server_group}
self.check_service_client_function(
self.client.show_server_group,
'tempest.lib.common.rest_client.RestClient.get',
@@ -81,3 +82,20 @@
def test_show_server_group_byte_body(self):
self._test_show_server_group(bytes_body=True)
+
+
+class TestServerGroupsClientMinV213(TestServerGroupsClient):
+
+ server_group = {
+ "id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9",
+ "name": "test",
+ "policies": ["anti-affinity"],
+ "members": [],
+ "metadata": {},
+ "project_id": "0beb4bffb7a445eb8eb05fee3ee7660a",
+ "user_id": "86031628064a4f99bb66ec03c507dcd8"}
+
+ def setUp(self):
+ super(TestServerGroupsClientMinV213, self).setUp()
+ self.patchobject(base_compute_client, 'COMPUTE_MICROVERSION',
+ new='2.13')
diff --git a/tempest/tests/lib/services/compute/test_snapshots_client.py b/tempest/tests/lib/services/compute/test_snapshots_client.py
index 1629943..1e2902c 100644
--- a/tempest/tests/lib/services/compute/test_snapshots_client.py
+++ b/tempest/tests/lib/services/compute/test_snapshots_client.py
@@ -12,7 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from oslotest import mockpatch
+import fixtures
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import snapshots_client
@@ -91,13 +91,13 @@
def test_is_resource_deleted_true(self):
module = ('tempest.lib.services.compute.snapshots_client.'
'SnapshotsClient.show_snapshot')
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
module, side_effect=lib_exc.NotFound))
self.assertTrue(self.client.is_resource_deleted('fake-id'))
def test_is_resource_deleted_false(self):
module = ('tempest.lib.services.compute.snapshots_client.'
'SnapshotsClient.show_snapshot')
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
module, return_value={}))
self.assertFalse(self.client.is_resource_deleted('fake-id'))
diff --git a/tempest/tests/lib/services/compute/test_versions_client.py b/tempest/tests/lib/services/compute/test_versions_client.py
index 255a0a3..40d424f 100644
--- a/tempest/tests/lib/services/compute/test_versions_client.py
+++ b/tempest/tests/lib/services/compute/test_versions_client.py
@@ -14,7 +14,7 @@
import copy
-from oslotest import mockpatch
+import fixtures
from tempest.lib.services.compute import versions_client
from tempest.tests.lib import fake_auth_provider
@@ -73,7 +73,7 @@
200)
def _test_get_version_by_url(self, bytes_body=False):
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
"tempest.lib.common.rest_client.RestClient.token",
return_value="Dummy Token"))
params = {"version_url": self.versions_client._get_base_version_url()}
diff --git a/tempest/tests/lib/services/compute/test_volumes_client.py b/tempest/tests/lib/services/compute/test_volumes_client.py
index b81cdbb..4b4f02e 100644
--- a/tempest/tests/lib/services/compute/test_volumes_client.py
+++ b/tempest/tests/lib/services/compute/test_volumes_client.py
@@ -14,7 +14,7 @@
import copy
-from oslotest import mockpatch
+import fixtures
from tempest.lib import exceptions as lib_exc
from tempest.lib.services.compute import volumes_client
@@ -102,13 +102,13 @@
def test_is_resource_deleted_true(self):
module = ('tempest.lib.services.compute.volumes_client.'
'VolumesClient.show_volume')
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
module, side_effect=lib_exc.NotFound))
self.assertTrue(self.client.is_resource_deleted('fake-id'))
def test_is_resource_deleted_false(self):
module = ('tempest.lib.services.compute.volumes_client.'
'VolumesClient.show_volume')
- self.useFixture(mockpatch.Patch(
+ self.useFixture(fixtures.MockPatch(
module, return_value={}))
self.assertFalse(self.client.is_resource_deleted('fake-id'))
diff --git a/tempest/tests/lib/services/identity/v2/test_identity_client.py b/tempest/tests/lib/services/identity/v2/test_identity_client.py
index 96d50d7..303d1f7 100644
--- a/tempest/tests/lib/services/identity/v2/test_identity_client.py
+++ b/tempest/tests/lib/services/identity/v2/test_identity_client.py
@@ -26,6 +26,33 @@
}
}
+ FAKE_ENDPOINTS_FOR_TOKEN = {
+ "endpoints_links": [],
+ "endpoints": [
+ {
+ "name": "nova",
+ "adminURL": "https://nova.region-one.internal.com/" +
+ "v2/be1319401cfa4a0aa590b97cc7b64d8d",
+ "region": "RegionOne",
+ "internalURL": "https://nova.region-one.internal.com/" +
+ "v2/be1319401cfa4a0aa590b97cc7b64d8d",
+ "type": "compute",
+ "id": "11b41ee1b00841128b7333d4bf1a6140",
+ "publicURL": "https://nova.region-one.public.com/v2/" +
+ "be1319401cfa4a0aa590b97cc7b64d8d"
+ },
+ {
+ "name": "neutron",
+ "adminURL": "https://neutron.region-one.internal.com/",
+ "region": "RegionOne",
+ "internalURL": "https://neutron.region-one.internal.com/",
+ "type": "network",
+ "id": "cdbfa3c416d741a9b5c968f2dc628acb",
+ "publicURL": "https://neutron.region-one.public.com/"
+ }
+ ]
+ }
+
FAKE_API_INFO = {
"name": "API_info",
"type": "API",
@@ -148,6 +175,22 @@
bytes_body,
token_id="cbc36478b0bd8e67e89")
+ def _test_list_endpoints_for_token(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_endpoints_for_token,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_ENDPOINTS_FOR_TOKEN,
+ bytes_body,
+ token_id="cbc36478b0bd8e67e89")
+
+ def _test_check_token_existence(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.check_token_existence,
+ 'tempest.lib.common.rest_client.RestClient.head',
+ {},
+ bytes_body,
+ token_id="cbc36478b0bd8e67e89")
+
def test_show_api_description_with_str_body(self):
self._test_show_api_description()
@@ -166,6 +209,18 @@
def test_show_token_with_bytes_body(self):
self._test_show_token(bytes_body=True)
+ def test_list_endpoints_for_token_with_str_body(self):
+ self._test_list_endpoints_for_token()
+
+ def test_list_endpoints_for_token_with_bytes_body(self):
+ self._test_list_endpoints_for_token(bytes_body=True)
+
+ def test_check_token_existence_with_bytes_body(self):
+ self._test_check_token_existence(bytes_body=True)
+
+ def test_check_token_existence_with_str_body(self):
+ self._test_check_token_existence()
+
def test_delete_token(self):
self.check_service_client_function(
self.client.delete_token,
diff --git a/tempest/tests/lib/services/identity/v3/test_endpoint_groups_client.py b/tempest/tests/lib/services/identity/v3/test_endpoint_groups_client.py
new file mode 100644
index 0000000..8b034e6
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_endpoint_groups_client.py
@@ -0,0 +1,162 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.identity.v3 import endpoint_groups_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestEndPointGroupsClient(base.BaseServiceTest):
+ FAKE_CREATE_ENDPOINT_GROUP = {
+ "endpoint_group": {
+ "id": 1,
+ "name": "FAKE_ENDPOINT_GROUP",
+ "description": "FAKE SERVICE ENDPOINT GROUP",
+ "filters": {
+ "service_id": 1
+ }
+ }
+ }
+
+ FAKE_ENDPOINT_GROUP_INFO = {
+ "endpoint_group": {
+ "id": 1,
+ "name": "FAKE_ENDPOINT_GROUP",
+ "description": "FAKE SERVICE ENDPOINT GROUP",
+ "links": {
+ "self": "http://example.com/identity/v3/OS-EP-FILTER/" +
+ "endpoint_groups/1"
+ },
+ "filters": {
+ "service_id": 1
+ }
+ }
+ }
+
+ FAKE_LIST_ENDPOINT_GROUPS = {
+ "endpoint_groups": [
+ {
+ "id": 1,
+ "name": "SERVICE_GROUP1",
+ "description": "FAKE SERVICE ENDPOINT GROUP",
+ "links": {
+ "self": "http://example.com/identity/v3/OS-EP-FILTER/" +
+ "endpoint_groups/1"
+ },
+ "filters": {
+ "service_id": 1
+ }
+ },
+ {
+ "id": 2,
+ "name": "SERVICE_GROUP2",
+ "description": "FAKE SERVICE ENDPOINT GROUP",
+ "links": {
+ "self": "http://example.com/identity/v3/OS-EP-FILTER/" +
+ "endpoint_groups/2"
+ },
+ "filters": {
+ "service_id": 2
+ }
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestEndPointGroupsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = endpoint_groups_client.EndPointGroupsClient(
+ fake_auth, 'identity', 'regionOne')
+
+ def _test_create_endpoint_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_endpoint_group,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_ENDPOINT_GROUP,
+ bytes_body,
+ status=201,
+ name="FAKE_ENDPOINT_GROUP",
+ filters={'service_id': "1"})
+
+ def _test_show_endpoint_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_endpoint_group,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_ENDPOINT_GROUP_INFO,
+ bytes_body,
+ endpoint_group_id="1")
+
+ def _test_check_endpoint_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.check_endpoint_group,
+ 'tempest.lib.common.rest_client.RestClient.head',
+ {},
+ bytes_body,
+ status=200,
+ endpoint_group_id="1")
+
+ def _test_update_endpoint_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_endpoint_group,
+ 'tempest.lib.common.rest_client.RestClient.patch',
+ self.FAKE_ENDPOINT_GROUP_INFO,
+ bytes_body,
+ endpoint_group_id="1",
+ name="NewName")
+
+ def _test_list_endpoint_groups(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_endpoint_groups,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_ENDPOINT_GROUPS,
+ bytes_body)
+
+ def test_create_endpoint_group_with_str_body(self):
+ self._test_create_endpoint_group()
+
+ def test_create_endpoint_group_with_bytes_body(self):
+ self._test_create_endpoint_group(bytes_body=True)
+
+ def test_show_endpoint_group_with_str_body(self):
+ self._test_show_endpoint_group()
+
+ def test_show_endpoint_group_with_bytes_body(self):
+ self._test_show_endpoint_group(bytes_body=True)
+
+ def test_check_endpoint_group_with_str_body(self):
+ self._test_check_endpoint_group()
+
+ def test_check_endpoint_group_with_bytes_body(self):
+ self._test_check_endpoint_group(bytes_body=True)
+
+ def test_list_endpoint_groups_with_str_body(self):
+ self._test_list_endpoint_groups()
+
+ def test_list_endpoint_groups_with_bytes_body(self):
+ self._test_list_endpoint_groups(bytes_body=True)
+
+ def test_update_endpoint_group_with_str_body(self):
+ self._test_update_endpoint_group()
+
+ def test_update_endpoint_group_with_bytes_body(self):
+ self._test_update_endpoint_group(bytes_body=True)
+
+ def test_delete_endpoint_group(self):
+ self.check_service_client_function(
+ self.client.delete_endpoint_group,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ endpoint_group_id="1",
+ status=204)
diff --git a/tempest/tests/lib/services/identity/v3/test_services_client.py b/tempest/tests/lib/services/identity/v3/test_services_client.py
index f87fcce..b464644 100644
--- a/tempest/tests/lib/services/identity/v3/test_services_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_services_client.py
@@ -101,12 +101,15 @@
bytes_body,
service_id="686766")
- def _test_list_services(self, bytes_body=False):
+ def _test_list_services(self, bytes_body=False, mock_args='services',
+ **params):
self.check_service_client_function(
self.client.list_services,
'tempest.lib.common.rest_client.RestClient.get',
self.FAKE_LIST_SERVICES,
- bytes_body)
+ bytes_body,
+ mock_args=[mock_args],
+ **params)
def _test_update_service(self, bytes_body=False):
self.check_service_client_function(
@@ -134,6 +137,10 @@
def test_list_services_with_bytes_body(self):
self._test_list_services(bytes_body=True)
+ def test_list_services_with_params(self):
+ self._test_list_services(
+ type='fake-type', mock_args='services?type=fake-type')
+
def test_update_service_with_str_body(self):
self._test_update_service()
diff --git a/tempest/tests/lib/services/network/test_extensions_client.py b/tempest/tests/lib/services/network/test_extensions_client.py
new file mode 100644
index 0000000..27eb485
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_extensions_client.py
@@ -0,0 +1,201 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.network import extensions_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestExtensionsClient(base.BaseServiceTest):
+
+ FAKE_EXTENSIONS = {
+ "extensions": [
+ {
+ "updated": "2013-01-20T00:00:00-00:00",
+ "name": "Neutron Service Type Management",
+ "links": [],
+ "alias": "service-type",
+ "description": "API for retrieving service providers for"
+ " Neutron advanced services"
+ },
+ {
+ "updated": "2012-10-05T10:00:00-00:00",
+ "name": "security-group",
+ "links": [],
+ "alias": "security-group",
+ "description": "The security groups extension."
+ },
+ {
+ "updated": "2013-02-07T10:00:00-00:00",
+ "name": "L3 Agent Scheduler",
+ "links": [],
+ "alias": "l3_agent_scheduler",
+ "description": "Schedule routers among l3 agents"
+ },
+ {
+ "updated": "2013-02-07T10:00:00-00:00",
+ "name": "Loadbalancer Agent Scheduler",
+ "links": [],
+ "alias": "lbaas_agent_scheduler",
+ "description": "Schedule pools among lbaas agents"
+ },
+ {
+ "updated": "2013-03-28T10:00:00-00:00",
+ "name": "Neutron L3 Configurable external gateway mode",
+ "links": [],
+ "alias": "ext-gw-mode",
+ "description":
+ "Extension of the router abstraction for specifying whether"
+ " SNAT should occur on the external gateway"
+ },
+ {
+ "updated": "2014-02-03T10:00:00-00:00",
+ "name": "Port Binding",
+ "links": [],
+ "alias": "binding",
+ "description": "Expose port bindings of a virtual port to"
+ " external application"
+ },
+ {
+ "updated": "2012-09-07T10:00:00-00:00",
+ "name": "Provider Network",
+ "links": [],
+ "alias": "provider",
+ "description": "Expose mapping of virtual networks to"
+ " physical networks"
+ },
+ {
+ "updated": "2013-02-03T10:00:00-00:00",
+ "name": "agent",
+ "links": [],
+ "alias": "agent",
+ "description": "The agent management extension."
+ },
+ {
+ "updated": "2012-07-29T10:00:00-00:00",
+ "name": "Quota management support",
+ "links": [],
+ "alias": "quotas",
+ "description": "Expose functions for quotas management per"
+ " tenant"
+ },
+ {
+ "updated": "2013-02-07T10:00:00-00:00",
+ "name": "DHCP Agent Scheduler",
+ "links": [],
+ "alias": "dhcp_agent_scheduler",
+ "description": "Schedule networks among dhcp agents"
+ },
+ {
+ "updated": "2013-06-27T10:00:00-00:00",
+ "name": "Multi Provider Network",
+ "links": [],
+ "alias": "multi-provider",
+ "description": "Expose mapping of virtual networks to"
+ " multiple physical networks"
+ },
+ {
+ "updated": "2013-01-14T10:00:00-00:00",
+ "name": "Neutron external network",
+ "links": [],
+ "alias": "external-net",
+ "description": "Adds external network attribute to network"
+ " resource."
+ },
+ {
+ "updated": "2012-07-20T10:00:00-00:00",
+ "name": "Neutron L3 Router",
+ "links": [],
+ "alias": "router",
+ "description": "Router abstraction for basic L3 forwarding"
+ " between L2 Neutron networks and access to external"
+ " networks via a NAT gateway."
+ },
+ {
+ "updated": "2013-07-23T10:00:00-00:00",
+ "name": "Allowed Address Pairs",
+ "links": [],
+ "alias": "allowed-address-pairs",
+ "description": "Provides allowed address pairs"
+ },
+ {
+ "updated": "2013-03-17T12:00:00-00:00",
+ "name": "Neutron Extra DHCP opts",
+ "links": [],
+ "alias": "extra_dhcp_opt",
+ "description": "Extra options configuration for DHCP. For"
+ " example PXE boot options to DHCP clients can be specified"
+ " (e.g. tftp-server, server-ip-address, bootfile-name)"
+ },
+ {
+ "updated": "2012-10-07T10:00:00-00:00",
+ "name": "LoadBalancing service",
+ "links": [],
+ "alias": "lbaas",
+ "description": "Extension for LoadBalancing service"
+ },
+ {
+ "updated": "2013-02-01T10:00:00-00:00",
+ "name": "Neutron Extra Route",
+ "links": [],
+ "alias": "extraroute",
+ "description": "Extra routes configuration for L3 router"
+ },
+ {
+ "updated": "2016-01-24T10:00:00-00:00",
+ "name": "Neutron Port Data Plane Status",
+ "links": [],
+ "alias": "data-plane-status",
+ "description": "Status of the underlying data plane."
+ }
+ ]
+ }
+
+ FAKE_EXTENSION_ALIAS = "service-type"
+
+ def setUp(self):
+ super(TestExtensionsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.extensions_client = extensions_client.ExtensionsClient(
+ fake_auth, "network", "regionOne")
+
+ def _test_list_extensions(self, bytes_body=False):
+ self.check_service_client_function(
+ self.extensions_client.list_extensions,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_EXTENSIONS,
+ bytes_body,
+ 200)
+
+ def _test_show_extension(self, bytes_body=False):
+ self.check_service_client_function(
+ self.extensions_client.show_extension,
+ "tempest.lib.common.rest_client.RestClient.get",
+ {"extension": self.FAKE_EXTENSIONS["extensions"][0]},
+ bytes_body,
+ 200,
+ ext_alias=self.FAKE_EXTENSION_ALIAS)
+
+ def test_list_extensions_with_str_body(self):
+ self._test_list_extensions()
+
+ def test_list_extensions_with_bytes_body(self):
+ self._test_list_extensions(bytes_body=True)
+
+ def test_show_extension_with_str_body(self):
+ self._test_show_extension()
+
+ def test_show_extension_with_bytes_body(self):
+ self._test_show_extension(bytes_body=True)
diff --git a/tempest/tests/lib/services/network/test_floating_ips_client.py b/tempest/tests/lib/services/network/test_floating_ips_client.py
new file mode 100644
index 0000000..c5b1845
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_floating_ips_client.py
@@ -0,0 +1,145 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from tempest.lib.services.network import floating_ips_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestFloatingIPsClient(base.BaseServiceTest):
+
+ FAKE_FLOATING_IPS = {
+ "floatingips": [
+ {
+ "router_id": "d23abc8d-2991-4a55-ba98-2aaea84cc72f",
+ "description": "for test",
+ "created_at": "2016-12-21T10:55:50Z",
+ "updated_at": "2016-12-21T10:55:53Z",
+ "revision_number": 1,
+ "project_id": "4969c491a3c74ee4af974e6d800c62de",
+ "tenant_id": "4969c491a3c74ee4af974e6d800c62de",
+ "floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57",
+ "fixed_ip_address": "10.0.0.3",
+ "floating_ip_address": "172.24.4.228",
+ "port_id": "ce705c24-c1ef-408a-bda3-7bbd946164ab",
+ "id": "2f245a7b-796b-4f26-9cf9-9e82d248fda7",
+ "status": "ACTIVE"
+ },
+ {
+ "router_id": None,
+ "description": "for test",
+ "created_at": "2016-12-21T11:55:50Z",
+ "updated_at": "2016-12-21T11:55:53Z",
+ "revision_number": 2,
+ "project_id": "4969c491a3c74ee4af974e6d800c62de",
+ "tenant_id": "4969c491a3c74ee4af974e6d800c62de",
+ "floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57",
+ "fixed_ip_address": None,
+ "floating_ip_address": "172.24.4.227",
+ "port_id": None,
+ "id": "61cea855-49cb-4846-997d-801b70c71bdd",
+ "status": "DOWN"
+ }
+ ]
+ }
+
+ FAKE_FLOATING_IP_ID = "2f245a7b-796b-4f26-9cf9-9e82d248fda7"
+
+ def setUp(self):
+ super(TestFloatingIPsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.floating_ips_client = floating_ips_client.FloatingIPsClient(
+ fake_auth, "compute", "regionOne")
+
+ def _test_list_floatingips(self, bytes_body=False):
+ self.check_service_client_function(
+ self.floating_ips_client.list_floatingips,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_FLOATING_IPS,
+ bytes_body,
+ 200)
+
+ def _test_create_floatingip(self, bytes_body=False):
+ self.check_service_client_function(
+ self.floating_ips_client.create_floatingip,
+ "tempest.lib.common.rest_client.RestClient.post",
+ {"floatingip": self.FAKE_FLOATING_IPS["floatingips"][1]},
+ bytes_body,
+ 201,
+ floating_network_id="172.24.4.228")
+
+ def _test_show_floatingip(self, bytes_body=False):
+ self.check_service_client_function(
+ self.floating_ips_client.show_floatingip,
+ "tempest.lib.common.rest_client.RestClient.get",
+ {"floatingip": self.FAKE_FLOATING_IPS["floatingips"][0]},
+ bytes_body,
+ 200,
+ floatingip_id=self.FAKE_FLOATING_IP_ID)
+
+ def _test_update_floatingip(self, bytes_body=False):
+ update_kwargs = {
+ "port_id": "fc861431-0e6c-4842-a0ed-e2363f9bc3a8"
+ }
+
+ resp_body = {
+ "floatingip": copy.deepcopy(
+ self.FAKE_FLOATING_IPS["floatingips"][0]
+ )
+ }
+ resp_body["floatingip"].update(update_kwargs)
+
+ self.check_service_client_function(
+ self.floating_ips_client.update_floatingip,
+ "tempest.lib.common.rest_client.RestClient.put",
+ resp_body,
+ bytes_body,
+ 200,
+ floatingip_id=self.FAKE_FLOATING_IP_ID,
+ **update_kwargs)
+
+ def test_list_floatingips_with_str_body(self):
+ self._test_list_floatingips()
+
+ def test_list_floatingips_with_bytes_body(self):
+ self._test_list_floatingips(bytes_body=True)
+
+ def test_create_floatingip_with_str_body(self):
+ self._test_create_floatingip()
+
+ def test_create_floatingip_with_bytes_body(self):
+ self._test_create_floatingip(bytes_body=True)
+
+ def test_show_floatingips_with_str_body(self):
+ self._test_show_floatingip()
+
+ def test_show_floatingips_with_bytes_body(self):
+ self._test_show_floatingip(bytes_body=True)
+
+ def test_update_floatingip_with_str_body(self):
+ self._test_update_floatingip()
+
+ def test_update_floatingip_with_bytes_body(self):
+ self._test_update_floatingip(bytes_body=True)
+
+ def test_delete_floatingip(self):
+ self.check_service_client_function(
+ self.floating_ips_client.delete_floatingip,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ status=204,
+ floatingip_id=self.FAKE_FLOATING_IP_ID)
diff --git a/tempest/tests/lib/services/network/test_metering_label_rules_client.py b/tempest/tests/lib/services/network/test_metering_label_rules_client.py
new file mode 100644
index 0000000..047c34f
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_metering_label_rules_client.py
@@ -0,0 +1,110 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.network import metering_label_rules_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestMeteringLabelRulesClient(base.BaseServiceTest):
+
+ FAKE_METERING_LABEL_RULES = {
+ "metering_label_rules": [
+ {
+ "remote_ip_prefix": "20.0.0.0/24",
+ "direction": "ingress",
+ "metering_label_id": "e131d186-b02d-4c0b-83d5-0c0725c4f812",
+ "id": "9536641a-7d14-4dc5-afaf-93a973ce0eb8",
+ "excluded": False
+ },
+ {
+ "remote_ip_prefix": "10.0.0.0/24",
+ "direction": "ingress",
+ "metering_label_id": "e131d186-b02d-4c0b-83d5-0c0725c4f812",
+ "id": "ffc6fd15-40de-4e7d-b617-34d3f7a93aec",
+ "excluded": False
+ }
+ ]
+ }
+
+ FAKE_METERING_LABEL_RULE = {
+ "remote_ip_prefix": "20.0.0.0/24",
+ "direction": "ingress",
+ "metering_label_id": "e131d186-b02d-4c0b-83d5-0c0725c4f812"
+ }
+
+ FAKE_METERING_LABEL_ID = "e131d186-b02d-4c0b-83d5-0c0725c4f812"
+ FAKE_METERING_LABEL_RULE_ID = "9536641a-7d14-4dc5-afaf-93a973ce0eb8"
+
+ def setUp(self):
+ super(TestMeteringLabelRulesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.metering_label_rules_client = \
+ metering_label_rules_client.MeteringLabelRulesClient(
+ fake_auth, "network", "regionOne")
+
+ def _test_list_metering_label_rules(self, bytes_body=False):
+ self.check_service_client_function(
+ self.metering_label_rules_client.list_metering_label_rules,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_METERING_LABEL_RULES,
+ bytes_body,
+ 200)
+
+ def _test_create_metering_label_rule(self, bytes_body=False):
+ self.check_service_client_function(
+ self.metering_label_rules_client.create_metering_label_rule,
+ "tempest.lib.common.rest_client.RestClient.post",
+ {"metering_label_rule": self.FAKE_METERING_LABEL_RULES[
+ "metering_label_rules"][0]},
+ bytes_body,
+ 201,
+ **self.FAKE_METERING_LABEL_RULE)
+
+ def _test_show_metering_label_rule(self, bytes_body=False):
+ self.check_service_client_function(
+ self.metering_label_rules_client.show_metering_label_rule,
+ "tempest.lib.common.rest_client.RestClient.get",
+ {"metering_label_rule": self.FAKE_METERING_LABEL_RULES[
+ "metering_label_rules"][0]},
+ bytes_body,
+ 200,
+ metering_label_rule_id=self.FAKE_METERING_LABEL_RULE_ID)
+
+ def test_delete_metering_label_rule(self):
+ self.check_service_client_function(
+ self.metering_label_rules_client.delete_metering_label_rule,
+ "tempest.lib.common.rest_client.RestClient.delete",
+ {},
+ status=204,
+ metering_label_rule_id=self.FAKE_METERING_LABEL_RULE_ID)
+
+ def test_list_metering_label_rules_with_str_body(self):
+ self._test_list_metering_label_rules()
+
+ def test_list_metering_label_rules_with_bytes_body(self):
+ self._test_list_metering_label_rules(bytes_body=True)
+
+ def test_create_metering_label_rule_with_str_body(self):
+ self._test_create_metering_label_rule()
+
+ def test_create_metering_label_rule_with_bytes_body(self):
+ self._test_create_metering_label_rule(bytes_body=True)
+
+ def test_show_metering_label_rule_with_str_body(self):
+ self._test_show_metering_label_rule()
+
+ def test_show_metering_label_rule_with_bytes_body(self):
+ self._test_show_metering_label_rule(bytes_body=True)
diff --git a/tempest/tests/lib/services/network/test_metering_labels_client.py b/tempest/tests/lib/services/network/test_metering_labels_client.py
new file mode 100644
index 0000000..a048326
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_metering_labels_client.py
@@ -0,0 +1,107 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.network import metering_labels_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestMeteringLabelsClient(base.BaseServiceTest):
+
+ FAKE_METERING_LABELS = {
+ "metering_labels": [
+ {
+ "project_id": "45345b0ee1ea477fac0f541b2cb79cd4",
+ "tenant_id": "45345b0ee1ea477fac0f541b2cb79cd4",
+ "description": "label1 description",
+ "name": "label1",
+ "id": "a6700594-5b7a-4105-8bfe-723b346ce866",
+ "shared": False
+ },
+ {
+ "project_id": "45345b0ee1ea477fac0f541b2cb79cd4",
+ "tenant_id": "45345b0ee1ea477fac0f541b2cb79cd4",
+ "description": "label2 description",
+ "name": "label2",
+ "id": "e131d186-b02d-4c0b-83d5-0c0725c4f812",
+ "shared": False
+ }
+ ]
+ }
+
+ FAKE_METERING_LABEL_ID = "a6700594-5b7a-4105-8bfe-723b346ce866"
+
+ def setUp(self):
+ super(TestMeteringLabelsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.metering_labels_client = \
+ metering_labels_client.MeteringLabelsClient(
+ fake_auth, "network", "regionOne")
+
+ def _test_list_metering_labels(self, bytes_body=False):
+ self.check_service_client_function(
+ self.metering_labels_client.list_metering_labels,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_METERING_LABELS,
+ bytes_body,
+ 200)
+
+ def _test_create_metering_label(self, bytes_body=False):
+ self.check_service_client_function(
+ self.metering_labels_client.create_metering_label,
+ "tempest.lib.common.rest_client.RestClient.post",
+ {"metering_label": self.FAKE_METERING_LABELS[
+ "metering_labels"][1]},
+ bytes_body,
+ 201,
+ name="label1",
+ description="label1 description",
+ shared=False)
+
+ def _test_show_metering_label(self, bytes_body=False):
+ self.check_service_client_function(
+ self.metering_labels_client.show_metering_label,
+ "tempest.lib.common.rest_client.RestClient.get",
+ {"metering_label": self.FAKE_METERING_LABELS[
+ "metering_labels"][0]},
+ bytes_body,
+ 200,
+ metering_label_id=self.FAKE_METERING_LABEL_ID)
+
+ def test_delete_metering_label(self):
+ self.check_service_client_function(
+ self.metering_labels_client.delete_metering_label,
+ "tempest.lib.common.rest_client.RestClient.delete",
+ {},
+ status=204,
+ metering_label_id=self.FAKE_METERING_LABEL_ID)
+
+ def test_list_metering_labels_with_str_body(self):
+ self._test_list_metering_labels()
+
+ def test_list_metering_labels_with_bytes_body(self):
+ self._test_list_metering_labels(bytes_body=True)
+
+ def test_create_metering_label_with_str_body(self):
+ self._test_create_metering_label()
+
+ def test_create_metering_label_with_bytes_body(self):
+ self._test_create_metering_label(bytes_body=True)
+
+ def test_show_metering_label_with_str_body(self):
+ self._test_show_metering_label()
+
+ def test_show_metering_label_with_bytes_body(self):
+ self._test_show_metering_label(bytes_body=True)
diff --git a/tempest/tests/lib/services/network/test_ports_client.py b/tempest/tests/lib/services/network/test_ports_client.py
new file mode 100644
index 0000000..20ef3f1
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_ports_client.py
@@ -0,0 +1,198 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from tempest.lib.services.network import ports_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestPortsClient(base.BaseServiceTest):
+
+ FAKE_PORTS = {
+ "ports": [
+ {
+ "admin_state_up": True,
+ "allowed_address_pairs": [],
+ "data_plane_status": None,
+ "description": "",
+ "device_id": "9ae135f4-b6e0-4dad-9e91-3c223e385824",
+ "device_owner": "network:router_gateway",
+ "extra_dhcp_opts": [],
+ "fixed_ips": [
+ {
+ "ip_address": "172.24.4.2",
+ "subnet_id": "008ba151-0b8c-4a67-98b5-0d2b87666062"
+ }
+ ],
+ "id": "d80b1a3b-4fc1-49f3-952e-1e2ab7081d8b",
+ "mac_address": "fa:16:3e:58:42:ed",
+ "name": "",
+ "network_id": "70c1db1f-b701-45bd-96e0-a313ee3430b3",
+ "project_id": "",
+ "security_groups": [],
+ "status": "ACTIVE",
+ "tenant_id": ""
+ },
+ {
+ "admin_state_up": True,
+ "allowed_address_pairs": [],
+ "data_plane_status": None,
+ "description": "",
+ "device_id": "9ae135f4-b6e0-4dad-9e91-3c223e385824",
+ "device_owner": "network:router_interface",
+ "extra_dhcp_opts": [],
+ "fixed_ips": [
+ {
+ "ip_address": "10.0.0.1",
+ "subnet_id": "288bf4a1-51ba-43b6-9d0a-520e9005db17"
+ }
+ ],
+ "id": "f71a6703-d6de-4be1-a91a-a570ede1d159",
+ "mac_address": "fa:16:3e:bb:3c:e4",
+ "name": "",
+ "network_id": "f27aa545-cbdd-4907-b0c6-c9e8b039dcc2",
+ "project_id": "d397de8a63f341818f198abb0966f6f3",
+ "security_groups": [],
+ "status": "ACTIVE",
+ "tenant_id": "d397de8a63f341818f198abb0966f6f3"
+ }
+ ]
+ }
+
+ FAKE_PORT_ID = "d80b1a3b-4fc1-49f3-952e-1e2ab7081d8b"
+
+ FAKE_PORT1 = {
+ "admin_state_up": True,
+ "name": "",
+ "network_id": "70c1db1f-b701-45bd-96e0-a313ee3430b3"
+ }
+
+ FAKE_PORT2 = {
+ "admin_state_up": True,
+ "name": "",
+ "network_id": "f27aa545-cbdd-4907-b0c6-c9e8b039dcc2"
+ }
+
+ FAKE_PORTS_REQ = {
+ "ports": [
+ FAKE_PORT1,
+ FAKE_PORT2
+ ]
+ }
+
+ def setUp(self):
+ super(TestPortsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.ports_client = ports_client.PortsClient(
+ fake_auth, "network", "regionOne")
+
+ def _test_list_ports(self, bytes_body=False):
+ self.check_service_client_function(
+ self.ports_client.list_ports,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_PORTS,
+ bytes_body,
+ 200)
+
+ def _test_create_port(self, bytes_body=False):
+ self.check_service_client_function(
+ self.ports_client.create_port,
+ "tempest.lib.common.rest_client.RestClient.post",
+ {"port": self.FAKE_PORTS["ports"][0]},
+ bytes_body,
+ 201,
+ **self.FAKE_PORT1)
+
+ def _test_create_bulk_ports(self, bytes_body=False):
+ self.check_service_client_function(
+ self.ports_client.create_bulk_ports,
+ "tempest.lib.common.rest_client.RestClient.post",
+ self.FAKE_PORTS,
+ bytes_body,
+ 201,
+ ports=self.FAKE_PORTS_REQ)
+
+ def _test_show_port(self, bytes_body=False):
+ self.check_service_client_function(
+ self.ports_client.show_port,
+ "tempest.lib.common.rest_client.RestClient.get",
+ {"port": self.FAKE_PORTS["ports"][0]},
+ bytes_body,
+ 200,
+ port_id=self.FAKE_PORT_ID)
+
+ def _test_update_port(self, bytes_body=False):
+ update_kwargs = {
+ "admin_state_up": True,
+ "device_id": "d90a13da-be41-461f-9f99-1dbcf438fdf2",
+ "device_owner": "compute:nova",
+ "name": "test-for-port-update"
+ }
+
+ resp_body = {
+ "port": copy.deepcopy(
+ self.FAKE_PORTS["ports"][0]
+ )
+ }
+ resp_body["port"].update(update_kwargs)
+
+ self.check_service_client_function(
+ self.ports_client.update_port,
+ "tempest.lib.common.rest_client.RestClient.put",
+ resp_body,
+ bytes_body,
+ 200,
+ port_id=self.FAKE_PORT_ID,
+ **update_kwargs)
+
+ def test_delete_port(self):
+ self.check_service_client_function(
+ self.ports_client.delete_port,
+ "tempest.lib.common.rest_client.RestClient.delete",
+ {},
+ status=204,
+ port_id=self.FAKE_PORT_ID)
+
+ def test_list_ports_with_str_body(self):
+ self._test_list_ports()
+
+ def test_list_ports_with_bytes_body(self):
+ self._test_list_ports(bytes_body=True)
+
+ def test_create_port_with_str_body(self):
+ self._test_create_port()
+
+ def test_create_port_with_bytes_body(self):
+ self._test_create_port(bytes_body=True)
+
+ def test_create_bulk_port_with_str_body(self):
+ self._test_create_bulk_ports()
+
+ def test_create_bulk_port_with_bytes_body(self):
+ self._test_create_bulk_ports(bytes_body=True)
+
+ def test_show_port_with_str_body(self):
+ self._test_show_port()
+
+ def test_show_port_with_bytes_body(self):
+ self._test_show_port(bytes_body=True)
+
+ def test_update_port_with_str_body(self):
+ self._test_update_port()
+
+ def test_update_port_with_bytes_body(self):
+ self._test_update_port(bytes_body=True)
diff --git a/tempest/tests/lib/services/network/test_quotas_client.py b/tempest/tests/lib/services/network/test_quotas_client.py
new file mode 100644
index 0000000..e76bc9c
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_quotas_client.py
@@ -0,0 +1,99 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.network import quotas_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestQuotasClient(base.BaseServiceTest):
+
+ FAKE_QUOTAS = {
+ "quotas": [
+ {
+ "floatingip": 50,
+ "network": 15,
+ "port": 50,
+ "project_id": "bab7d5c60cd041a0a36f7c4b6e1dd978",
+ "rbac_policy": -1,
+ "router": 10,
+ "security_group": 10,
+ "security_group_rule": 100,
+ "subnet": 10,
+ "subnetpool": -1,
+ "tenant_id": "bab7d5c60cd041a0a36f7c4b6e1dd978"
+ }
+ ]
+ }
+
+ FAKE_QUOTA_TENANT_ID = "bab7d5c60cd041a0a36f7c4b6e1dd978"
+
+ def setUp(self):
+ super(TestQuotasClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.quotas_client = quotas_client.QuotasClient(
+ fake_auth, "network", "regionOne")
+
+ def _test_list_quotas(self, bytes_body=False):
+ self.check_service_client_function(
+ self.quotas_client.list_quotas,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_QUOTAS,
+ bytes_body,
+ 200)
+
+ def _test_show_quotas(self, bytes_body=False):
+ self.check_service_client_function(
+ self.quotas_client.show_quotas,
+ "tempest.lib.common.rest_client.RestClient.get",
+ {"quota": self.FAKE_QUOTAS["quotas"][0]},
+ bytes_body,
+ 200,
+ tenant_id=self.FAKE_QUOTA_TENANT_ID)
+
+ def _test_update_quotas(self, bytes_body=False):
+ self.check_service_client_function(
+ self.quotas_client.update_quotas,
+ "tempest.lib.common.rest_client.RestClient.put",
+ {"quota": self.FAKE_QUOTAS["quotas"][0]},
+ bytes_body,
+ 200,
+ tenant_id=self.FAKE_QUOTA_TENANT_ID)
+
+ def test_reset_quotas(self):
+ self.check_service_client_function(
+ self.quotas_client.reset_quotas,
+ "tempest.lib.common.rest_client.RestClient.delete",
+ {},
+ status=204,
+ tenant_id=self.FAKE_QUOTA_TENANT_ID)
+
+ def test_list_quotas_with_str_body(self):
+ self._test_list_quotas()
+
+ def test_list_quotas_with_bytes_body(self):
+ self._test_list_quotas(bytes_body=True)
+
+ def test_show_quotas_with_str_body(self):
+ self._test_show_quotas()
+
+ def test_show_quotas_with_bytes_body(self):
+ self._test_show_quotas(bytes_body=True)
+
+ def test_update_quotas_with_str_body(self):
+ self._test_update_quotas()
+
+ def test_update_quotas_with_bytes_body(self):
+ self._test_update_quotas(bytes_body=True)
diff --git a/tempest/tests/lib/services/network/test_security_group_rules_client.py b/tempest/tests/lib/services/network/test_security_group_rules_client.py
new file mode 100644
index 0000000..ebffcbe
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_security_group_rules_client.py
@@ -0,0 +1,130 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.services.network import security_group_rules_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestSecurityGroupsClient(base.BaseServiceTest):
+
+ FAKE_SEC_GROUP_RULE_ID = "3c0e45ff-adaf-4124-b083-bf390e5482ff"
+
+ FAKE_SECURITY_GROUP_RULES = {
+ "security_group_rules": [
+ {
+ "direction": "egress",
+ "ethertype": "IPv6",
+ "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff",
+ "port_range_max": None,
+ "port_range_min": None,
+ "protocol": None,
+ "remote_group_id": None,
+ "remote_ip_prefix": None,
+ "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5",
+ "project_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "description": ""
+ },
+ {
+ "direction": "egress",
+ "ethertype": "IPv4",
+ "id": "93aa42e5-80db-4581-9391-3a608bd0e448",
+ "port_range_max": None,
+ "port_range_min": None,
+ "protocol": None,
+ "remote_group_id": None,
+ "remote_ip_prefix": None,
+ "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5",
+ "project_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "description": ""
+ }
+ ]
+ }
+
+ FAKE_SECURITY_GROUP_RULE = copy.copy(
+ FAKE_SECURITY_GROUP_RULES['security_group_rules'][0])
+
+ def setUp(self):
+ super(TestSecurityGroupsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = security_group_rules_client.SecurityGroupRulesClient(
+ fake_auth, 'network', 'regionOne')
+
+ def _test_list_security_group_rules(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_security_group_rules,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SECURITY_GROUP_RULES,
+ bytes_body,
+ mock_args='v2.0/security-group-rules')
+
+ def _test_create_security_group_rule(self, bytes_body=False):
+ kwargs = {'direction': 'egress',
+ 'security_group_id': '85cc3048-abc3-43cc-89b3-377341426ac5',
+ 'remote_ip_prefix': None}
+
+ self.check_service_client_function(
+ self.client.create_security_group_rule,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_SECURITY_GROUP_RULE,
+ bytes_body,
+ status=201,
+ mock_args=['v2.0/security-group-rules',
+ json.dumps({"security_group_rule": kwargs})],
+ **kwargs)
+
+ def _test_show_security_group_rule(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_security_group_rule,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SECURITY_GROUP_RULE,
+ bytes_body,
+ security_group_rule_id=self.FAKE_SEC_GROUP_RULE_ID,
+ mock_args='v2.0/security-group-rules/%s'
+ % self.FAKE_SEC_GROUP_RULE_ID)
+
+ def test_list_security_group_rules_with_str_body(self):
+ self._test_list_security_group_rules()
+
+ def test_list_security_group_rules_with_bytes_body(self):
+ self._test_list_security_group_rules(bytes_body=True)
+
+ def test_create_security_group_rule_with_str_body(self):
+ self._test_create_security_group_rule()
+
+ def test_create_security_group_rule_with_bytes_body(self):
+ self._test_create_security_group_rule(bytes_body=True)
+
+ def test_show_security_group_rule_with_str_body(self):
+ self._test_show_security_group_rule()
+
+ def test_show_security_group_rule_with_bytes_body(self):
+ self._test_show_security_group_rule(bytes_body=True)
+
+ def test_delete_security_group_rule(self):
+ self.check_service_client_function(
+ self.client.delete_security_group_rule,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ status=204,
+ security_group_rule_id=self.FAKE_SEC_GROUP_RULE_ID,
+ mock_args='v2.0/security-group-rules/%s'
+ % self.FAKE_SEC_GROUP_RULE_ID)
diff --git a/tempest/tests/lib/services/network/test_security_groups_client.py b/tempest/tests/lib/services/network/test_security_groups_client.py
new file mode 100644
index 0000000..d066378
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_security_groups_client.py
@@ -0,0 +1,157 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.services.network import security_groups_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestSecurityGroupsClient(base.BaseServiceTest):
+
+ FAKE_SEC_GROUP_ID = "85cc3048-abc3-43cc-89b3-377341426ac5"
+
+ FAKE_SECURITY_GROUPS = {
+ "security_groups": [
+ {
+ "description": "default",
+ "id": FAKE_SEC_GROUP_ID,
+ "name": "fake-security-group-name",
+ "security_group_rules": [
+ {
+ "direction": "egress",
+ "ethertype": "IPv4",
+ "id": "38ce2d8e-e8f1-48bd-83c2-d33cb9f50c3d",
+ "port_range_max": None,
+ "port_range_min": None,
+ "protocol": None,
+ "remote_group_id": None,
+ "remote_ip_prefix": None,
+ "security_group_id": FAKE_SEC_GROUP_ID,
+ "project_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "description": ""
+ },
+ {
+ "direction": "egress",
+ "ethertype": "IPv6",
+ "id": "565b9502-12de-4ffd-91e9-68885cff6ae1",
+ "port_range_max": None,
+ "port_range_min": None,
+ "protocol": None,
+ "remote_group_id": None,
+ "remote_ip_prefix": None,
+ "security_group_id": FAKE_SEC_GROUP_ID,
+ "project_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "description": ""
+ }
+ ],
+ "project_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550"
+ }
+ ]
+ }
+
+ FAKE_SECURITY_GROUP = {
+ "security_group": copy.deepcopy(
+ FAKE_SECURITY_GROUPS["security_groups"][0])
+ }
+
+ def setUp(self):
+ super(TestSecurityGroupsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = security_groups_client.SecurityGroupsClient(
+ fake_auth, 'network', 'regionOne')
+
+ def _test_list_security_groups(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_security_groups,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SECURITY_GROUPS,
+ bytes_body,
+ mock_args='v2.0/security-groups')
+
+ def _test_create_security_group(self, bytes_body=False):
+ kwargs = {'name': 'fake-security-group-name'}
+ self.check_service_client_function(
+ self.client.create_security_group,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_SECURITY_GROUP,
+ bytes_body,
+ status=201,
+ mock_args=['v2.0/security-groups',
+ json.dumps({"security_group": kwargs})],
+ **kwargs)
+
+ def _test_show_security_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_security_group,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SECURITY_GROUP,
+ bytes_body,
+ security_group_id=self.FAKE_SEC_GROUP_ID,
+ mock_args='v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID)
+
+ def _test_update_security_group(self, bytes_body=False):
+ kwargs = {'name': 'updated-security-group-name'}
+ resp_body = copy.deepcopy(self.FAKE_SECURITY_GROUP)
+ resp_body["security_group"]["name"] = 'updated-security-group-name'
+
+ self.check_service_client_function(
+ self.client.update_security_group,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ resp_body,
+ bytes_body,
+ security_group_id=self.FAKE_SEC_GROUP_ID,
+ mock_args=['v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID,
+ json.dumps({'security_group': kwargs})],
+ **kwargs)
+
+ def test_list_security_groups_with_str_body(self):
+ self._test_list_security_groups()
+
+ def test_list_security_groups_with_bytes_body(self):
+ self._test_list_security_groups(bytes_body=True)
+
+ def test_create_security_group_with_str_body(self):
+ self._test_create_security_group()
+
+ def test_create_security_group_with_bytes_body(self):
+ self._test_create_security_group(bytes_body=True)
+
+ def test_show_security_group_with_str_body(self):
+ self._test_show_security_group()
+
+ def test_show_security_group_with_bytes_body(self):
+ self._test_show_security_group(bytes_body=True)
+
+ def test_update_security_group_with_str_body(self):
+ self._test_update_security_group()
+
+ def test_update_security_group_with_bytes_body(self):
+ self._test_update_security_group(bytes_body=True)
+
+ def test_delete_security_group(self):
+ self.check_service_client_function(
+ self.client.delete_security_group,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ status=204,
+ security_group_id=self.FAKE_SEC_GROUP_ID,
+ mock_args='v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID)
diff --git a/tempest/tests/lib/services/network/test_subnetpools_client.py b/tempest/tests/lib/services/network/test_subnetpools_client.py
new file mode 100644
index 0000000..3abb438
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_subnetpools_client.py
@@ -0,0 +1,163 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from tempest.lib.services.network import subnetpools_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestSubnetsClient(base.BaseServiceTest):
+
+ FAKE_SUBNETPOOLS = {
+ "subnetpools": [
+ {
+ "min_prefixlen": "64",
+ "address_scope_id": None,
+ "default_prefixlen": "64",
+ "id": "03f761e6-eee0-43fc-a921-8acf64c14988",
+ "max_prefixlen": "64",
+ "name": "my-subnet-pool-ipv6",
+ "default_quota": None,
+ "is_default": False,
+ "project_id": "9fadcee8aa7c40cdb2114fff7d569c08",
+ "tenant_id": "9fadcee8aa7c40cdb2114fff7d569c08",
+ "prefixes": [
+ "2001:db8:0:2::/64",
+ "2001:db8::/63"
+ ],
+ "ip_version": 6,
+ "shared": False,
+ "description": "",
+ "revision_number": 2
+ },
+ {
+ "min_prefixlen": "24",
+ "address_scope_id": None,
+ "default_prefixlen": "25",
+ "id": "f49a1319-423a-4ee6-ba54-1d95a4f6cc68",
+ "max_prefixlen": "30",
+ "name": "my-subnet-pool-ipv4",
+ "default_quota": None,
+ "is_default": False,
+ "project_id": "9fadcee8aa7c40cdb2114fff7d569c08",
+ "tenant_id": "9fadcee8aa7c40cdb2114fff7d569c08",
+ "prefixes": [
+ "10.10.0.0/21",
+ "192.168.0.0/16"
+ ],
+ "ip_version": 4,
+ "shared": False,
+ "description": "",
+ "revision_number": 2
+ }
+ ]
+ }
+
+ FAKE_SUBNETPOOL_ID = "03f761e6-eee0-43fc-a921-8acf64c14988"
+
+ def setUp(self):
+ super(TestSubnetsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.subnetpools_client = subnetpools_client.SubnetpoolsClient(
+ fake_auth, 'compute', 'regionOne')
+
+ def _test_list_subnetpools(self, bytes_body=False):
+ self.check_service_client_function(
+ self.subnetpools_client.list_subnetpools,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SUBNETPOOLS,
+ bytes_body,
+ 200)
+
+ def _test_create_subnetpool(self, bytes_body=False):
+ self.check_service_client_function(
+ self.subnetpools_client.create_subnetpool,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ {'subnetpool': self.FAKE_SUBNETPOOLS['subnetpools'][1]},
+ bytes_body,
+ 201,
+ name="my-subnet-pool-ipv4",
+ prefixes=["192.168.0.0/16", "10.10.0.0/21"])
+
+ def _test_show_subnetpool(self, bytes_body=False):
+ self.check_service_client_function(
+ self.subnetpools_client.show_subnetpool,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ {'subnetpool': self.FAKE_SUBNETPOOLS['subnetpools'][0]},
+ bytes_body,
+ 200,
+ subnetpool_id=self.FAKE_SUBNETPOOL_ID)
+
+ def _test_update_subnetpool(self, bytes_body=False):
+ update_kwargs = {
+ "name": "my-new-subnetpool-name",
+ "prefixes": [
+ "2001:db8::/64",
+ "2001:db8:0:1::/64",
+ "2001:db8:0:2::/64"
+ ],
+ "min_prefixlen": 64,
+ "default_prefixlen": 64,
+ "max_prefixlen": 64
+ }
+
+ resp_body = {
+ 'subnetpool': copy.deepcopy(
+ self.FAKE_SUBNETPOOLS['subnetpools'][0])
+ }
+ resp_body['subnetpool'].update(update_kwargs)
+
+ self.check_service_client_function(
+ self.subnetpools_client.update_subnetpool,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ resp_body,
+ bytes_body,
+ 200,
+ subnetpool_id=self.FAKE_SUBNETPOOL_ID,
+ **update_kwargs)
+
+ def test_list_subnetpools_with_str_body(self):
+ self._test_list_subnetpools()
+
+ def test_list_subnetpools_with_bytes_body(self):
+ self._test_list_subnetpools(bytes_body=True)
+
+ def test_create_subnetpool_with_str_body(self):
+ self._test_create_subnetpool()
+
+ def test_create_subnetpool_with_bytes_body(self):
+ self._test_create_subnetpool(bytes_body=True)
+
+ def test_show_subnetpool_with_str_body(self):
+ self._test_show_subnetpool()
+
+ def test_show_subnetpool_with_bytes_body(self):
+ self._test_show_subnetpool(bytes_body=True)
+
+ def test_update_subnet_with_str_body(self):
+ self._test_update_subnetpool()
+
+ def test_update_subnet_with_bytes_body(self):
+ self._test_update_subnetpool(bytes_body=True)
+
+ def test_delete_subnetpool(self):
+ self.check_service_client_function(
+ self.subnetpools_client.delete_subnetpool,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ status=204,
+ subnetpool_id=self.FAKE_SUBNETPOOL_ID)
diff --git a/tempest/tests/lib/services/network/test_subnets_client.py b/tempest/tests/lib/services/network/test_subnets_client.py
new file mode 100644
index 0000000..0aadf54
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_subnets_client.py
@@ -0,0 +1,250 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from tempest.lib.services.network import subnets_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestSubnetsClient(base.BaseServiceTest):
+
+ FAKE_SUBNET = {
+ "subnet": {
+ "name": "",
+ "enable_dhcp": True,
+ "network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ "segment_id": None,
+ "project_id": "4fd44f30292945e481c7b8a0c8908869",
+ "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
+ "dns_nameservers": [],
+ "allocation_pools": [
+ {
+ "start": "192.168.199.2",
+ "end": "192.168.199.254"
+ }
+ ],
+ "host_routes": [],
+ "ip_version": 4,
+ "gateway_ip": "192.168.199.1",
+ "cidr": "192.168.199.0/24",
+ "id": "3b80198d-4f7b-4f77-9ef5-774d54e17126",
+ "created_at": "2016-10-10T14:35:47Z",
+ "description": "",
+ "ipv6_address_mode": None,
+ "ipv6_ra_mode": None,
+ "revision_number": 2,
+ "service_types": [],
+ "subnetpool_id": None,
+ "updated_at": "2016-10-10T14:35:47Z"
+ }
+ }
+
+ FAKE_UPDATED_SUBNET = {
+ "subnet": {
+ "name": "my_subnet",
+ "enable_dhcp": True,
+ "network_id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
+ "segment_id": None,
+ "project_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+ "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+ "dns_nameservers": [],
+ "allocation_pools": [
+ {
+ "start": "10.0.0.2",
+ "end": "10.0.0.254"
+ }
+ ],
+ "host_routes": [],
+ "ip_version": 4,
+ "gateway_ip": "10.0.0.1",
+ "cidr": "10.0.0.0/24",
+ "id": "08eae331-0402-425a-923c-34f7cfe39c1b",
+ "description": ""
+ }
+ }
+
+ FAKE_SUBNETS = {
+ "subnets": [
+ {
+ "name": "private-subnet",
+ "enable_dhcp": True,
+ "network_id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324",
+ "segment_id": None,
+ "project_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+ "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e",
+ "dns_nameservers": [],
+ "allocation_pools": [
+ {
+ "start": "10.0.0.2",
+ "end": "10.0.0.254"
+ }
+ ],
+ "host_routes": [],
+ "ip_version": 4,
+ "gateway_ip": "10.0.0.1",
+ "cidr": "10.0.0.0/24",
+ "id": "08eae331-0402-425a-923c-34f7cfe39c1b",
+ "created_at": "2016-10-10T14:35:34Z",
+ "description": "",
+ "ipv6_address_mode": None,
+ "ipv6_ra_mode": None,
+ "revision_number": 2,
+ "service_types": [],
+ "subnetpool_id": None,
+ "updated_at": "2016-10-10T14:35:34Z"
+ },
+ {
+ "name": "my_subnet",
+ "enable_dhcp": True,
+ "network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22",
+ "segment_id": None,
+ "project_id": "4fd44f30292945e481c7b8a0c8908869",
+ "tenant_id": "4fd44f30292945e481c7b8a0c8908869",
+ "dns_nameservers": [],
+ "allocation_pools": [
+ {
+ "start": "192.0.0.2",
+ "end": "192.255.255.254"
+ }
+ ],
+ "host_routes": [],
+ "ip_version": 4,
+ "gateway_ip": "192.0.0.1",
+ "cidr": "192.0.0.0/8",
+ "id": "54d6f61d-db07-451c-9ab3-b9609b6b6f0b",
+ "created_at": "2016-10-10T14:35:47Z",
+ "description": "",
+ "ipv6_address_mode": None,
+ "ipv6_ra_mode": None,
+ "revision_number": 2,
+ "service_types": [],
+ "subnetpool_id": None,
+ "updated_at": "2016-10-10T14:35:47Z"
+ }
+ ]
+ }
+
+ FAKE_BULK_SUBNETS = copy.deepcopy(FAKE_SUBNETS)
+
+ FAKE_SUBNET_ID = "54d6f61d-db07-451c-9ab3-b9609b6b6f0b"
+
+ FAKE_NETWORK_ID = "d32019d3-bc6e-4319-9c1d-6722fc136a22"
+
+ def setUp(self):
+ super(TestSubnetsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.subnets_client = subnets_client.SubnetsClient(
+ fake_auth, 'compute', 'regionOne')
+
+ def _test_create_subnet(self, bytes_body=False):
+ self.check_service_client_function(
+ self.subnets_client.create_subnet,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_SUBNET,
+ bytes_body,
+ 201,
+ network_id=self.FAKE_NETWORK_ID,
+ ip_version=4,
+ cidr="192.168.199.0/24")
+
+ def _test_update_subnet(self, bytes_body=False):
+ self.check_service_client_function(
+ self.subnets_client.update_subnet,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_UPDATED_SUBNET,
+ bytes_body,
+ 200,
+ subnet_id=self.FAKE_SUBNET_ID,
+ name="fake_updated_subnet_name")
+
+ def _test_show_subnet(self, bytes_body=False):
+ self.check_service_client_function(
+ self.subnets_client.show_subnet,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SUBNET,
+ bytes_body,
+ 200,
+ subnet_id=self.FAKE_SUBNET_ID)
+
+ def _test_list_subnets(self, bytes_body=False):
+ self.check_service_client_function(
+ self.subnets_client.list_subnets,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SUBNETS,
+ bytes_body,
+ 200)
+
+ def _test_create_bulk_subnets(self, bytes_body=False):
+ kwargs = {
+ "subnets": [
+ {
+ "cidr": "192.168.199.0/24",
+ "ip_version": 4,
+ "network_id": "e6031bc2-901a-4c66-82da-f4c32ed89406"
+ },
+ {
+ "cidr": "10.56.4.0/22",
+ "ip_version": 4,
+ "network_id": "64239a54-dcc4-4b39-920b-b37c2144effa"
+ }
+ ]
+ }
+ self.check_service_client_function(
+ self.subnets_client.create_bulk_subnets,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_SUBNETS,
+ bytes_body,
+ 201,
+ **kwargs)
+
+ def test_create_subnet_with_str_body(self):
+ self._test_create_subnet()
+
+ def test_create_subnet_with_bytes_body(self):
+ self._test_create_subnet(bytes_body=True)
+
+ def test_update_subnet_with_str_body(self):
+ self._test_update_subnet()
+
+ def test_update_subnet_with_bytes_body(self):
+ self._test_update_subnet(bytes_body=True)
+
+ def test_show_subnet_with_str_body(self):
+ self._test_show_subnet()
+
+ def test_show_subnet_with_bytes_body(self):
+ self._test_show_subnet(bytes_body=True)
+
+ def test_list_subnets_with_str_body(self):
+ self._test_list_subnets()
+
+ def test_list_subnets_with_bytes_body(self):
+ self._test_list_subnets(bytes_body=True)
+
+ def test_delete_subnet(self):
+ self.check_service_client_function(
+ self.subnets_client.delete_subnet,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ status=204,
+ subnet_id=self.FAKE_SUBNET_ID)
+
+ def test_create_bulk_subnets_with_str_body(self):
+ self._test_create_bulk_subnets()
+
+ def test_create_bulk_subnets_with_bytes_body(self):
+ self._test_create_bulk_subnets(bytes_body=True)
diff --git a/tempest/tests/lib/services/network/test_tags_client.py b/tempest/tests/lib/services/network/test_tags_client.py
new file mode 100644
index 0000000..dbe50a0
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_tags_client.py
@@ -0,0 +1,123 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+from tempest.lib.services.network import tags_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestTagsClient(base.BaseServiceTest):
+
+ FAKE_TAGS = {
+ "tags": [
+ "red",
+ "blue"
+ ]
+ }
+
+ FAKE_RESOURCE_TYPE = 'network'
+
+ FAKE_RESOURCE_ID = '7a8f904b-c1ed-4446-a87d-60440c02934b'
+
+ def setUp(self):
+ super(TestTagsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = tags_client.TagsClient(
+ fake_auth, 'network', 'regionOne')
+
+ def _test_update_all_tags(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_all_tags,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_TAGS,
+ bytes_body,
+ resource_type=self.FAKE_RESOURCE_TYPE,
+ resource_id=self.FAKE_RESOURCE_ID,
+ tags=self.FAKE_TAGS)
+
+ def _test_check_tag_existence(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.check_tag_existence,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ {},
+ bytes_body,
+ resource_type=self.FAKE_RESOURCE_TYPE,
+ resource_id=self.FAKE_RESOURCE_ID,
+ tag=self.FAKE_TAGS['tags'][0],
+ status=204)
+
+ def _test_create_tag(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_tag,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ {},
+ bytes_body,
+ resource_type=self.FAKE_RESOURCE_TYPE,
+ resource_id=self.FAKE_RESOURCE_ID,
+ tag=self.FAKE_TAGS['tags'][0],
+ status=201)
+
+ def _test_list_tags(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_tags,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_TAGS,
+ bytes_body,
+ resource_type=self.FAKE_RESOURCE_TYPE,
+ resource_id=self.FAKE_RESOURCE_ID)
+
+ def test_update_all_tags_with_str_body(self):
+ self._test_update_all_tags()
+
+ def test_update_all_tags_with_bytes_body(self):
+ self._test_update_all_tags(bytes_body=True)
+
+ def test_delete_all_tags(self):
+ self.check_service_client_function(
+ self.client.delete_all_tags,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ resource_type=self.FAKE_RESOURCE_TYPE,
+ resource_id=self.FAKE_RESOURCE_ID,
+ status=204)
+
+ def test_check_tag_existence_with_str_body(self):
+ self._test_check_tag_existence()
+
+ def test_check_tag_existence_with_bytes_body(self):
+ self._test_check_tag_existence(bytes_body=True)
+
+ def test_create_tag_with_str_body(self):
+ self._test_create_tag()
+
+ def test_create_tag_with_bytes_body(self):
+ self._test_create_tag(bytes_body=True)
+
+ def test_list_tags_with_str_body(self):
+ self._test_list_tags()
+
+ def test_list_tags_with_bytes_body(self):
+ self._test_list_tags(bytes_body=True)
+
+ def test_delete_tag(self):
+ self.check_service_client_function(
+ self.client.delete_tag,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ resource_type=self.FAKE_RESOURCE_TYPE,
+ resource_id=self.FAKE_RESOURCE_ID,
+ tag=self.FAKE_TAGS['tags'][0],
+ status=204)
diff --git a/tempest/tests/lib/services/volume/v2/test_capabilities_client.py b/tempest/tests/lib/services/volume/v2/test_capabilities_client.py
new file mode 100644
index 0000000..3d3f1e1
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v2/test_capabilities_client.py
@@ -0,0 +1,77 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.volume.v2 import capabilities_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestCapabilitiesClient(base.BaseServiceTest):
+
+ FAKE_BACKEND_CAPABILITIES = {
+ "namespace": "OS::Storage::Capabilities::fake",
+ "vendor_name": "OpenStack",
+ "volume_backend_name": "lvmdriver-1",
+ "pool_name": "pool",
+ "driver_version": "2.0.0",
+ "storage_protocol": "iSCSI",
+ "display_name": "Capabilities of Cinder LVM driver",
+ "description": (
+ "These are volume type options provided by Cinder LVM driver."),
+ "visibility": "public",
+ "replication_targets": [],
+ "properties": {
+ "compression": {
+ "title": "Compression",
+ "description": "Enables compression.",
+ "type": "boolean"
+ },
+ "qos": {
+ "title": "QoS",
+ "description": "Enables QoS.",
+ "type": "boolean"
+ },
+ "replication": {
+ "title": "Replication",
+ "description": "Enables replication.",
+ "type": "boolean"
+ },
+ "thin_provisioning": {
+ "title": "Thin Provisioning",
+ "description": "Sets thin provisioning.",
+ "type": "boolean"
+ }
+ }
+ }
+
+ def setUp(self):
+ super(TestCapabilitiesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = capabilities_client.CapabilitiesClient(
+ fake_auth, 'volume', 'regionOne')
+
+ def _test_show_backend_capabilities(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_backend_capabilities,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_BACKEND_CAPABILITIES,
+ bytes_body,
+ host='lvmdriver-1')
+
+ def test_show_backend_capabilities_with_str_body(self):
+ self._test_show_backend_capabilities()
+
+ def test_show_backend_capabilities_with_bytes_body(self):
+ self._test_show_backend_capabilities(bytes_body=True)
diff --git a/tempest/tests/lib/services/volume/v2/test_hosts_client.py b/tempest/tests/lib/services/volume/v2/test_hosts_client.py
new file mode 100644
index 0000000..e107910
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v2/test_hosts_client.py
@@ -0,0 +1,97 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.volume.v2 import hosts_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestQuotasClient(base.BaseServiceTest):
+ FAKE_LIST_HOSTS = {
+ "hosts": [
+ {
+ "service-status": "available",
+ "service": "cinder-scheduler",
+ "zone": "nova",
+ "service-state": "enabled",
+ "host_name": "fake-host",
+ "last-update": "2017-04-12T04:26:03.000000"
+ },
+ {
+ "service-status": "available",
+ "service": "cinder-volume",
+ "zone": "nova",
+ "service-state": "enabled",
+ "host_name": "fake-host@rbd",
+ "last-update": "2017-04-12T04:26:07.000000"
+ }
+ ]
+ }
+
+ FAKE_HOST_INFO = {
+ "host": [
+ {
+ "resource": {
+ "volume_count": "2",
+ "total_volume_gb": "2",
+ "total_snapshot_gb": "0",
+ "project": "(total)",
+ "host": "fake-host",
+ "snapshot_count": "0"
+ }
+ },
+ {
+ "resource": {
+ "volume_count": "2",
+ "total_volume_gb": "2",
+ "total_snapshot_gb": "0",
+ "project": "f21a9c86d7114bf99c711f4874d80474",
+ "host": "fake-host",
+ "snapshot_count": "0"
+ }
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestQuotasClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = hosts_client.HostsClient(fake_auth,
+ 'volume',
+ 'regionOne')
+
+ def _test_list_hosts(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_hosts,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_HOSTS, bytes_body)
+
+ def _test_show_host(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_host,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_HOST_INFO, bytes_body, host_name='fake-host')
+
+ def test_list_hosts_with_str_body(self):
+ self._test_list_hosts()
+
+ def test_list_hosts_with_bytes_body(self):
+ self._test_list_hosts(bytes_body=True)
+
+ def test_show_host_with_str_body(self):
+ self._test_show_host()
+
+ def test_show_host_with_bytes_body(self):
+ self._test_show_host(bytes_body=True)
diff --git a/tempest/tests/lib/services/volume/v3/test_volumes_client.py b/tempest/tests/lib/services/volume/v3/test_volumes_client.py
new file mode 100644
index 0000000..a515fd3
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v3/test_volumes_client.py
@@ -0,0 +1,48 @@
+# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.volume.v3 import volumes_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestVolumesClient(base.BaseServiceTest):
+
+ FAKE_VOLUME_SUMMARY = {
+ "volume-summary": {
+ "total_size": 20,
+ "total_count": 5
+ }
+ }
+
+ def setUp(self):
+ super(TestVolumesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = volumes_client.VolumesClient(fake_auth,
+ 'volume',
+ 'regionOne')
+
+ def _test_show_volume_summary(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_volume_summary,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_VOLUME_SUMMARY,
+ bytes_body)
+
+ def test_show_volume_summary_with_str_body(self):
+ self._test_show_volume_summary()
+
+ def test_show_volume_summary_with_bytes_body(self):
+ self._test_show_volume_summary(bytes_body=True)
diff --git a/tempest/tests/lib/test_auth.py b/tempest/tests/lib/test_auth.py
index ac13a13..c3a792f 100644
--- a/tempest/tests/lib/test_auth.py
+++ b/tempest/tests/lib/test_auth.py
@@ -16,7 +16,7 @@
import copy
import datetime
-from oslotest import mockpatch
+import fixtures
import testtools
from tempest.lib import auth
@@ -82,9 +82,9 @@
def test_auth_data_property_when_cache_exists(self):
self.auth_provider.cache = 'foo'
- self.useFixture(mockpatch.PatchObject(self.auth_provider,
- 'is_expired',
- return_value=False))
+ self.useFixture(fixtures.MockPatchObject(self.auth_provider,
+ 'is_expired',
+ return_value=False))
self.assertEqual('foo', getattr(self.auth_provider, 'auth_data'))
def test_delete_auth_data_property_through_deleter(self):
diff --git a/tempest/tests/test_decorators.py b/tempest/tests/test_decorators.py
index 8b6472b..2fc84dc 100644
--- a/tempest/tests/test_decorators.py
+++ b/tempest/tests/test_decorators.py
@@ -12,8 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import fixtures
from oslo_config import cfg
-from oslotest import mockpatch
import testtools
from tempest import config
@@ -95,8 +95,8 @@
'bad_service')
def test_services_decorator_with_service_valid_and_unavailable(self):
- self.useFixture(mockpatch.PatchObject(test.CONF.service_available,
- 'cinder', False))
+ self.useFixture(fixtures.MockPatchObject(test.CONF.service_available,
+ 'cinder', False))
self.assertRaises(testtools.TestCase.skipException,
self._test_services_helper, 'compute',
'volume')
diff --git a/test-requirements.txt b/test-requirements.txt
index 13950bd..19b45ea 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -3,10 +3,11 @@
# process, which may cause wedges in the gate later.
hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
# needed for doc build
-sphinx>=1.5.1 # BSD
+sphinx!=1.6.1,>=1.5.1 # BSD
oslosphinx>=4.7.0 # Apache-2.0
-reno>=1.8.0 # Apache-2.0
+reno!=2.3.1,>=1.8.0 # Apache-2.0
mock>=2.0 # BSD
-coverage>=4.0 # Apache-2.0
+coverage!=4.4,>=4.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
flake8-import-order==0.11 # LGPLv3
+openstackdocstheme>=1.5.0 # Apache-2.0
diff --git a/tools/check_logs.py b/tools/check_logs.py
index f82b387..fc21f75 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -25,7 +25,6 @@
import six.moves.urllib.request as urlreq
import yaml
-
# DEVSTACK_GATE_GRENADE is either unset if grenade is not running
# or a string describing what type of grenade run to perform.
is_grenade = os.environ.get('DEVSTACK_GATE_GRENADE') is not None
@@ -137,7 +136,7 @@
with open(WHITELIST_FILE) as stream:
loaded = yaml.safe_load(stream)
if loaded:
- for (name, l) in loaded.iteritems():
+ for (name, l) in six.iteritems(loaded):
for w in l:
assert 'module' in w, 'no module in %s' % name
assert 'message' in w, 'no message in %s' % name
diff --git a/tools/find_stack_traces.py b/tools/find_stack_traces.py
index 2ba8b16..1f2b88b 100755
--- a/tools/find_stack_traces.py
+++ b/tools/find_stack_traces.py
@@ -126,8 +126,8 @@
def print_stats(items, fname, verbose=False):
- errors = len(filter(lambda x: x.level == "ERROR", items))
- traces = len(filter(lambda x: x.level == "TRACE", items))
+ errors = len([x for x in items if x.level == "ERROR"])
+ traces = len([x for x in items if x.level == "TRACE"])
print("%d ERRORS found in %s" % (errors, fname))
print("%d TRACES found in %s" % (traces, fname))
diff --git a/tools/generate-tempest-plugins-list.py b/tools/generate-tempest-plugins-list.py
index acb29af..a33962b 100644
--- a/tools/generate-tempest-plugins-list.py
+++ b/tools/generate-tempest-plugins-list.py
@@ -26,7 +26,12 @@
import json
import re
-import requests
+try:
+ # For Python 3.0 and later
+ import urllib
+except ImportError:
+ # Fall back to Python 2's urllib2
+ import urllib2 as urllib
url = 'https://review.openstack.org/projects/'
@@ -49,23 +54,31 @@
def has_tempest_plugin(proj):
- if proj.startswith('openstack/deb-'):
- return False
- r = requests.get(
- "https://git.openstack.org/cgit/%s/plain/setup.cfg" % proj)
+ try:
+ r = urllib.urlopen("https://git.openstack.org/cgit/%s/plain/setup.cfg"
+ % proj)
+ except urllib.HTTPError as err:
+ if err.code == 404:
+ return False
p = re.compile('^tempest\.test_plugins', re.M)
- if p.findall(r.text):
+ if p.findall(r.read()):
return True
else:
False
-r = requests.get(url)
+r = urllib.urlopen(url)
# Gerrit prepends 4 garbage octets to the JSON, in order to counter
# cross-site scripting attacks. Therefore we must discard it so the
# json library won't choke.
-projects = sorted(filter(is_in_openstack_namespace, json.loads(r.text[4:])))
+projects = sorted(filter(is_in_openstack_namespace, json.loads(r.read()[4:])))
-found_plugins = filter(has_tempest_plugin, projects)
+# Retrieve projects having no deb, ui or spec namespace as those namespaces
+# do not contains tempest plugins.
+projects_list = [i for i in projects if not (i.startswith('openstack/deb-') or
+ i.endswith('-ui') or
+ i.endswith('-specs'))]
+
+found_plugins = list(filter(has_tempest_plugin, projects_list))
# Every element of the found_plugins list begins with "openstack/".
# We drop those initial 10 octets when printing the list.