Add tests for Share Network Subnet Metadata
Adds positive and negative tests for share network subnet metadata.
Works to microversion 2.78 and later.
Change-Id: I32268eaa16b6b56ef4dda32806983744809c8707
Depends-On: https://review.opendev.org/c/openstack/manila-tempest-plugin/+/877674
Signed-off-by: Kiran Pawar <kinpaa@gmail.com>
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 a9ab199..4b35687 100644
--- a/manila_tempest_tests/services/share/v2/json/shares_client.py
+++ b/manila_tempest_tests/services/share/v2/json/shares_client.py
@@ -2108,7 +2108,8 @@
def create_subnet(
self, share_network_id, availability_zone=None,
- neutron_net_id=None, neutron_subnet_id=None):
+ neutron_net_id=None, neutron_subnet_id=None,
+ metadata=None, version=LATEST_MICROVERSION):
body = {'share_network_id': share_network_id}
if availability_zone:
@@ -2117,6 +2118,9 @@
body['neutron_net_id'] = neutron_net_id
if neutron_subnet_id:
body['neutron_subnet_id'] = neutron_subnet_id
+
+ if utils.is_microversion_ge(version, "2.78") and metadata:
+ body["metadata"] = metadata
body = json.dumps({"share-network-subnet": body})
url = '/share-networks/%s/subnets' % share_network_id
resp, body = self.post(url, body, version=LATEST_MICROVERSION)
@@ -2312,6 +2316,7 @@
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)
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index 9583de8..7e9e1c4 100644
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -779,11 +779,12 @@
def create_share_network_subnet(cls,
client=None,
cleanup_in_class=False,
+ metadata=None,
**kwargs):
if client is None:
client = cls.shares_v2_client
share_network_subnet = client.create_subnet(
- **kwargs)['share_network_subnet']
+ metadata=metadata, **kwargs)['share_network_subnet']
resource = {
"type": "share_network_subnet",
"id": share_network_subnet["id"],
diff --git a/manila_tempest_tests/tests/api/test_share_network_subnet_metadata.py b/manila_tempest_tests/tests/api/test_share_network_subnet_metadata.py
new file mode 100644
index 0000000..2251b68
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_share_network_subnet_metadata.py
@@ -0,0 +1,386 @@
+# 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 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 ShareNetworkSubnetMetadataTest(base.BaseSharesMixedTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(ShareNetworkSubnetMetadataTest, cls).skip_checks()
+ utils.check_skip_if_microversion_not_supported("2.78")
+
+ @classmethod
+ def resource_setup(cls):
+ super(ShareNetworkSubnetMetadataTest, cls).resource_setup()
+ # create share_network and subnet
+ cls.share_network = cls.create_share_network(cleanup_in_class=True)
+ az = cls.shares_v2_client.list_availability_zones(
+ )['availability_zones'][0]
+ cls.az_name = az['name']
+
+ cls.data = utils.generate_subnet_data()
+ cls.data['share_network_id'] = cls.share_network['id']
+ cls.data['availability_zone'] = cls.az_name
+
+ cls.subnet = cls.create_share_network_subnet(cleanup_in_class=True,
+ **cls.data)
+
+ def _verify_subnet_metadata(self, subnet, md):
+ # get metadata of share-network-subnet
+ metadata = self.shares_v2_client.get_metadata(
+ subnet['id'], resource="subnet",
+ parent_resource="share-networks",
+ parent_id=subnet['share_network_id'])['metadata']
+
+ # verify metadata
+ self.assertEqual(md, metadata)
+
+ # verify metadata items
+ for key in md:
+ get_value = self.shares_v2_client.get_metadata_item(
+ subnet['id'], key, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=subnet['share_network_id'])['meta']
+ self.assertEqual(md[key], get_value[key])
+
+ @decorators.idempotent_id('260744c2-c062-4ce3-a57e-cce475650e7b')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_set_metadata_in_subnet_creation(self):
+ share_network = self.create_share_network()
+ az = self.shares_v2_client.list_availability_zones(
+ )['availability_zones'][0]
+ az_name = az['name']
+
+ # Generate subnet data
+ data = utils.generate_subnet_data()
+ data['share_network_id'] = share_network['id']
+ data['availability_zone'] = az_name
+
+ md = {u"key1": u"value1", u"key2": u"value2", }
+
+ # create network subnet with metadata
+ subnet = self.create_share_network_subnet(metadata=md,
+ cleanup_in_class=False,
+ **data)
+
+ # verify metadata
+ self._verify_subnet_metadata(subnet, md)
+
+ # Delete the subnets
+ self.shares_v2_client.delete_subnet(share_network['id'], subnet['id'])
+
+ @decorators.idempotent_id('ec5c02e9-fcee-4890-87bc-7937a247afe9')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_set_get_delete_metadata(self):
+ md = {u"key3": u"value3", u"key4": u"value4", u"key.5.1": u"value.5"}
+
+ # create subnet
+ subnet = self.create_share_network_subnet(**self.data)
+
+ # set metadata
+ self.shares_v2_client.set_metadata(
+ subnet['id'], md, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ # verify metadata
+ self._verify_subnet_metadata(subnet, md)
+
+ # delete metadata
+ for key in md.keys():
+ self.shares_v2_client.delete_metadata(
+ subnet['id'], key, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ # verify deletion of metadata
+ get_metadata = self.shares_v2_client.get_metadata(
+ subnet['id'], resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])['metadata']
+ self.assertEmpty(get_metadata)
+
+ # Delete the subnet
+ self.shares_v2_client.delete_subnet(self.share_network['id'],
+ subnet['id'])
+
+ @decorators.idempotent_id('9ff9c3b4-9bd0-4e8a-a317-726cab640a67')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ 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 subnet
+ subnet = self.create_share_network_subnet(**self.data)
+
+ # set metadata
+ self.shares_v2_client.set_metadata(
+ subnet['id'], md1, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ # verify metadata
+ self._verify_subnet_metadata(subnet, md1)
+
+ # set metadata again
+ self.shares_v2_client.set_metadata(
+ subnet['id'], md2, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ md1.update(md2)
+ md = md1
+
+ # verify metadata
+ self._verify_subnet_metadata(subnet, md)
+
+ # delete metadata
+ for key in md.keys():
+ self.shares_v2_client.delete_metadata(
+ subnet['id'], key, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ # verify deletion of metadata
+ get_metadata = self.shares_v2_client.get_metadata(
+ subnet['id'], resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])['metadata']
+ self.assertEmpty(get_metadata)
+
+ # Delete the subnet
+ self.shares_v2_client.delete_subnet(self.share_network['id'],
+ subnet['id'])
+
+ @decorators.idempotent_id('1973bcb0-93a5-49a5-84fb-a03f6f6ff43b')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ 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 subnet
+ subnet = self.create_share_network_subnet(**self.data)
+
+ # set metadata
+ self.shares_v2_client.set_metadata(
+ subnet['id'], md1, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ # verify metadata
+ self._verify_subnet_metadata(subnet, md1)
+
+ # set metadata again
+ self.shares_v2_client.set_metadata(
+ subnet['id'], md2, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ # verify metadata
+ md1.update(md2)
+ self._verify_subnet_metadata(subnet, md1)
+
+ # delete metadata
+ for key in md1.keys():
+ self.shares_v2_client.delete_metadata(
+ subnet['id'], key, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ # verify deletion of metadata
+ get_metadata = self.shares_v2_client.get_metadata(
+ subnet['id'], resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])['metadata']
+ self.assertEmpty(get_metadata)
+
+ # Delete the subnets
+ self.shares_v2_client.delete_subnet(self.share_network['id'],
+ subnet['id'])
+
+ @decorators.idempotent_id('d37ea163-7215-4c35-996a-1bc165e554de')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ 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 subnet
+ subnet = self.create_share_network_subnet(**self.data)
+
+ # set metadata
+ self.shares_v2_client.set_metadata(
+ subnet['id'], md1, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ # update metadata
+ self.shares_v2_client.update_all_metadata(
+ subnet['id'], md2, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ # verify metadata
+ self._verify_subnet_metadata(subnet, md2)
+
+ # Delete the subnets
+ self.shares_v2_client.delete_subnet(self.share_network['id'],
+ subnet['id'])
+
+ @decorators.idempotent_id('20b96e7e-33cf-41f2-8f00-357170fa27f9')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_set_metadata_min_size_key(self):
+ data = {"k": "value"}
+
+ self.shares_v2_client.set_metadata(self.subnet['id'],
+ data, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ body_get = self.shares_v2_client.get_metadata(
+ self.subnet['id'], resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])['metadata']
+ self.assertEqual(data['k'], body_get.get('k'))
+
+ @decorators.idempotent_id('b7933b35-04e7-4487-8e6a-730f7261a736')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_set_metadata_max_size_key(self):
+ max_key = "k" * 255
+ data = {max_key: "value"}
+
+ self.shares_v2_client.set_metadata(self.subnet['id'],
+ data, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ body_get = self.shares_v2_client.get_metadata(
+ self.subnet['id'], resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])['metadata']
+
+ self.assertIn(max_key, body_get)
+ self.assertEqual(data[max_key], body_get.get(max_key))
+
+ @decorators.idempotent_id('469cd8ca-5846-4ff7-9a94-1087fc369e0f')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_set_metadata_min_size_value(self):
+ data = {"key": "v"}
+
+ self.shares_v2_client.set_metadata(self.subnet['id'],
+ data, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ body_get = self.shares_v2_client.get_metadata(
+ self.subnet['id'], resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])['metadata']
+
+ self.assertEqual(data['key'], body_get['key'])
+
+ @decorators.idempotent_id('5aa3b4a2-79d3-4fa4-b923-eb120bbe2f29')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_set_metadata_max_size_value(self):
+ max_value = "v" * 1023
+ data = {"key": max_value}
+
+ self.shares_v2_client.set_metadata(self.subnet['id'],
+ data, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ body_get = self.shares_v2_client.get_metadata(
+ self.subnet['id'], resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])['metadata']
+
+ self.assertEqual(data['key'], body_get['key'])
+
+ @decorators.idempotent_id('336970cb-eb04-4d08-9941-44c1267c1d5a')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_upd_metadata_min_size_key(self):
+ data = {"k": "value"}
+
+ self.shares_v2_client.update_all_metadata(
+ self.subnet['id'], data, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ body_get = self.shares_v2_client.get_metadata(
+ self.subnet['id'], resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])['metadata']
+
+ self.assertEqual(data, body_get)
+
+ @decorators.idempotent_id('93ec3f28-4cd7-48da-8418-e945b9ec4530')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_upd_metadata_max_size_key(self):
+ max_key = "k" * 255
+ data = {max_key: "value"}
+
+ self.shares_v2_client.update_all_metadata(
+ self.subnet['id'], data, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ body_get = self.shares_v2_client.get_metadata(
+ self.subnet['id'], resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])['metadata']
+
+ self.assertEqual(data, body_get)
+
+ @decorators.idempotent_id('f9372c69-559a-47b8-b6a2-0b2876d7a985')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_upd_metadata_min_size_value(self):
+ data = {"key": "v"}
+
+ self.shares_v2_client.update_all_metadata(
+ self.subnet['id'], data, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ body_get = self.shares_v2_client.get_metadata(
+ self.subnet['id'], resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])['metadata']
+
+ self.assertEqual(data, body_get)
+
+ @decorators.idempotent_id('fdb6696f-910a-41a7-aab3-79addad86936')
+ @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+ def test_upd_metadata_max_size_value(self):
+ max_value = "v" * 1023
+ data = {"key": max_value}
+
+ self.shares_v2_client.update_all_metadata(
+ self.subnet['id'], data, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ body_get = self.shares_v2_client.get_metadata(
+ self.subnet['id'], resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])['metadata']
+
+ self.assertEqual(data, body_get)
diff --git a/manila_tempest_tests/tests/api/test_share_network_subnet_metadata_negative.py b/manila_tempest_tests/tests/api/test_share_network_subnet_metadata_negative.py
new file mode 100644
index 0000000..0ad9d46
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_share_network_subnet_metadata_negative.py
@@ -0,0 +1,138 @@
+# 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 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
+
+
+class ShareNetworkSubnetMetadataNegativeTest(base.BaseSharesMixedTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(ShareNetworkSubnetMetadataNegativeTest, cls).skip_checks()
+ utils.check_skip_if_microversion_not_supported("2.78")
+
+ @classmethod
+ def resource_setup(cls):
+ super(ShareNetworkSubnetMetadataNegativeTest, cls).resource_setup()
+ # create share_network and subnet
+ cls.share_network = cls.create_share_network()
+ az = cls.shares_v2_client.list_availability_zones(
+ )['availability_zones'][0]
+ cls.az_name = az['name']
+
+ data = utils.generate_subnet_data()
+ data['share_network_id'] = cls.share_network['id']
+ data['availability_zone'] = cls.az_name
+
+ cls.subnet = cls.create_share_network_subnet(**data)
+
+ @decorators.idempotent_id('852d080f-16f3-48c4-af26-d8440be9801b')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_try_set_metadata_to_unexisting_subnet(self):
+ share_network = self.create_share_network()
+ md = {u"key1": u"value1", u"key2": u"value2", }
+ self.assertRaises(lib_exc.NotFound,
+ self.shares_v2_client.set_metadata,
+ "wrong_subnet_id", md, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=share_network['id'])
+
+ @decorators.idempotent_id('dfe93a02-43cc-458c-92e5-ede6c2c2e597')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_try_update_all_metadata_to_unexisting_subnet(self):
+ share_network = self.create_share_network()
+ md = {u"key1": u"value1", u"key2": u"value2", }
+ self.assertRaises(lib_exc.NotFound,
+ self.shares_v2_client.update_all_metadata,
+ "wrong_subnet_id", md, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=share_network['id'])
+
+ @decorators.idempotent_id('fc561d8e-a2df-468f-a760-7b5d340b4b29')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_try_set_metadata_with_empty_key(self):
+ self.assertRaises(lib_exc.BadRequest,
+ self.shares_v2_client.set_metadata,
+ self.subnet['id'], {"": "value"}, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ @decorators.idempotent_id('b6066659-d635-4f24-9a65-fa3a132fd5ad')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_try_upd_metadata_with_empty_key(self):
+ self.assertRaises(lib_exc.BadRequest,
+ self.shares_v2_client.update_all_metadata,
+ self.subnet['id'], {"": "value"}, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ @decorators.idempotent_id('a1ea51a6-01a4-4b12-8508-04e45fdabb13')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ 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.subnet['id'], md, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ @decorators.idempotent_id('a02e3970-a3d3-4c0f-a7b8-2ea3f4459214')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ 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.subnet['id'], md, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ @decorators.idempotent_id('f086589e-81a2-4d73-9fb0-9dd235cd35f1')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ 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.subnet['id'], md, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ @decorators.idempotent_id('4693e944-4b85-4655-8245-f1da2b5f9ff3')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ 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.subnet['id'], md, resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])
+
+ @decorators.idempotent_id('30e82c73-edd3-4f23-8b8f-c38e67668381')
+ @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+ def test_try_delete_unexisting_metadata(self):
+ self.assertRaises(lib_exc.NotFound,
+ self.shares_v2_client.delete_metadata,
+ self.subnet['id'], "wrong_key", resource="subnet",
+ parent_resource="share-networks",
+ parent_id=self.share_network['id'])