Adds new functional tests for share-network-subnets

This patch adds functional test for share-network-subnets and
validates the new API version 2.51

Change-Id: I60bdb493ad5766f28408a0c877f960922fe44ad0
Partially-implements: bp share-network-multiple-subnets
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index 35fa1ed..c6b9c73 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -30,7 +30,7 @@
                help="The minimum api microversion is configured to be the "
                     "value of the minimum microversion supported by Manila."),
     cfg.StrOpt("max_api_microversion",
-               default="2.50",
+               default="2.51",
                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/json/shares_client.py b/manila_tempest_tests/services/share/json/shares_client.py
index 69aeba8..3481151 100644
--- a/manila_tempest_tests/services/share/json/shares_client.py
+++ b/manila_tempest_tests/services/share/json/shares_client.py
@@ -376,9 +376,9 @@
             raise share_exceptions.InvalidResource(
                 message=six.text_type(kwargs))
 
-    def _is_resource_deleted(self, func, res_id):
+    def _is_resource_deleted(self, func, res_id, **kwargs):
         try:
-            res = func(res_id)
+            res = func(res_id, **kwargs)
         except exceptions.NotFound:
             return True
         if res.get('status') in ['error_deleting', 'error']:
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 9439d80..3c1f5a4 100644
--- a/manila_tempest_tests/services/share/v2/json/shares_client.py
+++ b/manila_tempest_tests/services/share/v2/json/shares_client.py
@@ -226,6 +226,13 @@
         elif "message_id" in kwargs:
             return self._is_resource_deleted(
                 self.get_message, kwargs.get("message_id"))
+        elif "share_network_subnet_id" in kwargs:
+            subnet_kwargs = {
+                "sn_id": kwargs["extra_params"]["share_network_id"]}
+            return self._is_resource_deleted(
+                self.get_subnet, kwargs.get("share_network_subnet_id"),
+                **subnet_kwargs
+            )
         else:
             return super(SharesV2Client, self).is_resource_deleted(
                 *args, **kwargs)
@@ -1417,7 +1424,8 @@
 ###############
 
     def manage_share_server(self, host, share_network_id, identifier,
-                            driver_options=None, version=LATEST_MICROVERSION):
+                            driver_options=None, version=LATEST_MICROVERSION,
+                            share_network_subnet_id=None):
         body = {
             'share_server': {
                 'host': host,
@@ -1426,6 +1434,9 @@
                 'driver_options': driver_options if driver_options else {},
             }
         }
+        if share_network_subnet_id:
+            body['share_server']['share_network_subnet_id'] = (
+                share_network_subnet_id)
 
         body = json.dumps(body)
         resp, body = self.post('share-servers/manage', body,
@@ -1975,3 +1986,42 @@
         resp, body = self.get(uri, version=version)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
+
+###############
+
+    def create_subnet(
+            self, share_network_id, availability_zone=None,
+            neutron_net_id=None, neutron_subnet_id=None):
+        body = {'share_network_id': share_network_id}
+
+        if availability_zone:
+            body['availability_zone'] = availability_zone
+        if neutron_net_id:
+            body['neutron_net_id'] = neutron_net_id
+        if neutron_subnet_id:
+            body['neutron_subnet_id'] = neutron_subnet_id
+        body = json.dumps({"share-network-subnet": body})
+        url = '/share-networks/%s/subnets' % share_network_id
+        resp, body = self.post(url, body, version=LATEST_MICROVERSION)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def get_subnet(self, share_network_subnet_id, share_network_id):
+        url = ('share-networks/%(network)s/subnets/%(subnet)s' % {
+            'network': share_network_id,
+            'subnet': share_network_subnet_id}
+        )
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def delete_subnet(self, share_network_id, share_network_subnet_id):
+        url = ('share-networks/%(network)s/subnets/%(subnet)s' % {
+            'network': share_network_id,
+            'subnet': share_network_subnet_id}
+        )
+        resp, body = self.delete(url)
+        self.expected_success(202, resp.status)
+        return body
+
+###############
diff --git a/manila_tempest_tests/tests/api/admin/test_migration.py b/manila_tempest_tests/tests/api/admin/test_migration.py
index e979dcf..e4c8f5e 100644
--- a/manila_tempest_tests/tests/api/admin/test_migration.py
+++ b/manila_tempest_tests/tests/api/admin/test_migration.py
@@ -195,11 +195,14 @@
 
         old_share_network = self.shares_v2_client.get_share_network(
             old_share_network_id)
-
+        share_net_info = (
+            utils.share_network_get_default_subnet(old_share_network)
+            if utils.share_network_subnets_are_supported()
+            else old_share_network)
         new_share_network = self.create_share_network(
             cleanup_in_class=True,
-            neutron_net_id=old_share_network['neutron_net_id'],
-            neutron_subnet_id=old_share_network['neutron_subnet_id'])
+            neutron_net_id=share_net_info['neutron_net_id'],
+            neutron_subnet_id=share_net_info['neutron_subnet_id'])
 
         return new_share_network['id']
 
