Merge "Replace assertEqual([], items) with assertEmpty(items)"
diff --git a/doc/source/conf.py b/doc/source/conf.py
index cbfcc09..f11d96a 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".
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 1264ecc..c4affd2 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
=========
----------------------------
Tempest Configuration Guide
---------------------------
@@ -40,7 +36,6 @@
configuration
sampleconf
----------------------
Command Documentation
---------------------
@@ -53,11 +48,9 @@
workspace
run
-==============
For developers
==============
------------
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/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/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/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/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/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/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 11517cc..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']
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/volume/base.py b/tempest/api/volume/base.py
index cc1e087..3f33c7b 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(
@@ -266,6 +269,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_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index 5fd1904..5a192ac 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -63,6 +63,12 @@
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_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_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index be3f1f2..99918eb 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -35,10 +35,9 @@
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')
self.attach_volume(server['id'], self.volume_origin['id'])
@@ -47,19 +46,6 @@
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)
diff --git a/tempest/clients.py b/tempest/clients.py
index 73a4b20..4baa31d 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -269,6 +269,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()
diff --git a/tempest/config.py b/tempest/config.py
index a5225e6..a2e0877 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."),
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/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/test-requirements.txt b/test-requirements.txt
index 13950bd..fbdad44 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
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