Add tempest tests for share snapshot metadata

Adds positive and negative tests for share snapshot metadata api.
Works for microversion 2.73 and later.

Partially-implements: bp/metadata-for-share-resources
Depends-On: I91151792d033a4297557cd5f330053d78895eb78
Change-Id: I78cccc6bcd1b8d938b00467d07f3fd6edf7bfc6f
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index b62c409..2c1b375 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -40,7 +40,7 @@
                     "This value is only used to validate the versions "
                     "response from Manila."),
     cfg.StrOpt("max_api_microversion",
-               default="2.71",
+               default="2.73",
                help="The maximum api microversion is configured to be the "
                     "value of the latest microversion supported by Manila."),
     cfg.StrOpt("region",
diff --git a/manila_tempest_tests/services/share/v2/json/shares_client.py b/manila_tempest_tests/services/share/v2/json/shares_client.py
index a87648c..87f7559 100644
--- a/manila_tempest_tests/services/share/v2/json/shares_client.py
+++ b/manila_tempest_tests/services/share/v2/json/shares_client.py
@@ -515,7 +515,8 @@
 ###############
 
     def create_snapshot(self, share_id, name=None, description=None,
-                        force=False, version=LATEST_MICROVERSION):
+                        force=False, metadata=None,
+                        version=LATEST_MICROVERSION):
         if name is None:
             name = data_utils.rand_name("tempest-created-share-snap")
         if description is None:
@@ -529,6 +530,9 @@
                 "share_id": share_id,
             }
         }
+        if utils.is_microversion_ge(version, "2.73") and metadata:
+            post_body["snapshot"]["metadata"] = metadata
+
         body = json.dumps(post_body)
         resp, body = self.post("snapshots", body, version=version)
         self.expected_success(202, resp.status)
@@ -2071,3 +2075,73 @@
 
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
+
+#################
+
+    def _update_metadata(self, resource, resource_id, metadata=None,
+                         method="post", parent_resource=None, parent_id=None):
+        if parent_resource is None:
+            uri = f'{resource}s/{resource_id}/metadata'
+        else:
+            uri = (f'{parent_resource}/{parent_id}'
+                   f'/{resource}s/{resource_id}/metadata')
+        if metadata is None:
+            metadata = {}
+        post_body = {"metadata": metadata}
+        body = json.dumps(post_body)
+        if method == "post":
+            resp, body = self.post(uri, body)
+        if method == "put":
+            resp, body = self.put(uri, body)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def set_metadata(self, resource_id, metadata=None, resource='share',
+                     parent_resource=None, parent_id=None):
+        return self._update_metadata(resource, resource_id, metadata,
+                                     method="post",
+                                     parent_resource=parent_resource,
+                                     parent_id=parent_id)
+
+    def update_all_metadata(self, resource_id, metadata=None,
+                            resource='share', parent_resource=None,
+                            parent_id=None):
+        return self._update_metadata(resource, resource_id, metadata,
+                                     method="put",
+                                     parent_resource=parent_resource,
+                                     parent_id=parent_id)
+
+    def delete_metadata(self, resource_id, key, resource='share',
+                        parent_resource=None, parent_id=None):
+        if parent_resource is None:
+            uri = f'{resource}s/{resource_id}/metadata/{key}'
+        else:
+            uri = (f'{parent_resource}/{parent_id}'
+                   f'/{resource}s/{resource_id}/metadata/{key}')
+        resp, body = self.delete(uri)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def get_metadata(self, resource_id, resource='share',
+                     parent_resource=None, parent_id=None):
+        if parent_resource is None:
+            uri = f'{resource}s/{resource_id}/metadata'
+        else:
+            uri = (f'{parent_resource}/{parent_id}'
+                   f'/{resource}s/{resource_id}/metadata')
+        resp, body = self.get(uri)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return rest_client.ResponseBody(resp, body)
+
+    def get_metadata_item(self, resource_id, key, resource='share',
+                          parent_resource=None, parent_id=None):
+        if parent_resource is None:
+            uri = f'{resource}s/{resource_id}/metadata/{key}'
+        else:
+            uri = (f'{parent_resource}/{parent_id}'
+                   f'/{resource}s/{resource_id}/metadata/{key}')
+        resp, body = self.get(uri)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
diff --git a/manila_tempest_tests/tests/api/admin/test_snapshot_manage.py b/manila_tempest_tests/tests/api/admin/test_snapshot_manage.py
index 7e2f9f1..79e80e6 100644
--- a/manila_tempest_tests/tests/api/admin/test_snapshot_manage.py
+++ b/manila_tempest_tests/tests/api/admin/test_snapshot_manage.py
@@ -112,6 +112,8 @@
                          "provider_location"]
         if utils.is_microversion_ge(version, '2.17'):
             expected_keys.extend(["user_id", "project_id"])