diff --git a/manila_tempest_tests/tests/api/admin/test_share_servers.py b/manila_tempest_tests/tests/api/admin/test_share_servers.py
index 82f61d6..65ccd96 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_servers.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_servers.py
@@ -53,6 +53,10 @@
             cls.share_network["name"],
             cls.share_network["id"],
         ]
+        cls.share_net_info = (
+            utils.share_network_get_default_subnet(cls.share_network)
+            if utils.share_network_subnets_are_supported()
+            else cls.share_network)
 
         # Date should be like '2014-13-12T11:10:09.000000'
         cls.date_re = re.compile("^([0-9]{4}-[0-9]{2}-[0-9]{2}[A-Z]{1}"
@@ -70,6 +74,7 @@
             "updated_at",
             "project_id",
         ]
+
         for server in servers:
             # All expected keys are present
             for key in keys:
@@ -171,6 +176,8 @@
         if utils.is_microversion_ge(CONF.share.max_api_microversion, "2.49"):
             keys.append("is_auto_deletable")
             keys.append("identifier")
+        if utils.is_microversion_ge(CONF.share.max_api_microversion, "2.51"):
+            keys.append("share_network_subnet_id")
         # all expected keys are present
         for key in keys:
             self.assertIn(key, server.keys())
@@ -211,8 +218,8 @@
         # TODO(vponomaryov): attach security-services too. If any exist from
         #                    donor share-network.
         new_sn = self.create_share_network(
-            neutron_net_id=self.share_network['neutron_net_id'],
-            neutron_subnet_id=self.share_network['neutron_subnet_id'])
+            neutron_net_id=self.share_net_info['neutron_net_id'],
+            neutron_subnet_id=self.share_net_info['neutron_subnet_id'])
 
         # Create server with share
         self.create_share(share_type_id=self.share_type_id,
@@ -274,8 +281,8 @@
         # Get network and subnet from existing share_network and reuse it
         # to be able to delete share_server after test ends.
         new_sn = self.create_share_network(
-            neutron_net_id=self.share_network['neutron_net_id'],
-            neutron_subnet_id=self.share_network['neutron_subnet_id'])
+            neutron_net_id=self.share_net_info['neutron_net_id'],
+            neutron_subnet_id=self.share_net_info['neutron_subnet_id'])
         share = self.create_share(
             share_type_id=self.share_type_id,
             share_network_id=new_sn['id']
diff --git a/manila_tempest_tests/tests/api/admin/test_share_servers_manage.py b/manila_tempest_tests/tests/api/admin/test_share_servers_manage.py
index ae4f007..661079f 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_servers_manage.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_servers_manage.py
@@ -13,12 +13,14 @@
 #    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
 import testtools
 from testtools import testcase as tc
 
 from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
 
 CONF = config.CONF
 
@@ -30,6 +32,7 @@
 @testtools.skipUnless(
     CONF.share.run_manage_unmanage_tests,
     'Manage/unmanage tests are disabled.')
+@ddt.ddt
 class ManageShareServersTest(base.BaseSharesAdminTest):
 
     @classmethod
@@ -51,23 +54,44 @@
                       "This test is not suitable for pre-existing "
                       "share_network.")
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
-    def test_manage_share_server(self):
-
+    @ddt.data(True, False)
+    def test_manage_share_server(self, add_subnet_field):
+        # Starting from v2.51 share network spans to multiple subnets.
+        if add_subnet_field and not utils.is_microversion_supported('2.51'):
+            msg = ("Manage share server with share network subnet is "
+                   "supported starting from microversion '2.51'.")
+            raise self.skipException(msg)
         # create a new share network to make sure that a new share server
         # will be created
         original_share_network = self.shares_v2_client.get_share_network(
             self.shares_v2_client.share_network_id
         )
+        share_net_info = (
+            utils.share_network_get_default_subnet(original_share_network)
+            if utils.share_network_subnets_are_supported()
+            else original_share_network)
         share_network = self.create_share_network(
-            neutron_net_id=original_share_network['neutron_net_id'],
-            neutron_subnet_id=original_share_network['neutron_subnet_id'],
+            neutron_net_id=share_net_info['neutron_net_id'],
+            neutron_subnet_id=share_net_info['neutron_subnet_id'],
             cleanup_in_class=True
         )
+        az = params = None
+        if add_subnet_field:
+            # Get a compatible availability zone
+            az = self.get_availability_zones_matching_share_type(
+                self.share_type['share_type'])[0]
+            az_subnet = self.shares_v2_client.create_subnet(
+                share_network['id'],
+                neutron_net_id=share_network['neutron_net_id'],
+                neutron_subnet_id=share_network['neutron_subnet_id'],
+                availability_zone=az
+            )
+            params = {'share_network_subnet_id': az_subnet['id']}
 
         # create share
         share = self.create_share(
             share_type_id=self.share_type['share_type']['id'],
-            share_network_id=share_network['id']
+            share_network_id=share_network['id'], availability_zone=az
         )
         share = self.shares_v2_client.get_share(share['id'])
         el = self.shares_v2_client.list_share_export_locations(share['id'])
@@ -88,6 +112,8 @@
             "is_auto_deletable",
             "identifier",
         ]
+        if add_subnet_field:
+            keys.append('share_network_subnet_id')
         # all expected keys are present
         for key in keys:
             self.assertIn(key, share_server)
