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>
This commit is contained in:
Goutham Pacha Ravi 2022-04-06 23:42:27 +05:30
parent 5203643c24
commit 8bb17fc562
5 changed files with 90 additions and 41 deletions

View File

@ -23,6 +23,7 @@ from tempest.lib.common.utils import data_utils
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 @@ class SharesClient(rest_client.RestClient):
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 @@ class SharesClient(rest_client.RestClient):
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')
###############

View File

@ -34,14 +34,15 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
# 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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
# 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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataTest(base.BaseSharesMixedTest):
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)

View File

@ -61,14 +61,14 @@ class SharesMetadataNegativeTest(base.BaseSharesMixedTest):
@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 @@ class SharesMetadataNegativeTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataNegativeTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataNegativeTest(base.BaseSharesMixedTest):
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 @@ class SharesMetadataNegativeTest(base.BaseSharesMixedTest):
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")

View File

@ -70,10 +70,10 @@ class SharesSchedulerHintsTest(base.BaseSharesMixedTest):
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"]}

View File

@ -14,6 +14,7 @@
# under the License.
from collections import OrderedDict
import json
import random
import re
@ -225,3 +226,43 @@ def get_extra_headers(request_version, graduation_version):
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