+        if utils.is_microversion_ge(version, '2.73'):
+            expected_keys.extend(["metadata"])
 
         actual_keys = snapshot.keys()
 
@@ -135,7 +137,8 @@
 
     @decorators.idempotent_id('5fb65a19-fb73-4b5a-9210-010f93e0304f')
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
-    @ddt.data('2.12', '2.16', CONF.share.max_api_microversion)
+    @ddt.data(*utils.deduplicate(['2.12', '2.16', '2.73',
+                                  CONF.share.max_api_microversion]))
     def test_manage_different_versions(self, version):
         """Run snapshot manage test for multiple versions.
 
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index 34f8e41..42c2fab 100755
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -562,13 +562,14 @@
     @classmethod
     def create_snapshot_wait_for_active(cls, share_id, name=None,
                                         description=None, force=False,
-                                        client=None, cleanup_in_class=True):
+                                        metadata=None, client=None,
+                                        cleanup_in_class=True):
         if client is None:
             client = cls.shares_v2_client
         if description is None:
             description = "Tempest's snapshot"
         snapshot = client.create_snapshot(
-            share_id, name, description, force)['snapshot']
+            share_id, name, description, force, metadata)['snapshot']
         resource = {
             "type": "snapshot",
             "id": snapshot["id"],
diff --git a/manila_tempest_tests/tests/api/test_metadata_negative.py b/manila_tempest_tests/tests/api/test_metadata_negative.py
index caa34ac..5caca5e 100644
--- a/manila_tempest_tests/tests/api/test_metadata_negative.py
+++ b/manila_tempest_tests/tests/api/test_metadata_negative.py
@@ -66,7 +66,7 @@
 
     @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):
+    def test_try_update_metadata_with_empty_key(self):
         self.assertRaises(lib_exc.BadRequest,
                           self.shares_v2_client.update_all_metadata,
                           self.share["id"], {"": "value"})
@@ -82,7 +82,7 @@
 
     @decorators.idempotent_id('33ef3047-6ca3-4547-a681-b52314382dcb')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_try_upd_metadata_with_too_big_key(self):
+    def test_try_update_metadata_with_too_big_key(self):
         too_big_key = "x" * 256
         md = {too_big_key: "value"}
         self.assertRaises(lib_exc.BadRequest,
@@ -100,7 +100,7 @@
 
     @decorators.idempotent_id('c2eddcf0-cf81-4f9f-b06d-c9165ab8553e')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_try_upd_metadata_with_too_big_value(self):
+    def test_try_update_metadata_with_too_big_value(self):
         too_big_value = "x" * 1024
         md = {"key": too_big_value}
         self.assertRaises(lib_exc.BadRequest,
diff --git a/manila_tempest_tests/tests/api/test_shares.py b/manila_tempest_tests/tests/api/test_shares.py
index 3ff87b2..11b6963 100644
--- a/manila_tempest_tests/tests/api/test_shares.py
+++ b/manila_tempest_tests/tests/api/test_shares.py
@@ -157,6 +157,13 @@
             self.assertNotIn('user_id', detailed_elements)
             self.assertNotIn('project_id', detailed_elements)
 
+        # In v2.73 and beyond, we expect metadata key
+        if utils.is_microversion_supported('2.73'):
+            detailed_elements.update({'metadata'})
+            self.assertTrue(detailed_elements.issubset(snap.keys()), msg)
+        else:
+            self.assertNotIn('metadata', detailed_elements)
+
         # delete snapshot
         self.shares_client.delete_snapshot(snap["id"])
         self.shares_client.wait_for_resource_deletion(snapshot_id=snap["id"])
diff --git a/manila_tempest_tests/tests/api/test_shares_actions.py b/manila_tempest_tests/tests/api/test_shares_actions.py
index 987658d..1b987ae 100644
--- a/manila_tempest_tests/tests/api/test_shares_actions.py
+++ b/manila_tempest_tests/tests/api/test_shares_actions.py
@@ -470,7 +470,7 @@
         if version and utils.is_microversion_ge(version, '2.17'):
             expected_keys.extend(["user_id", "project_id"])
         if version and utils.is_microversion_ge(version, '2.73'):
-            expected_keys.append("metadata")
+            expected_keys.extend(["metadata"])
         actual_keys = snapshot.keys()
 
         # strict key check
@@ -552,6 +552,9 @@
         if version and utils.is_microversion_ge(version, '2.73'):
             expected_keys.append("metadata")
 
+        if version and utils.is_microversion_ge(version, '2.73'):
+            expected_keys.extend(["metadata"])
+
         # strict key check
         [self.assertEqual(set(expected_keys), set(s.keys())) for s in snaps]
 
diff --git a/manila_tempest_tests/tests/api/test_snapshot_metadata.py b/manila_tempest_tests/tests/api/test_snapshot_metadata.py
new file mode 100644
index 0000000..fb64618
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_snapshot_metadata.py
@@ -0,0 +1,317 @@
+# 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 import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from testtools import testcase as tc
+
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
+
+CONF = config.CONF
+LATEST_MICROVERSION = CONF.share.max_api_microversion
+
+
+class ShareSnapshotMetadataTest(base.BaseSharesMixedTest):
+    @classmethod
+    def skip_checks(cls):
+        super(ShareSnapshotMetadataTest, cls).skip_checks()
+        utils.check_skip_if_microversion_not_supported("2.73")
+        if not CONF.share.run_snapshot_tests:
+            raise cls.skipException('Snapshot tests are disabled.')
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareSnapshotMetadataTest, cls).resource_setup()
+        # create share_type
+        extra_specs = {}
+        if CONF.share.capability_snapshot_support:
+            extra_specs.update({'snapshot_support': True})
+        if CONF.share.capability_create_share_from_snapshot_support:
+            extra_specs.update({'create_share_from_snapshot_support': True})
+        cls.share_type = cls.create_share_type(extra_specs=extra_specs)
+        cls.share_type_id = cls.share_type['id']
+
+        # create share
+        cls.share_name = data_utils.rand_name("tempest-share-name")
+        cls.share_desc = data_utils.rand_name("tempest-share-description")
+        cls.share = cls.create_share(
+            name=cls.share_name,
+            description=cls.share_desc,
+            share_type_id=cls.share_type_id,
+        )
+        cls.share_id = cls.share["id"]
+
+        # create snapshot
+        cls.snap_name = data_utils.rand_name("tempest-snapshot-name")
+        cls.snap_desc = data_utils.rand_name(
+            "tempest-snapshot-description")
+        cls.snap = cls.create_snapshot_wait_for_active(
+            cls.share_id, cls.snap_name, cls.snap_desc)
+        cls.snap_id = cls.snap['id']
+
+    def _verify_snapshot_metadata(self, snapshot, md):
+
+        # get metadata of snapshot
+        metadata = self.shares_v2_client.get_metadata(
+            snapshot['id'], resource="snapshot")['metadata']
+
+        # verify metadata
+        self.assertEqual(md, metadata)
+
+        # verify metadata items
+        for key in md:
+            get_value = self.shares_v2_client.get_metadata_item(
+                snapshot['id'], key, resource="snapshot")
+            self.assertEqual(md[key], get_value[key])
+
+    @decorators.idempotent_id('5d537913-ce6f-4771-beb2-84e2390b06d3')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_metadata_in_snapshot_creation(self):
+
+        md = {u"key1": u"value1", u"key2": u"value2", }
+
+        # create snapshot with metadata
+        snapshot = self.create_snapshot_wait_for_active(
+            share_id=self.share_id, metadata=md,
+            cleanup_in_class=False)
+
+        # verify metadata
+        self._verify_snapshot_metadata(snapshot, md)
+
+    @decorators.idempotent_id('7cbdf3c5-fb72-4ea5-9e60-ba50bad68ee9')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_get_delete_metadata(self):
+
+        md = {u"key3": u"value3", u"key4": u"value4", u"key.5.1": u"value.5"}
+
+        # create snapshot
+        snapshot = self.create_snapshot_wait_for_active(
+            share_id=self.share_id,
+            cleanup_in_class=False)
+
+        # set metadata
+        self.shares_v2_client.set_metadata(
+            snapshot['id'], md, resource="snapshot")
+
+        # verify metadata
+        self._verify_snapshot_metadata(snapshot, md)
+
+        # delete metadata
+        for key in md.keys():
+            self.shares_v2_client.delete_metadata(
+                snapshot['id'], key, resource="snapshot")
+
+        # verify deletion of metadata
+        get_metadata = self.shares_v2_client.get_metadata(
+            snapshot['id'], resource="snapshot")['metadata']
+        self.assertEmpty(get_metadata)
+
+    @decorators.idempotent_id('23ec837d-1b50-499c-bbb9-a7bde843c9e8')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_metadata_not_delete_pre_metadata(self):
+        md1 = {u"key9": u"value9", u"key10": u"value10", }
+        md2 = {u"key11": u"value11", u"key12": u"value12", }
+
+        # create snapshot
+        snapshot = self.create_snapshot_wait_for_active(
+            share_id=self.share_id,
+            cleanup_in_class=False)
+
+        # set metadata
+        self.shares_v2_client.set_metadata(
+            snapshot['id'], md1, resource="snapshot")
+
+        # verify metadata
+        self._verify_snapshot_metadata(snapshot, md1)
+
+        # set metadata again
+        self.shares_v2_client.set_metadata(
+            snapshot['id'], md2, resource="snapshot")
+
+        # verify metadata
+        md1.update(md2)
+        md = md1
+
+        # verify metadata
+        self._verify_snapshot_metadata(snapshot, md)
+
+        # delete metadata
+        for key in md.keys():
+            self.shares_v2_client.delete_metadata(
+                snapshot['id'], key, resource="snapshot")
+
+        # verify deletion of metadata
+        get_metadata = self.shares_v2_client.get_metadata(
+            snapshot['id'], resource="snapshot")['metadata']
+        self.assertEmpty(get_metadata)
+
+    @decorators.idempotent_id('b7a00be5-3dd1-4d25-8723-c662581c923f')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_metadata_key_already_exist(self):
+        md1 = {u"key9": u"value9", u"key10": u"value10", }
+        md2 = {u"key9": u"value13", u"key11": u"value11", }
+
+        # create snapshot
+        snapshot = self.create_snapshot_wait_for_active(
+            share_id=self.share_id,
+            cleanup_in_class=False)
+
+        # set metadata
+        self.shares_v2_client.set_metadata(
+            snapshot['id'], md1, resource="snapshot")
+
+        # verify metadata
+        self._verify_snapshot_metadata(snapshot, md1)
+
+        # set metadata again
+        self.shares_v2_client.set_metadata(
+            snapshot['id'], md2, resource="snapshot")
+
+        # verify metadata
+        md1.update(md2)
+        self._verify_snapshot_metadata(snapshot, md1)
+
+        # delete metadata
+        for key in md1.keys():
+            self.shares_v2_client.delete_metadata(
+                snapshot['id'], key, resource="snapshot")
+
+        # verify deletion of metadata
+        get_metadata = self.shares_v2_client.get_metadata(
+            snapshot['id'], resource="snapshot")['metadata']
+        self.assertEmpty(get_metadata)
+
+    @decorators.idempotent_id('90120310-07a9-43f4-9d5e-38d0a3f2f5bb')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_and_update_metadata_by_key(self):
+
+        md1 = {u"key5": u"value5", u"key6": u"value6", }
+        md2 = {u"key7": u"value7", u"key8": u"value8", }
+
+        # create snapshot
+        snapshot = self.create_snapshot_wait_for_active(
+            share_id=self.share_id,
+            cleanup_in_class=False)
+
+        # set metadata
+        self.shares_v2_client.set_metadata(
+            snapshot['id'], md1, resource="snapshot")
+
+        # update metadata
+        self.shares_v2_client.update_all_metadata(
+            snapshot['id'], md2, resource="snapshot")
+
+        # verify metadata
+        self._verify_snapshot_metadata(snapshot, md2)
+
+    @decorators.idempotent_id('8963b7ae-db3a-476e-b0c7-29023e7aa321')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_metadata_min_size_key(self):
+        data = {"k": "value"}
+
+        self.shares_v2_client.set_metadata(self.snap_id,
+                                           data, resource="snapshot")
+
+        body_get = self.shares_v2_client.get_metadata(
+            self.snap_id, resource="snapshot")['metadata']
+        self.assertEqual(data['k'], body_get.get('k'))
+
+    @decorators.idempotent_id('dc226070-5820-4df2-a30a-9dfb2f037a4b')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_metadata_max_size_key(self):
+        max_key = "k" * 255
+        data = {max_key: "value"}
+
+        self.shares_v2_client.set_metadata(self.snap_id,
+                                           data, resource="snapshot")
+
+        body_get = self.shares_v2_client.get_metadata(
+            self.snap_id, resource="snapshot")['metadata']
+        self.assertIn(max_key, body_get)
+        self.assertEqual(data[max_key], body_get.get(max_key))
+
+    @decorators.idempotent_id('940c283f-4f43-4122-86e8-32230da81886')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_metadata_min_size_value(self):
+        data = {"key": "v"}
+
+        self.shares_v2_client.set_metadata(self.snap_id,
+                                           data, resource="snapshot")
+
+        body_get = self.shares_v2_client.get_metadata(
+            self.snap_id, resource="snapshot")['metadata']
+        self.assertEqual(data['key'], body_get['key'])
+
+    @decorators.idempotent_id('85c480bc-0ffa-43e1-bc0a-284c5641996d')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_metadata_max_size_value(self):
+        max_value = "v" * 1023
+        data = {"key": max_value}
+
+        self.shares_v2_client.set_metadata(self.snap_id,
+                                           data, resource="snapshot")
+
+        body_get = self.shares_v2_client.get_metadata(
+            self.snap_id, resource="snapshot")['metadata']
+        self.assertEqual(data['key'], body_get['key'])
+
+    @decorators.idempotent_id('c42335ae-ee90-4b73-b022-51c0a9bc301d')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_upd_metadata_min_size_key(self):
+        data = {"k": "value"}
+
+        self.shares_v2_client.update_all_metadata(self.snap_id,
+                                                  data, resource="snapshot")
+
+        body_get = self.shares_v2_client.get_metadata(
+            self.snap_id, resource="snapshot")['metadata']
+        self.assertEqual(data, body_get)
+
+    @decorators.idempotent_id('1b5f06b0-bbff-49d1-8a4b-6e912039e2ba')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_upd_metadata_max_size_key(self):
+        max_key = "k" * 255
+        data = {max_key: "value"}
+
+        self.shares_v2_client.update_all_metadata(self.snap_id,
+                                                  data, resource="snapshot")
+
+        body_get = self.shares_v2_client.get_metadata(
+            self.snap_id, resource="snapshot")['metadata']
+        self.assertEqual(data, body_get)
+
+    @decorators.idempotent_id('849fdcd4-9b4c-4aea-833a-240d7d06966b')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_upd_metadata_min_size_value(self):
+        data = {"key": "v"}
+
+        self.shares_v2_client.update_all_metadata(self.snap_id,
+                                                  data, resource="snapshot")
+
+        body_get = self.shares_v2_client.get_metadata(
+            self.snap_id, resource="snapshot")['metadata']
+        self.assertEqual(data, body_get)
+
+    @decorators.idempotent_id('fdfbe469-6403-41de-b909-c4c13fc57407')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_upd_metadata_max_size_value(self):
+        max_value = "v" * 1023
+        data = {"key": max_value}
+
+        self.shares_v2_client.update_all_metadata(self.snap_id,
+                                                  data, resource="snapshot")
+
+        body_get = self.shares_v2_client.get_metadata(
+            self.snap_id, resource="snapshot")['metadata']
+        self.assertEqual(data, body_get)
diff --git a/manila_tempest_tests/tests/api/test_snapshot_metadata_negative.py b/manila_tempest_tests/tests/api/test_snapshot_metadata_negative.py
new file mode 100644
index 0000000..7a80e4a
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_snapshot_metadata_negative.py
@@ -0,0 +1,142 @@
+# 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 ddt
+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 testtools import testcase as tc
+
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
+
+CONF = config.CONF
+LATEST_MICROVERSION = CONF.share.max_api_microversion
+
+
+@ddt.ddt
+class ShareSnapshotMetadataNegativeTest(base.BaseSharesMixedTest):
+    @classmethod
+    def skip_checks(cls):
+        super(ShareSnapshotMetadataNegativeTest, cls).skip_checks()
+        utils.check_skip_if_microversion_not_supported("2.73")
+        if not CONF.share.run_snapshot_tests:
+            raise cls.skipException('Snapshot tests are disabled.')
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareSnapshotMetadataNegativeTest, cls).resource_setup()
+        # create share_type
+        extra_specs = {}
+        if CONF.share.capability_snapshot_support:
+            extra_specs.update({'snapshot_support': True})
+        if CONF.share.capability_create_share_from_snapshot_support:
+            extra_specs.update({'create_share_from_snapshot_support': True})
+        cls.share_type = cls.create_share_type(extra_specs=extra_specs)
+        cls.share_type_id = cls.share_type['id']
+
+        # create share
+        cls.share_name = data_utils.rand_name("tempest-share-name")
+        cls.share_desc = data_utils.rand_name("tempest-share-description")
+        cls.metadata = {
+            'foo_key_share_1': 'foo_value_share_1',
+            'bar_key_share_1': 'foo_value_share_1',
+        }
+        cls.share = cls.create_share(
+            name=cls.share_name,
+            description=cls.share_desc,
+            metadata=cls.metadata,
+            share_type_id=cls.share_type_id,
+        )
+        cls.share_id = cls.share["id"]
+
+        # create snapshot
+        cls.snap_name = data_utils.rand_name("tempest-snapshot-name")
+        cls.snap_desc = data_utils.rand_name(
+            "tempest-snapshot-description")
+        cls.snap = cls.create_snapshot_wait_for_active(
+            cls.share_id, cls.snap_name, cls.snap_desc)
+        cls.snap_id = cls.snap['id']
+
+    @decorators.idempotent_id('8be4773b-6af9-413f-97e2-8acdb6149e7a')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_try_set_metadata_to_unexisting_snapshot(self):
+        md = {u"key1": u"value1", u"key2": u"value2", }
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.set_metadata,
+                          "wrong_snapshot_id", md, resource="snapshot")
+
+    @decorators.idempotent_id('03a7f6e9-de8b-4669-87e1-b179308b477d')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_try_update_all_metadata_to_unexisting_snapshot(self):
+        md = {u"key1": u"value1", u"key2": u"value2", }
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.update_all_metadata,
+                          "wrong_snapshot_id", md, resource="snapshot")
+
+    @decorators.idempotent_id('ef0afcc8-7b12-41bc-8aa1-4916ad4b4560')
+    @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_v2_client.set_metadata,
+                          self.snap_id, {"": "value"}, resource="snapshot")
+
+    @decorators.idempotent_id('9f2aee7c-ebd6-4516-87f7-bd85453d74c9')
+    @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_v2_client.update_all_metadata,
+                          self.snap_id, {"": "value"}, resource="snapshot")
+
+    @decorators.idempotent_id('ef61255e-462c-49fe-8e94-ff3afafcccb3')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_try_set_metadata_with_too_big_key(self):
+        too_big_key = "x" * 256
+        md = {too_big_key: "value"}
+        self.assertRaises(lib_exc.BadRequest,
+                          self.shares_v2_client.set_metadata,
+                          self.snap_id, md, resource="snapshot")
+
+    @decorators.idempotent_id('f896f354-6179-4abb-b0c5-7b7dc96f0870')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_try_upd_metadata_with_too_big_key(self):
+        too_big_key = "x" * 256
+        md = {too_big_key: "value"}
+        self.assertRaises(lib_exc.BadRequest,
+                          self.shares_v2_client.update_all_metadata,
+                          self.snap_id, md, resource="snapshot")
+
+    @decorators.idempotent_id('1bf97c18-27df-4618-94f4-224d1a98bc0c')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_try_set_metadata_with_too_big_value(self):
+        too_big_value = "x" * 1024
+        md = {"key": too_big_value}
+        self.assertRaises(lib_exc.BadRequest,
+                          self.shares_v2_client.set_metadata,
+                          self.snap_id, md, resource="snapshot")
+
+    @decorators.idempotent_id('2b9e08fa-b35d-4bfe-9137-e59ab50bd9ef')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_try_upd_metadata_with_too_big_value(self):
+        too_big_value = "x" * 1024
+        md = {"key": too_big_value}
+        self.assertRaises(lib_exc.BadRequest,
+                          self.shares_v2_client.update_all_metadata,
+                          self.snap_id, md, resource="snapshot")
+
+    @decorators.idempotent_id('9afb381d-c48c-4c2c-a5b5-42463daef5a2')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_try_delete_unexisting_metadata(self):
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.delete_metadata,
+                          self.snap_id, "wrong_key", resource="snapshot")
diff --git a/manila_tempest_tests/tests/rbac/test_shares.py b/manila_tempest_tests/tests/rbac/test_shares.py
index f6f5297..c58a17e 100644
--- a/manila_tempest_tests/tests/rbac/test_shares.py
+++ b/manila_tempest_tests/tests/rbac/test_shares.py
@@ -273,14 +273,14 @@
         share = self.create_share(
             self.share_member_client, self.share_type['id'])
         self.do_request(
-            'set_metadata', expected_status=200, share_id=share['id'],
+            'set_metadata', expected_status=200, resource_id=share['id'],
             metadata={'key': 'value'})
 
         alt_share = self.create_share(
             self.alt_project_share_v2_client, self.share_type['id'])
         self.do_request(
             'set_metadata', expected_status=200,
-            share_id=alt_share['id'], metadata={'key': 'value'})
+            resource_id=alt_share['id'], metadata={'key': 'value'})
 
     @decorators.idempotent_id('2d91e97e-d0e5-4112-8b22-60cd4659586c')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@@ -290,14 +290,14 @@
             self.share_member_client, self.share_type['id'],
             metadata=metadata)
         self.do_request(
-            'get_metadata', expected_status=200, share_id=share['id'])
+            'get_metadata', expected_status=200, resource_id=share['id'])
 
         alt_share = self.create_share(
             self.alt_project_share_v2_client, self.share_type['id'],
             metadata=metadata)
         self.do_request(
             'get_metadata', expected_status=200,
-            share_id=alt_share['id'])
+            resource_id=alt_share['id'])
 
     @decorators.idempotent_id('4cd807d6-bac4-4d0f-a207-c84dfe77f032')
     @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@@ -306,7 +306,7 @@
             self.share_member_client, self.share_type['id'],
             metadata={'key': 'value'})
         self.do_request(
-            'delete_metadata', expected_status=200, share_id=share['id'],
+            'delete_metadata', expected_status=200, resource_id=share['id'],
             key='key')
 
         alt_share = self.create_share(
@@ -314,7 +314,7 @@
             metadata={'key': 'value'})
         self.do_request(
             'delete_metadata', expected_status=200,
-            share_id=alt_share['id'], key='key')
+            resource_id=alt_share['id'], key='key')
 
 
 class TestProjectMemberTestsNFS(ShareRbacSharesTests, base.BaseSharesTest):
@@ -468,14 +468,14 @@
         share = self.create_share(
             self.client, self.share_type['id'])
         self.do_request(
-            'set_metadata', expected_status=200, share_id=share['id'],
+            'set_metadata', expected_status=200, resource_id=share['id'],
             metadata={'key': 'value'})
 
         alt_share = self.create_share(
             self.alt_project_share_v2_client, self.share_type['id'])
         self.do_request(
             'set_metadata', expected_status=lib_exc.Forbidden,
-            share_id=alt_share['id'], metadata={'key': 'value'})
+            resource_id=alt_share['id'], metadata={'key': 'value'})
 
     @decorators.idempotent_id('a69a2b85-3374-4621-83a9-89937ddb520b')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@@ -485,14 +485,14 @@
         share = self.create_share(share_client, self.share_type['id'],
                                   metadata=metadata)
         self.do_request(
-            'get_metadata', expected_status=200, share_id=share['id'])
+            'get_metadata', expected_status=200, resource_id=share['id'])
 
         alt_share = self.create_share(
             self.alt_project_share_v2_client, self.share_type['id'],
             metadata=metadata)
         self.do_request(
             'get_metadata', expected_status=lib_exc.Forbidden,
-            share_id=alt_share['id'])
+            resource_id=alt_share['id'])
 
     @decorators.idempotent_id('bea5518a-338e-494d-9034-1d03658ed58b')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@@ -500,7 +500,7 @@
         share = self.create_share(
             self.client, self.share_type['id'], metadata={'key': 'value'})
         self.do_request(
-            'delete_metadata', expected_status=200, share_id=share['id'],
+            'delete_metadata', expected_status=200, resource_id=share['id'],
             key='key')
 
         alt_share = self.create_share(
@@ -508,7 +508,7 @@
             metadata={'key': 'value'})
         self.do_request(
             'delete_metadata', expected_status=lib_exc.Forbidden,
-            share_id=alt_share['id'], key='key')
+            resource_id=alt_share['id'], key='key')
 
 
 class TestProjectReaderTestsNFS(TestProjectMemberTestsNFS):
@@ -631,13 +631,13 @@
             self.share_member_client, self.share_type['id'])
         self.do_request(
             'set_metadata', expected_status=lib_exc.Forbidden,
-            share_id=share['id'], metadata={'key': 'value'})
+            resource_id=share['id'], metadata={'key': 'value'})
 
         alt_share = self.create_share(
             self.alt_project_share_v2_client, self.share_type['id'])
         self.do_request(
             'set_metadata', expected_status=lib_exc.Forbidden,
-            share_id=alt_share['id'], metadata={'key': 'value'})
+            resource_id=alt_share['id'], metadata={'key': 'value'})
 
     @decorators.idempotent_id('28cacc77-556f-4707-ba2b-5ef3e56d6ef9')
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@@ -652,14 +652,14 @@
             metadata={'key': 'value'})
         self.do_request(
             'delete_metadata', expected_status=lib_exc.Forbidden,
-            share_id=share['id'], key='key')
+            resource_id=share['id'], key='key')
 
         alt_share = self.create_share(
             self.alt_project_share_v2_client, self.share_type['id'],
             metadata={'key': 'value'})
         self.do_request(
             'delete_metadata', expected_status=lib_exc.Forbidden,
-            share_id=alt_share['id'], key='key')
+            resource_id=alt_share['id'], key='key')
 
 
 class TestProjectAdminTestsCEPHFS(TestProjectAdminTestsNFS):