Merge "Remove python shebangs from python modules"
diff --git a/releasenotes/notes/add-show-api-v3-details-api-to-v3-versions-client-4b408427379cabfe.yaml b/releasenotes/notes/add-show-api-v3-details-api-to-v3-versions-client-4b408427379cabfe.yaml
new file mode 100644
index 0000000..50f10fa
--- /dev/null
+++ b/releasenotes/notes/add-show-api-v3-details-api-to-v3-versions-client-4b408427379cabfe.yaml
@@ -0,0 +1,7 @@
+---
+features:
+ - |
+ Add show api version details function to v3
+ versions_client library for cinder.
+
+ * show_version
\ No newline at end of file
diff --git a/tempest/api/identity/v3/test_tokens.py b/tempest/api/identity/v3/test_tokens.py
index f13aa10..fa1c47f 100644
--- a/tempest/api/identity/v3/test_tokens.py
+++ b/tempest/api/identity/v3/test_tokens.py
@@ -43,7 +43,15 @@
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)
+ # NOTE: resource name that are case-sensitive in keystone
+ # depends on backends such as MySQL or LDAP which are
+ # case-insensitive, case-preserving. Resource name is
+ # returned as it is stored in the backend, not as it is
+ # requested. Verifying the username with both lower-case to
+ # avoid failure on different backends
+ self.assertEqual(
+ authenticated_token['user']['name'].lower(), username.lower())
+
self.non_admin_client.delete_token(subject_token)
self.assertRaises(
lib_exc.NotFound, self.non_admin_client.show_token, subject_token)
@@ -84,10 +92,17 @@
self.assertIsNotNone(subject_id, 'Expected user ID in token.')
subject_name = resp['user']['name']
+
if username:
- self.assertEqual(subject_name, username)
+ # NOTE: resource name that are case-sensitive in keystone
+ # depends on backends such as MySQL or LDAP which are
+ # case-insensitive, case-preserving. Resource name is
+ # returned as it is stored in the backend, not as it is
+ # requested. Verifying the username with both lower-case to
+ # avoid failure on different backends
+ self.assertEqual(subject_name.lower(), username.lower())
else:
- # Expect a user name, but don't know what it will be.
+ # Expect a user name, but don't know what it will be
self.assertIsNotNone(subject_name, 'Expected user name in token.')
self.assertEqual(resp['methods'][0], 'password')
@@ -110,7 +125,15 @@
subject_token)['token']
self.assertEqual(resp['x-subject-token'], subject_token)
self.assertEqual(token_details['user']['id'], user.user_id)
- self.assertEqual(token_details['user']['name'], user.username)
+ # NOTE: resource name that are case-sensitive in keystone
+ # depends on backends such as MySQL or LDAP which are
+ # case-insensitive, case-preserving. Resource name is
+ # returned as it is stored in the backend, not as it is
+ # requested. Verifying the username with both lower-case to
+ # avoid failure on different backends
+ self.assertEqual(
+ token_details['user']['name'].lower(),
+ user.username.lower())
# Perform Delete Token
self.non_admin_client.delete_token(subject_token)
self.assertRaises(lib_exc.NotFound,
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index 0acb11a..645a952 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -70,6 +70,15 @@
deleted unless the ``--delete-tempest-conf-objects`` flag is used to
force their deletion.
+.. note::
+
+ If during execution of ``tempest cleanup`` NotImplemented exception
+ occurres, ``tempest cleanup`` won't fail on that, it will be logged only.
+ NotImplemented errors are ignored because they are an outcome of some
+ extensions being disabled and ``tempest cleanup`` is not checking their
+ availability as it tries to clean up as much as possible without any
+ complicated logic.
+
"""
import sys
import traceback
@@ -83,6 +92,7 @@
from tempest.common import credentials_factory as credentials
from tempest.common import identity
from tempest import config
+from tempest.lib import exceptions
SAVED_STATE_JSON = "saved_state.json"
DRY_RUN_JSON = "dry_run.json"
@@ -103,7 +113,13 @@
LOG.exception("Failure during cleanup")
traceback.print_exc()
raise
- if self.GOT_EXCEPTIONS:
+ # ignore NotImplemented errors as those are an outcome of some
+ # extensions being disabled and cleanup is not checking their
+ # availability as it tries to clean up as much as possible without
+ # any complicated logic
+ critical_exceptions = [ex for ex in self.GOT_EXCEPTIONS if
+ not isinstance(ex, exceptions.NotImplemented)]
+ if critical_exceptions:
raise Exception(self.GOT_EXCEPTIONS)
def init(self, parsed_args):
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index bc57a9c..8b625d0 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -142,7 +142,7 @@
msg = ("Got NotImplemented error in %s, full exception: %s" %
(str(self.__class__), str(exc)))
LOG.exception(msg)
- self.got_exceptions.append(msg)
+ self.got_exceptions.append(exc)
class SnapshotService(BaseService):
diff --git a/tempest/lib/api_schema/response/volume/versions.py b/tempest/lib/api_schema/response/volume/versions.py
index 2391a8c..c845f7f 100644
--- a/tempest/lib/api_schema/response/volume/versions.py
+++ b/tempest/lib/api_schema/response/volume/versions.py
@@ -58,3 +58,49 @@
'required': ['versions'],
}
}
+
+volume_api_version_details = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'versions': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'status': {'type': 'string'},
+ 'updated': {'type': 'string'},
+ 'id': {'type': 'string'},
+ 'links': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'href': {'type': 'string',
+ 'format': 'uri'},
+ 'rel': {'type': 'string'},
+ 'type': {'type': 'string'},
+ },
+ 'required': ['href', 'rel']
+ }
+ },
+ 'min_version': {'type': 'string'},
+ 'version': {'type': 'string'},
+ 'media-types': {
+ 'type': 'array',
+ 'properties': {
+ 'base': {'type': 'string'},
+ 'type': {'type': 'string'}
+ },
+ 'required': ['base', 'type']
+ }
+ },
+ 'required': ['status', 'updated', 'id', 'links',
+ 'min_version', 'version', 'media-types']
+ }
+ }
+ },
+ 'required': ['versions'],
+ }
+}
diff --git a/tempest/lib/services/network/quotas_client.py b/tempest/lib/services/network/quotas_client.py
index c479799..997d201 100644
--- a/tempest/lib/services/network/quotas_client.py
+++ b/tempest/lib/services/network/quotas_client.py
@@ -35,10 +35,22 @@
return self.delete_resource(uri)
def show_quotas(self, tenant_id, **fields):
+ """Show quota for a project.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://docs.openstack.org/api-ref/network/v2/index.html#list-quotas-for-a-project
+ """
uri = '/quotas/%s' % tenant_id
return self.show_resource(uri, **fields)
def list_quotas(self, **filters):
+ """List quotas for projects with non default quota values.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://docs.openstack.org/api-ref/network/v2/index.html#list-quotas-for-projects-with-non-default-quota-values
+ """
uri = '/quotas'
return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/volume/v3/versions_client.py b/tempest/lib/services/volume/v3/versions_client.py
index 29c3fb0..fc8e92f 100644
--- a/tempest/lib/services/volume/v3/versions_client.py
+++ b/tempest/lib/services/volume/v3/versions_client.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import os
import time
from oslo_serialization import jsonutils as json
@@ -45,3 +46,17 @@
body = json.loads(body)
self.validate_response(schema.list_versions, resp, body)
return rest_client.ResponseBody(resp, body)
+
+ def show_version(self, version):
+ """Show API version details
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://docs.openstack.org/api-ref/block-storage/v3/#show-api-v3-details
+ """
+
+ version_url = os.path.join(self._get_base_version_url(), version)
+ resp, body = self.get(version_url)
+ body = json.loads(body)
+ self.validate_response(schema.volume_api_version_details, resp, body)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/tests/lib/services/volume/v3/test_groups_client.py b/tempest/tests/lib/services/volume/v3/test_groups_client.py
index 918e958..5a5ae88 100644
--- a/tempest/tests/lib/services/volume/v3/test_groups_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_groups_client.py
@@ -20,27 +20,22 @@
class TestGroupsClient(base.BaseServiceTest):
FAKE_CREATE_GROUP = {
"group": {
- "name": "group-001",
- "description": "Test group 1",
- "group_type": "0e58433f-d108-4bf3-a22c-34e6b71ef86b",
- "volume_types": ["2103099d-7cc3-4e52-a2f1-23a5284416f3"],
- "availability_zone": "az1",
+ "id": "6f519a48-3183-46cf-a32f-41815f816666",
+ "name": "first_group"
}
}
FAKE_CREATE_GROUP_FROM_GROUP_SNAPSHOT = {
- "create-from-src": {
- "name": "group-002",
- "description": "Test group 2",
- "group_snapshot_id": "79c9afdb-7e46-4d71-9249-1f022886963c",
+ "group": {
+ "id": "6f519a48-3183-46cf-a32f-41815f816668",
+ "name": "first_group"
}
}
FAKE_CREATE_GROUP_FROM_GROUP = {
- "create-from-src": {
- "name": "group-003",
- "description": "Test group 3",
- "source_group_id": "e92f9dc7-0b20-492d-8ab2-3ad8fdac270e",
+ "group": {
+ "id": "6f519a48-3183-46cf-a32f-41815f816667",
+ "name": "other_group"
}
}
diff --git a/tempest/tests/lib/services/volume/v3/test_versions_client.py b/tempest/tests/lib/services/volume/v3/test_versions_client.py
index 9627b9a..b9abd45 100644
--- a/tempest/tests/lib/services/volume/v3/test_versions_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_versions_client.py
@@ -69,6 +69,27 @@
]
}
+ FAKE_VERSION_DETAILS = {
+ "versions": [
+ {
+ "id": "v3.0",
+ "links": [
+ {"href": "https://docs.openstack.org/",
+ "type": "text/html", "rel": "describedby"},
+ {"href": "http://127.0.0.1:44895/v3/", "rel": "self"}
+ ],
+ "media-types": [
+ {"base": "application/json",
+ "type": "application/vnd.openstack.volume+json;version=3"}
+ ],
+ "min_version": "3.0",
+ "status": "CURRENT",
+ "updated": "2018-07-17T00:00:00Z",
+ "version": "3.59"
+ }
+ ]
+ }
+
def setUp(self):
super(TestVersionsClient, self).setUp()
fake_auth = fake_auth_provider.FakeAuthProvider()
@@ -89,3 +110,17 @@
def test_list_versions_with_bytes_body(self):
self._test_list_versions(bytes_body=True)
+
+ def _test_show_version(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_version,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_VERSION_DETAILS,
+ bytes_body,
+ 200, version='v3')
+
+ def test_show_version_details_with_str_body(self):
+ self._test_show_version()
+
+ def test_show_version_details_with_bytes_body(self):
+ self._test_show_version(bytes_body=True)