@@ -95,6 +121,9 @@
         # check that the share server is initially auto-deletable
         self.assertIs(True, share_server["is_auto_deletable"])
         self.assertIsNotNone(share_server["identifier"])
+        if add_subnet_field:
+            self.assertEqual(az_subnet["id"],
+                             share_server["share_network_subnet_id"])
 
         self._unmanage_share_and_wait(share)
 
@@ -107,7 +136,8 @@
 
         # unmanage share server and manage it again
         self._unmanage_share_server_and_wait(share_server)
-        managed_share_server = self._manage_share_server(share_server)
+        managed_share_server = self._manage_share_server(share_server,
+                                                         fields=params)
         managed_share = self._manage_share(
             share,
             name="managed share that had ID %s" % share['id'],
@@ -138,3 +168,8 @@
 
         # delete share server
         self._delete_share_server_and_wait(managed_share_server['id'])
+
+        if add_subnet_field:
+            # delete the created subnet
+            self.shares_v2_client.delete_subnet(share_network['id'],
+                                                az_subnet['id'])
diff --git a/manila_tempest_tests/tests/api/admin/test_share_servers_manage_negative.py b/manila_tempest_tests/tests/api/admin/test_share_servers_manage_negative.py
index 62081c5..39ec08a 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_servers_manage_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_servers_manage_negative.py
@@ -23,6 +23,7 @@
 from manila_tempest_tests.common import constants
 from manila_tempest_tests import share_exceptions
 from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
 
 CONF = config.CONF
 
@@ -53,11 +54,15 @@
             extra_specs=cls.extra_specs)
         cls.original_share_network = cls.shares_v2_client.get_share_network(
             cls.shares_v2_client.share_network_id)
