Refactor share metadata tests
1) Use the shares_v2_client to make metadata API requests.
This allows us to test v1 proxies as well where appropriate,
and actually test the supported version of the API instead
of the deprecated version
2) Verify key in GET /v2/shares/<share>/metadata/{key} API
the client's _parse_body helper strips out the top
level key allowing us to miss bugs associated with
any key changes from the server [1]. Allow for opt-in
verification of the key and add this verification
to the affected API.
[1] https://bugs.launchpad.net/manila/+bug/1968069
Depends-On: Ib5a62599b84ba55617071f8bcd8e2a1a11b2537b
Change-Id: I7b1af957f08328c642a74ff123deb78e193bbe3a
Related-Bug: #1968069
Signed-off-by: Goutham Pacha Ravi <gouthampravi@gmail.com>
diff --git a/manila_tempest_tests/services/share/json/shares_client.py b/manila_tempest_tests/services/share/json/shares_client.py
index 3413387..1e3aa6e 100644
--- a/manila_tempest_tests/services/share/json/shares_client.py
+++ b/manila_tempest_tests/services/share/json/shares_client.py
@@ -23,6 +23,7 @@
from tempest.lib import exceptions
from manila_tempest_tests import share_exceptions
+from manila_tempest_tests import utils
CONF = config.CONF
@@ -42,6 +43,9 @@
self.share_network_id = CONF.share.share_network_id
self.share_size = CONF.share.share_size
+ def _parse_resp(self, body, verify_top_key=None):
+ return utils._parse_resp(body, verify_top_key=verify_top_key)
+
def create_share(self, share_protocol=None, size=None,
name=None, snapshot_id=None, description=None,
metadata=None, share_network_id=None,
@@ -446,7 +450,7 @@
def get_metadata_item(self, share_id, key):
resp, body = self.get("shares/%s/metadata/%s" % (share_id, key))
self.expected_success(200, resp.status)
- return self._parse_resp(body)
+ return self._parse_resp(body, verify_top_key='meta')
###############
diff --git a/manila_tempest_tests/tests/api/test_metadata.py b/manila_tempest_tests/tests/api/test_metadata.py
index c8529a3..d2ae326 100644
--- a/manila_tempest_tests/tests/api/test_metadata.py
+++ b/manila_tempest_tests/tests/api/test_metadata.py
@@ -34,14 +34,15 @@
def _verify_share_metadata(self, share, md):
# get metadata of share
- metadata = self.shares_client.get_metadata(share["id"])['metadata']
+ metadata = self.shares_v2_client.get_metadata(share["id"])['metadata']
# verify metadata
self.assertEqual(md, metadata)
# verify metadata items
for key in md:
- get_value = self.shares_client.get_metadata_item(share["id"], key)
+ get_value = self.shares_v2_client.get_metadata_item(share["id"],
+ key)
self.assertEqual(md[key], get_value[key])
@decorators.idempotent_id('9070249f-6e94-4a38-a036-08debee547c3')
@@ -69,17 +70,18 @@
cleanup_in_class=False)
# set metadata
- self.shares_client.set_metadata(share["id"], md)
+ self.shares_v2_client.set_metadata(share["id"], md)
# verify metadata
self._verify_share_metadata(share, md)
# delete metadata
for key in md.keys():
- self.shares_client.delete_metadata(share["id"], key)
+ self.shares_v2_client.delete_metadata(share["id"], key)
# verify deletion of metadata
- get_metadata = self.shares_client.get_metadata(share["id"])['metadata']
+ get_metadata = self.shares_v2_client.get_metadata(share["id"])[
+ 'metadata']
self.assertEmpty(get_metadata)
@decorators.idempotent_id('4e5f8159-62b6-4d5c-f729-d8b1f029d7de')
@@ -93,13 +95,13 @@
cleanup_in_class=False)
# set metadata
- self.shares_client.set_metadata(share["id"], md1)
+ self.shares_v2_client.set_metadata(share["id"], md1)
# verify metadata
self._verify_share_metadata(share, md1)
# set metadata again
- self.shares_client.set_metadata(share["id"], md2)
+ self.shares_v2_client.set_metadata(share["id"], md2)
# verify metadata
md1.update(md2)
@@ -110,10 +112,11 @@
# delete metadata
for key in md.keys():
- self.shares_client.delete_metadata(share["id"], key)
+ self.shares_v2_client.delete_metadata(share["id"], key)
# verify deletion of metadata
- get_metadata = self.shares_client.get_metadata(share["id"])['metadata']
+ get_metadata = self.shares_v2_client.get_metadata(
+ share["id"])['metadata']
self.assertEmpty(get_metadata)
@decorators.idempotent_id('2ec70ba5-050b-3b17-c862-c149e53543c0')
@@ -127,13 +130,13 @@
cleanup_in_class=False)
# set metadata
- self.shares_client.set_metadata(share["id"], md1)
+ self.shares_v2_client.set_metadata(share["id"], md1)
# verify metadata
self._verify_share_metadata(share, md1)
# set metadata again
- self.shares_client.set_metadata(share["id"], md2)
+ self.shares_v2_client.set_metadata(share["id"], md2)
# verify metadata
md = {u"key9": u"value13", u"key10": u"value10",
@@ -142,10 +145,11 @@
# delete metadata
for key in md.keys():
- self.shares_client.delete_metadata(share["id"], key)
+ self.shares_v2_client.delete_metadata(share["id"], key)
# verify deletion of metadata
- get_metadata = self.shares_client.get_metadata(share["id"])['metadata']
+ get_metadata = self.shares_v2_client.get_metadata(
+ share["id"])['metadata']
self.assertEmpty(get_metadata)
@decorators.idempotent_id('c94851f4-2559-4712-9297-9912db1da7ff')
@@ -160,10 +164,10 @@
cleanup_in_class=False)
# set metadata
- self.shares_client.set_metadata(share["id"], md1)
+ self.shares_v2_client.set_metadata(share["id"], md1)
# update metadata
- self.shares_client.update_all_metadata(share["id"], md2)
+ self.shares_v2_client.update_all_metadata(share["id"], md2)
# verify metadata
self._verify_share_metadata(share, md2)
@@ -173,9 +177,9 @@
def test_set_metadata_min_size_key(self):
data = {"k": "value"}
- self.shares_client.set_metadata(self.share["id"], data)
+ self.shares_v2_client.set_metadata(self.share["id"], data)
- body_get = self.shares_client.get_metadata(
+ body_get = self.shares_v2_client.get_metadata(
self.share["id"])['metadata']
self.assertEqual(data['k'], body_get.get('k'))
@@ -185,9 +189,9 @@
max_key = "k" * 255
data = {max_key: "value"}
- self.shares_client.set_metadata(self.share["id"], data)
+ self.shares_v2_client.set_metadata(self.share["id"], data)
- body_get = self.shares_client.get_metadata(
+ body_get = self.shares_v2_client.get_metadata(
self.share["id"])['metadata']
self.assertIn(max_key, body_get)
self.assertEqual(data[max_key], body_get.get(max_key))
@@ -197,9 +201,9 @@
def test_set_metadata_min_size_value(self):
data = {"key": "v"}
- self.shares_client.set_metadata(self.share["id"], data)
+ self.shares_v2_client.set_metadata(self.share["id"], data)
- body_get = self.shares_client.get_metadata(
+ body_get = self.shares_v2_client.get_metadata(
self.share["id"])['metadata']
self.assertEqual(data['key'], body_get['key'])
@@ -209,9 +213,9 @@
max_value = "v" * 1023
data = {"key": max_value}
- self.shares_client.set_metadata(self.share["id"], data)
+ self.shares_v2_client.set_metadata(self.share["id"], data)
- body_get = self.shares_client.get_metadata(
+ body_get = self.shares_v2_client.get_metadata(
self.share["id"])['metadata']
self.assertEqual(data['key'], body_get['key'])
@@ -220,9 +224,9 @@
def test_upd_metadata_min_size_key(self):
data = {"k": "value"}
- self.shares_client.update_all_metadata(self.share["id"], data)
+ self.shares_v2_client.update_all_metadata(self.share["id"], data)
- body_get = self.shares_client.get_metadata(
+ body_get = self.shares_v2_client.get_metadata(
self.share["id"])['metadata']
self.assertEqual(data, body_get)
@@ -232,9 +236,9 @@
max_key = "k" * 255
data = {max_key: "value"}
- self.shares_client.update_all_metadata(self.share["id"], data)
+ self.shares_v2_client.update_all_metadata(self.share["id"], data)
- body_get = self.shares_client.get_metadata(
+ body_get = self.shares_v2_client.get_metadata(
self.share["id"])['metadata']
self.assertEqual(data, body_get)
@@ -243,9 +247,9 @@
def test_upd_metadata_min_size_value(self):
data = {"key": "v"}
- self.shares_client.update_all_metadata(self.share["id"], data)
+ self.shares_v2_client.update_all_metadata(self.share["id"], data)
- body_get = self.shares_client.get_metadata(
+ body_get = self.shares_v2_client.get_metadata(
self.share["id"])['metadata']
self.assertEqual(data, body_get)
@@ -255,8 +259,8 @@
max_value = "v" * 1023
data = {"key": max_value}
- self.shares_client.update_all_metadata(self.share["id"], data)
+ self.shares_v2_client.update_all_metadata(self.share["id"], data)
- body_get = self.shares_client.get_metadata(
+ body_get = self.shares_v2_client.get_metadata(
self.share["id"])['metadata']
self.assertEqual(data, body_get)
diff --git a/manila_tempest_tests/tests/api/test_metadata_negative.py b/manila_tempest_tests/tests/api/test_metadata_negative.py
index 93a3628..caa34ac 100644
--- a/manila_tempest_tests/tests/api/test_metadata_negative.py
+++ b/manila_tempest_tests/tests/api/test_metadata_negative.py
@@ -61,14 +61,14 @@
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_try_set_metadata_with_empty_key(self):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.set_metadata,
+ self.shares_v2_client.set_metadata,
self.share["id"], {"": "value"})
@decorators.idempotent_id('759ca34d-1c87-43f3-8da2-8e1d373049ac')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_try_upd_metadata_with_empty_key(self):
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.update_all_metadata,
+ self.shares_v2_client.update_all_metadata,
self.share["id"], {"": "value"})
@decorators.idempotent_id('94c7ebb3-14c3-4ff1-9839-ae3acb318cd0')
@@ -77,7 +77,7 @@
too_big_key = "x" * 256
md = {too_big_key: "value"}
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.set_metadata,
+ self.shares_v2_client.set_metadata,
self.share["id"], md)
@decorators.idempotent_id('33ef3047-6ca3-4547-a681-b52314382dcb')
@@ -86,7 +86,7 @@
too_big_key = "x" * 256
md = {too_big_key: "value"}
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.update_all_metadata,
+ self.shares_v2_client.update_all_metadata,
self.share["id"], md)
@decorators.idempotent_id('1114970a-1b45-4c56-b20a-e13e1764e3c4')
@@ -95,7 +95,7 @@
too_big_value = "x" * 1024
md = {"key": too_big_value}
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.set_metadata,
+ self.shares_v2_client.set_metadata,
self.share["id"], md)
@decorators.idempotent_id('c2eddcf0-cf81-4f9f-b06d-c9165ab8553e')
@@ -104,12 +104,12 @@
too_big_value = "x" * 1024
md = {"key": too_big_value}
self.assertRaises(lib_exc.BadRequest,
- self.shares_client.update_all_metadata,
+ self.shares_v2_client.update_all_metadata,
self.share["id"], md)
@decorators.idempotent_id('14df3262-5a2b-4de4-b335-422329b22b07')
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
def test_try_delete_unexisting_metadata(self):
self.assertRaises(lib_exc.NotFound,
- self.shares_client.delete_metadata,
+ self.shares_v2_client.delete_metadata,
self.share["id"], "wrong_key")
diff --git a/manila_tempest_tests/tests/api/test_scheduler_hints.py b/manila_tempest_tests/tests/api/test_scheduler_hints.py
index 83e5a1a..5012f17 100644
--- a/manila_tempest_tests/tests/api/test_scheduler_hints.py
+++ b/manila_tempest_tests/tests/api/test_scheduler_hints.py
@@ -70,10 +70,10 @@
self.assertEqual(backend_a, backend_b)
# get metadata of share
- metadata_a = self.shares_client.get_metadata(
+ metadata_a = self.shares_v2_client.get_metadata(
self.share_a["id"])['metadata']
md_a = {"__affinity_same_host": "%s" % share_b["id"]}
- metadata_b = self.shares_client.get_metadata(
+ metadata_b = self.shares_v2_client.get_metadata(
share_b["id"])['metadata']
md_b = {"__affinity_same_host": "%s" % self.share_a["id"]}
diff --git a/manila_tempest_tests/utils.py b/manila_tempest_tests/utils.py
index 5ecfb36..29d6096 100644
--- a/manila_tempest_tests/utils.py
+++ b/manila_tempest_tests/utils.py
@@ -14,6 +14,7 @@
# under the License.
from collections import OrderedDict
+import json
import random
import re
@@ -225,3 +226,43 @@
headers = EXPERIMENTAL
extra_headers = True
return headers, extra_headers
+
+
+def _parse_resp(body, verify_top_key=None):
+ try:
+ body = json.loads(body)
+ except ValueError:
+ return body
+
+ # We assume, that if the first value of the deserialized body's
+ # item set is a dict or a list, that we just return the first value
+ # of deserialized body.
+ # Essentially "cutting out" the first placeholder element in a body
+ # that looks like this:
+ #
+ # {
+ # "users": [
+ # ...
+ # ]
+ # }
+ try:
+ # Ensure there are not more than one top-level keys
+ # NOTE(freerunner): Ensure, that JSON is not nullable to
+ # to prevent StopIteration Exception
+ if not hasattr(body, "keys") or len(body.keys()) != 1:
+ return body
+ # Just return the "wrapped" element
+ first_key, first_item = tuple(body.items())[0]
+ if isinstance(first_item, (dict, list)):
+ if verify_top_key is not None:
+ assert_msg = (
+ "The expected top level key is '%(top_key)s' but we "
+ "found '%(actual_key)s'." % {
+ 'top_key': verify_top_key,
+ 'actual_key': first_key
+ })
+ assert verify_top_key == first_key, assert_msg
+ return first_item
+ except (ValueError, IndexError):
+ pass
+ return body