+        cls.share_net_info = (
+            utils.share_network_get_default_subnet(cls.original_share_network)
+            if utils.share_network_subnets_are_supported() else
+            cls.original_share_network)
 
     def _create_share_with_new_share_network(self):
         share_network = self.create_share_network(
-            neutron_net_id=self.original_share_network['neutron_net_id'],
-            neutron_subnet_id=self.original_share_network['neutron_subnet_id'],
+            neutron_net_id=self.share_net_info['neutron_net_id'],
+            neutron_subnet_id=self.share_net_info['neutron_subnet_id'],
             cleanup_in_class=True
         )
         share = self.create_share(
@@ -69,6 +74,7 @@
     @ddt.data(
         ('host', 'invalid_host'),
         ('share_network_id', 'invalid_share_network_id'),
+        ('share_network_subnet_id', 'invalid_share_network_subnet_id'),
     )
     @ddt.unpack
     @testtools.skipIf(CONF.share.share_network_id != "",
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index 3afd6fb..d3ebbb8 100644
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -361,8 +361,13 @@
                 # Try get suitable share-network
                 share_networks = sc.list_share_networks_with_detail()
                 for sn in share_networks:
-                    if (sn["neutron_net_id"] is None and
-                            sn["neutron_subnet_id"] is None and
+                    net_info = (
+                        utils.share_network_get_default_subnet(sn)
+                        if utils.share_network_subnets_are_supported() else sn)
+                    if net_info is None:
+                        continue
+                    if(net_info["neutron_net_id"] is None and
+                            net_info["neutron_subnet_id"] is None and
                             sn["name"] and search_word in sn["name"]):
                         share_network_id = sn["id"]
                         break
@@ -401,8 +406,14 @@
                     # Try get suitable share-network
                     share_networks = sc.list_share_networks_with_detail()
                     for sn in share_networks:
-                        if (net_id == sn["neutron_net_id"] and
-                                subnet_id == sn["neutron_subnet_id"] and
+                        net_info = (
+                            utils.share_network_get_default_subnet(sn)
+                            if utils.share_network_subnets_are_supported()
+                            else sn)
+                        if net_info is None:
+                            continue
+                        if (net_id == net_info["neutron_net_id"] and
+                                subnet_id == net_info["neutron_subnet_id"] and
                                 sn["name"] and search_word in sn["name"]):
                             share_network_id = sn["id"]
                             break
@@ -837,6 +848,26 @@
         return share_network
 
     @classmethod
+    def create_share_network_subnet(cls, client=None,
+                                    cleanup_in_class=False, **kwargs):
+        if client is None:
+            client = cls.shares_v2_client
+        share_network_subnet = client.create_subnet(**kwargs)
+        resource = {
+            "type": "share-network-subnet",
+            "id": share_network_subnet["id"],
+            "extra_params": {
+                "share_network_id": share_network_subnet["share_network_id"]
+            },
+            "client": client,
+        }
+        if cleanup_in_class:
+            cls.class_resources.insert(0, resource)
+        else:
+            cls.method_resources.insert(0, resource)
+        return share_network_subnet
+
+    @classmethod
     def create_security_service(cls, ss_type="ldap", client=None,
                                 cleanup_in_class=False, **kwargs):
         if client is None:
@@ -990,6 +1021,12 @@
                     elif res["type"] is "share_replica":
                         client.delete_share_replica(res_id)
                         client.wait_for_resource_deletion(replica_id=res_id)
+                    elif res["type"] is "share_network_subnet":
+                        sn_id = res["extra_params"]["share_network_id"]
+                        client.delete_subnet(sn_id, res_id)
+                        client.wait_for_resource_deletion(
+                            share_network_subnet_id=res_id,
+                            sn_id=sn_id)
                     else:
                         LOG.warning("Provided unsupported resource type for "
                                     "cleanup '%s'. Skipping.", res["type"])
@@ -1006,6 +1043,14 @@
         return data
 
     @classmethod
+    def generate_subnet_data(self):
+        data = {
+            "neutron_net_id": data_utils.rand_name("net-id"),
+            "neutron_subnet_id": data_utils.rand_name("subnet-id"),
+        }
+        return data
+
+    @classmethod
     def generate_security_service_data(self, set_ou=False):
         data = {
             "name": data_utils.rand_name("ss-name"),
@@ -1192,10 +1237,12 @@
 
     def _manage_share_server(self, share_server, fields=None):
         params = fields or {}
+        subnet_id = params.get('share_network_subnet_id', None)
         managed_share_server = self.shares_v2_client.manage_share_server(
             params.get('host', share_server['host']),
             params.get('share_network_id', share_server['share_network_id']),
             params.get('identifier', share_server['identifier']),
+            share_network_subnet_id=subnet_id,
         )
         self.shares_v2_client.wait_for_share_server_status(
             managed_share_server['id'],
diff --git a/manila_tempest_tests/tests/api/test_security_services_mapping_negative.py b/manila_tempest_tests/tests/api/test_security_services_mapping_negative.py
index fe59d6e..744e5ac 100644
--- a/manila_tempest_tests/tests/api/test_security_services_mapping_negative.py
+++ b/manila_tempest_tests/tests/api/test_security_services_mapping_negative.py
@@ -21,6 +21,7 @@
 from testtools import testcase as tc
 
 from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
 
 CONF = config.CONF
 LOG = log.getLogger(__name__)
@@ -32,6 +33,9 @@
     def resource_setup(cls):
         super(SecServicesMappingNegativeTest, cls).resource_setup()
         cls.sn = cls.create_share_network(cleanup_in_class=True)
+        cls.share_net_info = (
+            utils.share_network_get_default_subnet(cls.sn)
+            if utils.share_network_subnets_are_supported() else cls.sn)
         cls.ss = cls.create_security_service(cleanup_in_class=True)
         cls.cl = cls.shares_client
         # create share type
diff --git a/manila_tempest_tests/tests/api/test_share_network_subnets.py b/manila_tempest_tests/tests/api/test_share_network_subnets.py
new file mode 100644
index 0000000..d824680
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_share_network_subnets.py
@@ -0,0 +1,256 @@
+# Copyright 2019 NetApp Inc.
+# All Rights Reserved.
+#
+#    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
+import testtools
+from testtools import testcase as tc
+
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
+
+CONF = config.CONF
+
+
+@base.skip_if_microversion_lt("2.51")
+@ddt.ddt
+class ShareNetworkSubnetsTest(base.BaseSharesMixedTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareNetworkSubnetsTest, cls).resource_setup()
+        # create share_type
+        cls.extra_specs = {
+            'driver_handles_share_servers': CONF.share.multitenancy_enabled,
+        }
+        cls.share_type = cls._create_share_type(specs=cls.extra_specs)
+        cls.share_type_id = cls.share_type['id']
+        # create share_network
+        cls.share_network = cls.create_share_network()
+        cls.share_network_id = cls.share_network['id']
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_create_delete_subnet(self):
+        share_network = self.shares_v2_client.create_share_network()
+        share_network = self.shares_v2_client.get_share_network(
+            share_network['id']
+        )
+        default_subnet = share_network['share_network_subnets'][0]
+
+        az = self.shares_v2_client.list_availability_zones()[0]
+        az_name = az['name']
+
+        # Generate subnet data
+        data = self.generate_subnet_data()
+        data['share_network_id'] = share_network['id']
+        data['availability_zone'] = az_name
+
+        # create a new share network subnet
+        created = self.create_share_network_subnet(**data)
+        data['share_network_name'] = share_network['name']
+        # verify keys
+        keys = [
+            "share_network_name", "id", "network_type", "cidr",
+            "ip_version", "neutron_net_id", "neutron_subnet_id", "created_at",
+            "updated_at", "segmentation_id", "availability_zone", "gateway",
+            "share_network_id", "mtu"
+        ]
+
+        # Default subnet was created during share network creation
+        self.assertIsNone(default_subnet['availability_zone'])
+        # Match new subnet content
+        self.assertDictContainsSubset(data, created)
+
+        self.assertEqual(sorted(keys), sorted(list(created.keys())))
+
+        # Delete the subnets
+        self.shares_v2_client.delete_subnet(share_network['id'], created['id'])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_show_share_network_subnet(self):
+        share_network = self.create_share_network()
+        az = self.shares_v2_client.list_availability_zones()[0]
+        az_name = az['name']
+
+        # Generate subnet data
+        data = self.generate_subnet_data()
+        data['share_network_id'] = share_network['id']
+        data['availability_zone'] = az_name
+
+        # Create the share network subnet
+        created = self.create_share_network_subnet(**data)
+
+        # Shows the share network subnet
+        shown = self.shares_v2_client.get_subnet(created['id'],
+                                                 share_network['id'])
+
+        # Asserts
+        self.assertDictContainsSubset(data, shown)
+
+        # Deletes the created subnet
+        self.shares_v2_client.delete_subnet(share_network['id'],
+                                            created['id'])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    @testtools.skipIf(
+        not CONF.share.multitenancy_enabled, "Only for multitenancy.")
+    @testtools.skipIf(CONF.share.share_network_id != "",
+                      "This test is not suitable for pre-existing "
+                      "share_network.")
+    def test_create_share_on_subnet_with_availability_zone(self):
+        compatible_azs = self.get_availability_zones_matching_share_type(
+            self.share_type)
+        if len(compatible_azs) < 2:
+            msg = ("This test needs at least two compatible storage "
+                   "availability zones.")
+            raise self.skipException(msg)
+
+        original_share_network = self.shares_v2_client.get_share_network(
+            self.shares_v2_client.share_network_id
+        )
+        share_net_info = (
+            utils.share_network_get_default_subnet(original_share_network))
+        share_network = self.create_share_network(
+            neutron_net_id=share_net_info['neutron_net_id'],
+            neutron_subnet_id=share_net_info['neutron_subnet_id'],
+        )
+        share_network = self.shares_v2_client.get_share_network(
+            share_network['id']
+        )
+        default_subnet = share_network['share_network_subnets'][0]
+        availability_zone = compatible_azs[0]
+
+        data = {
+            "neutron_net_id": share_net_info['neutron_net_id'],
+            "neutron_subnet_id": share_net_info['neutron_subnet_id'],
+            'share_network_id': share_network['id'],
+            'availability_zone': availability_zone,
+        }
+        # Create a new share network subnet
+        subnet = self.create_share_network_subnet(**data)
+
+        # Create a new share in the select availability zone
+        # The 'status' of the share returned by the create API must be
+        share = self.create_share(
+            share_type_id=self.share_type_id,
+            share_network_id=share_network['id'],
+            availability_zone=availability_zone)
+        # Set and have value either 'creating' or
+        # 'available' (if share creation is really fast as in
+        # case of Dummy driver).
+        self.assertIn(share['status'], ('creating', 'available'))
+
+        share = self.admin_shares_v2_client.get_share(share['id'])
+        share_server = self.admin_shares_v2_client.show_share_server(
+            share['share_server_id']
+        )
+
+        # Default subnet was created during share network creation
+        self.assertIsNone(default_subnet['availability_zone'])
+        # Match new subnet content
+        self.assertDictContainsSubset(data, subnet)
+        # Match share server subnet
+        self.assertEqual(subnet['id'],
+                         share_server['share_network_subnet_id'])
+        # Delete share
+        self.shares_v2_client.delete_share(share['id'])
+        self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
+        # Delete the subnets
+        self.shares_v2_client.delete_subnet(share_network['id'], subnet['id'])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    @testtools.skipIf(
+        not CONF.share.multitenancy_enabled, "Only for multitenancy.")
+    @testtools.skipIf(CONF.share.share_network_id != "",
+                      "This test is not suitable for pre-existing "
+                      "share_network.")
+    @ddt.data(True, False)
+    def test_create_share_on_share_network_with_multiple_subnets(
+            self, create_share_with_az):
+        compatible_azs = self.get_availability_zones_matching_share_type(
+            self.share_type)
+        if len(compatible_azs) < 2:
+            msg = ("This test needs at least two compatible storage "
+                   "availability zones.")
+            raise self.skipException(msg)
+
+        original_share_network = self.shares_v2_client.get_share_network(
+            self.shares_v2_client.share_network_id
+        )
+        share_net_info = (
+            utils.share_network_get_default_subnet(original_share_network))
+        share_network = self.create_share_network(
+            neutron_net_id=share_net_info['neutron_net_id'],
+            neutron_subnet_id=share_net_info['neutron_subnet_id'],
+        )
+        share_network = self.shares_v2_client.get_share_network(
+            share_network['id']
+        )
+        default_subnet = share_network['share_network_subnets'][0]
+        # Save one availability zone to remain associated with default subnet
+        destination_az = compatible_azs.pop()
+        if not create_share_with_az:
+            destination_az = None
+
+        new_subnets = []
+        data = {
+            "neutron_net_id": share_net_info['neutron_net_id'],
+            "neutron_subnet_id": share_net_info['neutron_subnet_id'],
+            'share_network_id': share_network['id'],
+        }
+        for availability_zone in compatible_azs:
+            # update availability zone
+            data['availability_zone'] = availability_zone
+            # create a new share network subnet
+            subnet = self.create_share_network_subnet(**data)
+            new_subnets.append(subnet)
+
+        # Create a new share in the selected availability zone
+        share = self.create_share(
+            share_type_id=self.share_type_id,
+            share_network_id=share_network['id'],
+            availability_zone=destination_az)
+        # The 'status' of the share returned by the create API must be
+        # set and have value either 'creating' or 'available' (if share
+        # creation is really fast as in case of Dummy driver).
+        self.assertIn(share['status'], ('creating', 'available'))
+
+        share = self.admin_shares_v2_client.get_share(share['id'])
+        share_server = self.admin_shares_v2_client.show_share_server(
+            share['share_server_id']
+        )
+        # If no availability zone was provided during share creation, it is
+        # expected that the Scheduler selects one of the compatible backends to
+        # place the share. The destination availability zone may or may not
+        # have an specific share network subnet.
+        expected_subnet_id = (
+            next((subnet['id'] for subnet in new_subnets
+                 if subnet['availability_zone'] == share['availability_zone']),
+                 default_subnet['id']))
+        # Default subnet was created during share network creation
+        self.assertIsNone(default_subnet['availability_zone'])
+        # Match share server subnet
+        self.assertEqual(expected_subnet_id,
+                         share_server['share_network_subnet_id'])
+        if create_share_with_az:
+            self.assertEqual(destination_az,
+                             share['availability_zone'])
+        # Delete share
+        self.shares_v2_client.delete_share(share['id'])
+        self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
+        # Delete the subnets
+        for subnet in new_subnets:
+            self.shares_v2_client.delete_subnet(share_network['id'],
+                                                subnet['id'])
diff --git a/manila_tempest_tests/tests/api/test_share_network_subnets_negative.py b/manila_tempest_tests/tests/api/test_share_network_subnets_negative.py
new file mode 100644
index 0000000..7cedc07
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_share_network_subnets_negative.py
@@ -0,0 +1,270 @@
+# Copyright 2019 NetApp Inc.
+# All Rights Reserved.
+#
+#    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 import exceptions as lib_exc
+import testtools
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import constants
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests import utils
+
+CONF = config.CONF
+
+
+@base.skip_if_microversion_lt("2.51")
+@ddt.ddt
+class ShareNetworkSubnetsNegativeTest(base.BaseSharesAdminTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareNetworkSubnetsNegativeTest, cls).resource_setup()
+        # Create a new share network which will be used in the tests
+        cls.share_network = cls.shares_v2_client.create_share_network(
+            cleanup_in_class=True)
+        cls.share_network_id = cls.share_network['id']
+        cls.share_type = cls._create_share_type()
+        cls.az = cls.shares_v2_client.list_availability_zones()[0]
+        cls.az_name = cls.az['name']
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_add_share_network_subnet_share_network_not_found(self):
+        data = self.generate_subnet_data()
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.create_subnet,
+                          'fake_inexistent_id',
+                          **data)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_add_share_network_subnet_az_not_found(self):
+        data = {'availability_zone': 'non-existent-az'}
+
+        self.assertRaises(lib_exc.BadRequest,
+                          self.shares_v2_client.create_subnet,
+                          self.share_network_id, **data)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    @ddt.data(True, False)
+    def test_add_share_network_subnet_in_same_az_exists(self, is_default):
+        share_network = self.shares_v2_client.create_share_network()
+        data = {}
+
+        if not is_default:
+            azs = self.get_availability_zones_matching_share_type(
+                self.share_type)
+            data['availability_zone'] = azs[0]
+            self.shares_v2_client.create_subnet(
+                share_network['id'], **data)
+
+        self.assertRaises(lib_exc.Conflict,
+                          self.shares_v2_client.create_subnet,
+                          share_network['id'], **data)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_add_share_network_subnet_missing_parameters(self):
+        # Generate subnet data
+        data = self.generate_subnet_data()
+        data['availability_zone'] = self.az_name
+
+        data.pop('neutron_net_id')
+        self.assertRaises(lib_exc.BadRequest,
+                          self.shares_v2_client.create_subnet,
+                          self.share_network_id, **data)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_show_subnet_share_network_not_found(self):
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.get_subnet,
+                          'fake-subnet',
+                          'fake-sn')
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_show_subnet_not_found(self):
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.get_subnet,
+                          'fake-subnet',
+                          self.share_network_id)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_get_deleted_subnet(self):
+        # Generate subnet data
+        data = self.generate_subnet_data()
+        data['share_network_id'] = self.share_network_id
+        az = self.shares_v2_client.list_availability_zones()[0]
+        data['availability_zone'] = az['name']
+
+        subnet = self.create_share_network_subnet(**data)
+
+        # Make sure that the created subnet contains the data
+        self.assertDictContainsSubset(data, subnet)
+
+        # Delete the given subnet
+        self.shares_v2_client.delete_subnet(self.share_network_id,
+                                            subnet['id'])
+        share_network = self.shares_v2_client.get_share_network(
+            self.share_network_id
+        )
+
+        self.assertIsNotNone(share_network)
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.get_subnet,
+                          subnet['id'],
+                          self.share_network['id'])
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    @testtools.skipIf(not CONF.share.multitenancy_enabled,
+                      'Can run only with drivers that do handle share servers '
+                      'creation. Skipping.')
+    @testtools.skipIf(not CONF.share.run_manage_unmanage_tests,
+                      'Can run only with manage/unmanage tests enabled.')
+    def test_delete_contains_unmanaged_share_servers(self):
+        # Get a compatible availability zone
+        az = self.get_availability_zones_matching_share_type(
+            self.share_type)[0]
+
+        share_network = self.shares_v2_client.get_share_network(
+            self.shares_v2_client.share_network_id
+        )
+        share_network_id = share_network['id']
+        subnet = utils.share_network_get_default_subnet(share_network)
+
+        # Generate subnet data
+        data = {'neutron_net_id': subnet['neutron_net_id'],
+                'neutron_subnet_id': subnet['neutron_subnet_id'],
+                'share_network_id': share_network_id,
+                'availability_zone': az}
+
+        # Create a new subnet in the desired az
+        subnet = self.create_share_network_subnet(**data)
+
+        args = {'share_network_id': share_network_id,
+                'share_type_id': self.share_type['id'],
+                'availability_zone': az}
+
+        # Create a share into the share network
+        share = self.shares_v2_client.create_share(**args)
+        self.shares_v2_client.wait_for_share_status(
+            share['id'], constants.STATUS_AVAILABLE)
+        share = self.shares_v2_client.get_share(share['id'])
+
+        # Gets the export locations to be used in the future
+        el = self.shares_v2_client.list_share_export_locations(share['id'])
+        share['export_locations'] = el
+
+        # Unmanages the share to make the share server become is_auto
+        # deletable=False
+        self._unmanage_share_and_wait(share)
+
+        # Assert that the user cannot delete a subnet that contains share
+        # servers which may have unmanaged stuff
+        self.assertRaises(lib_exc.Conflict,
+                          self.shares_v2_client.delete_subnet,
+                          share_network_id,
+                          subnet['id'])
+
+        # Manages the share again to start cleaning up the test stuff
+        managed_share = self.shares_v2_client.manage_share(
+            service_host=share['host'],
+            export_path=share['export_locations'][0],
+            protocol=share['share_proto'],
+            share_type_id=self.share_type['id'],
+            name='share_to_be_deleted',
+            description='share managed to be deleted',
+            share_server_id=share['share_server_id']
+        )
+
+        # Do some necessary cleanup
+        self.shares_v2_client.wait_for_share_status(
+            managed_share['id'], constants.STATUS_AVAILABLE)
+        self.shares_client.delete_share(managed_share['id'])
+        self.shares_v2_client.wait_for_resource_deletion(
+            share_id=managed_share["id"])
+        self._delete_share_server_and_wait(share['share_server_id'])
+        self.shares_v2_client.delete_subnet(share_network_id,
+                                            subnet['id'])
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    @testtools.skipIf(not CONF.share.multitenancy_enabled,
+                      'Can run only with drivers that do handle share servers '
+                      'creation. Skipping.')
+    def test_delete_contains_shares(self):
+        # Get a compatible availability zone
+        az = self.get_availability_zones_matching_share_type(
+            self.share_type)[0]
+
+        share_network = self.shares_v2_client.get_share_network(
+            self.shares_v2_client.share_network_id
+        )
+        share_network_id = share_network['id']
+        subnet = utils.share_network_get_default_subnet(share_network)
+
+        # Generate subnet data
+        data = {'neutron_net_id': subnet['neutron_net_id'],
+                'neutron_subnet_id': subnet['neutron_subnet_id'],
+                'share_network_id': share_network_id,
+                'availability_zone': az}
+
+        # Create a new subnet in the desired az
+        subnet = self.create_share_network_subnet(**data)
+
+        args = {'share_network_id': share_network_id,
+                'share_type_id': self.share_type['id'],
+                'availability_zone': az}
+
+        # Create a share into the share network
+        share = self.shares_v2_client.create_share(**args)
+        self.shares_v2_client.wait_for_share_status(
+            share['id'], constants.STATUS_AVAILABLE)
+        share = self.admin_shares_v2_client.get_share(share['id'])
+        share_server = self.admin_shares_v2_client.show_share_server(
+            share['share_server_id']
+        )
+        # Match share server subnet
+        self.assertEqual(subnet['id'],
+                         share_server['share_network_subnet_id'])
+
+        # Assert that the user cannot delete a subnet that contain shares
+        self.assertRaises(lib_exc.Conflict,
+                          self.shares_v2_client.delete_subnet,
+                          share_network_id,
+                          subnet['id'])
+        # Assert that the user cannot delete a share-network that contain
+        # shares
+        self.assertRaises(lib_exc.Conflict,
+                          self.shares_v2_client.delete_share_network,
+                          share_network_id)
+        # Cleanups
+        self.shares_client.delete_share(share['id'])
+        self.shares_v2_client.wait_for_resource_deletion(share_id=share["id"])
+        self._delete_share_server_and_wait(share['share_server_id'])
+        self.shares_v2_client.delete_subnet(share_network_id,
+                                            subnet['id'])
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_delete_subnet_share_network_not_found(self):
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.delete_subnet,
+                          'fake-sn',
+                          'fake-subnet')
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_delete_subnet_not_found(self):
+        self.assertRaises(lib_exc.NotFound,
+                          self.shares_v2_client.delete_subnet,
+                          self.share_network_id,
+                          'fake-subnet')
diff --git a/manila_tempest_tests/tests/api/test_share_networks.py b/manila_tempest_tests/tests/api/test_share_networks.py
index 975d261..b7cd0bf 100644
--- a/manila_tempest_tests/tests/api/test_share_networks.py
+++ b/manila_tempest_tests/tests/api/test_share_networks.py
@@ -76,6 +76,19 @@
         if utils.is_microversion_supported('2.20'):
             keys.append('mtu')
 
+        # In v2.51 and beyond, share-network does not have
+        # network parameters anymore.
+        if utils.is_microversion_supported('2.51'):
+            subnet_keys = [
+                "network_type", "cidr", "ip_version", "neutron_net_id",
+                "neutron_subnet_id", "segmentation_id", "gateway", "mtu"
+            ]
+            keys = list(set(keys) - set(subnet_keys))
+            keys.append('share_network_subnets')
+            for sn in listed:
+                [self.assertIn(key, list(subnet.keys())) for key in subnet_keys
+                 for subnet in sn['share_network_subnets']]
+
         [self.assertIn(key, sn.keys()) for sn in listed for key in keys]
 
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
@@ -279,11 +292,14 @@
                           cleanup_in_class=False)
         share_net_details = self.shares_v2_client.get_share_network(
             self.shares_v2_client.share_network_id)
+        share_net_info = (
+            utils.share_network_get_default_subnet(share_net_details)
+            if utils.share_network_subnets_are_supported()
+            else share_net_details)
         subnet_details = subnet_client.show_subnet(
-            share_net_details['neutron_subnet_id'])
-
+            share_net_info['neutron_subnet_id'])
         self.assertEqual(subnet_details['subnet']['gateway_ip'],
-                         share_net_details['gateway'])
+                         share_net_info['gateway'])
 
     @testtools.skipUnless(CONF.share.create_networks_when_multitenancy_enabled,
                           "Only for setups with network creation.")
@@ -299,8 +315,12 @@
                           cleanup_in_class=False)
         share_net_details = self.shares_v2_client.get_share_network(
             self.shares_v2_client.share_network_id)
+        share_net_info = (
+            utils.share_network_get_default_subnet(share_net_details)
+            if utils.share_network_subnets_are_supported()
+            else share_net_details)
         network_details = network_client.show_network(
-            share_net_details['neutron_net_id'])
+            share_net_info['neutron_net_id'])
 
         self.assertEqual(network_details['network']['mtu'],
-                         share_net_details['mtu'])
+                         share_net_info['mtu'])
diff --git a/manila_tempest_tests/tests/api/test_share_networks_negative.py b/manila_tempest_tests/tests/api/test_share_networks_negative.py
index ce04ef9..0308ebc 100644
--- a/manila_tempest_tests/tests/api/test_share_networks_negative.py
+++ b/manila_tempest_tests/tests/api/test_share_networks_negative.py
@@ -141,3 +141,40 @@
                 params=filters))
 
         self.assertEqual(0, len(share_networks))
+
+    @base.skip_if_microversion_lt("2.51")
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_share_network_contains_more_than_one_subnet(self):
+        share_network = self.create_share_network()
+        az = self.shares_v2_client.list_availability_zones()[0]
+        az_name = az['name']
+
+        # Generate subnet data
+        data = self.generate_subnet_data()
+        data['share_network_id'] = share_network['id']
+        data['availability_zone'] = az_name
+
+        # create share network
+        subnet = self.create_share_network_subnet(**data)
+
+        # Try to delete the share network
+        self.assertRaises(
+            lib_exc.Conflict,
+            self.shares_client.delete_share_network,
+            share_network['id']
+        )
+
+        self.shares_v2_client.delete_subnet(share_network['id'], subnet['id'])
+        share_network = self.shares_v2_client.get_share_network(
+            share_network['id'])
+        default_subnet = share_network['share_network_subnets'][0]
+        self.assertIsNone(default_subnet['availability_zone'])
+
+    @base.skip_if_microversion_lt("2.51")
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_share_network_inexistent_az(self):
+        self.assertRaises(
+            lib_exc.BadRequest,
+            self.shares_v2_client.create_share_network,
+            availability_zone='inexistent-availability-zone',
+        )
diff --git a/manila_tempest_tests/utils.py b/manila_tempest_tests/utils.py
index c2c7ec6..09effde 100644
--- a/manila_tempest_tests/utils.py
+++ b/manila_tempest_tests/utils.py
@@ -22,6 +22,7 @@
 import testtools
 
 CONF = config.CONF
+SHARE_NETWORK_SUBNETS_MICROVERSION = '2.51'
 
 
 def get_microversion_as_tuple(microversion_str):
@@ -177,3 +178,13 @@
         raise testtools.TestCase.skipException(
             "Share manage tests with multitenancy are disabled for "
             "microversion < 2.49")
+
+
+def share_network_subnets_are_supported():
+    return is_microversion_supported(SHARE_NETWORK_SUBNETS_MICROVERSION)
+
+
+def share_network_get_default_subnet(share_network):
+    return next((
+        subnet for subnet in share_network.get('share_network_subnets', [])
+        if subnet['availability_zone'] is None), None)