Merge "Fix the exact filter can be filter by inexact value"
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index e13d334..9e4a168 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.37",
+               default="2.40",
                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 510b2f7..94e1ac6 100644
--- a/manila_tempest_tests/services/share/v2/json/shares_client.py
+++ b/manila_tempest_tests/services/share/v2/json/shares_client.py
@@ -852,11 +852,23 @@
 
 ###############
 
-    def _get_quotas_url(self, version):
+    @staticmethod
+    def _get_quotas_url(version):
         if utils.is_microversion_gt(version, "2.6"):
             return 'quota-sets'
         return 'os-quota-sets'
 
+    @staticmethod
+    def _get_quotas_url_arguments_as_str(user_id=None, share_type=None):
+        args_str = ''
+        if not (user_id is None or share_type is None):
+            args_str = "?user_id=%s&share_type=%s" % (user_id, share_type)
+        elif user_id is not None:
+            args_str = "?user_id=%s" % user_id
+        elif share_type is not None:
+            args_str = "?share_type=%s" % share_type
+        return args_str
+
     def default_quotas(self, tenant_id, url=None, version=LATEST_MICROVERSION):
         if url is None:
             url = self._get_quotas_url(version)
@@ -865,48 +877,46 @@
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
-    def show_quotas(self, tenant_id, user_id=None, url=None,
+    def show_quotas(self, tenant_id, user_id=None, share_type=None, url=None,
                     version=LATEST_MICROVERSION):
         if url is None:
             url = self._get_quotas_url(version)
         url += '/%s' % tenant_id
-        if user_id is not None:
-            url += "?user_id=%s" % user_id
+        url += self._get_quotas_url_arguments_as_str(user_id, share_type)
         resp, body = self.get(url, version=version)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
-    def reset_quotas(self, tenant_id, user_id=None, url=None,
+    def reset_quotas(self, tenant_id, user_id=None, share_type=None, url=None,
                      version=LATEST_MICROVERSION):
         if url is None:
             url = self._get_quotas_url(version)
         url += '/%s' % tenant_id
-        if user_id is not None:
-            url += "?user_id=%s" % user_id
+        url += self._get_quotas_url_arguments_as_str(user_id, share_type)
         resp, body = self.delete(url, version=version)
         self.expected_success(202, resp.status)
         return body
 
-    def detail_quotas(self, tenant_id, user_id=None, url=None,
+    def detail_quotas(self, tenant_id, user_id=None, share_type=None, url=None,
                       version=LATEST_MICROVERSION):
         if url is None:
             url = self._get_quotas_url(version)
         url += '/%s/detail' % tenant_id
-        if user_id is not None:
-            url += "?user_id=%s" % user_id
+        url += self._get_quotas_url_arguments_as_str(user_id, share_type)
         resp, body = self.get(url, version=version)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
     def update_quotas(self, tenant_id, user_id=None, shares=None,
                       snapshots=None, gigabytes=None, snapshot_gigabytes=None,
-                      share_networks=None, force=True, url=None,
-                      version=LATEST_MICROVERSION):
+                      share_networks=None,
+                      share_groups=None, share_group_snapshots=None,
+                      force=True, share_type=None,
+                      url=None, version=LATEST_MICROVERSION):
         if url is None:
             url = self._get_quotas_url(version)
         url += '/%s' % tenant_id
-        if user_id is not None:
-            url += "?user_id=%s" % user_id
+        url += self._get_quotas_url_arguments_as_str(user_id, share_type)
 
         put_body = {"tenant_id": tenant_id}
         if force:
@@ -921,6 +931,10 @@
             put_body["snapshot_gigabytes"] = snapshot_gigabytes
         if share_networks is not None:
             put_body["share_networks"] = share_networks
+        if share_groups is not None:
+            put_body["share_groups"] = share_groups
+        if share_group_snapshots is not None:
+            put_body["share_group_snapshots"] = share_group_snapshots
         put_body = json.dumps({"quota_set": put_body})
 
         resp, body = self.put(url, put_body, version=version)
diff --git a/manila_tempest_tests/tests/api/admin/test_quotas.py b/manila_tempest_tests/tests/api/admin/test_quotas.py
index fec32f3..02d0a62 100644
--- a/manila_tempest_tests/tests/api/admin/test_quotas.py
+++ b/manila_tempest_tests/tests/api/admin/test_quotas.py
@@ -13,14 +13,22 @@
 #    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 exceptions as lib_exc
+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
+PRE_SHARE_GROUPS_MICROVERSION = "2.39"
+SHARE_GROUPS_MICROVERSION = "2.40"
 
 
+@ddt.ddt
 class SharesAdminQuotasTest(base.BaseSharesAdminTest):
 
     @classmethod
@@ -40,6 +48,9 @@
         self.assertGreater(int(quotas["shares"]), -2)
         self.assertGreater(int(quotas["snapshots"]), -2)
         self.assertGreater(int(quotas["share_networks"]), -2)
+        if utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION):
+            self.assertGreater(int(quotas["share_groups"]), -2)
+            self.assertGreater(int(quotas["share_group_snapshots"]), -2)
 
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
     def test_show_quotas(self):
@@ -49,6 +60,9 @@
         self.assertGreater(int(quotas["shares"]), -2)
         self.assertGreater(int(quotas["snapshots"]), -2)
         self.assertGreater(int(quotas["share_networks"]), -2)
+        if utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION):
+            self.assertGreater(int(quotas["share_groups"]), -2)
+            self.assertGreater(int(quotas["share_group_snapshots"]), -2)
 
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
     def test_show_quotas_for_user(self):
@@ -59,12 +73,68 @@
         self.assertGreater(int(quotas["shares"]), -2)
         self.assertGreater(int(quotas["snapshots"]), -2)
         self.assertGreater(int(quotas["share_networks"]), -2)
+        if utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION):
+            self.assertGreater(int(quotas["share_groups"]), -2)
+            self.assertGreater(int(quotas["share_group_snapshots"]), -2)
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    @base.skip_if_microversion_not_supported(PRE_SHARE_GROUPS_MICROVERSION)
+    def test_show_sg_quotas_using_too_old_microversion(self):
+        quotas = self.shares_v2_client.show_quotas(
+            self.tenant_id, version=PRE_SHARE_GROUPS_MICROVERSION)
+
+        for key in ('share_groups', 'share_group_snapshots'):
+            self.assertNotIn(key, quotas)
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    @base.skip_if_microversion_not_supported(PRE_SHARE_GROUPS_MICROVERSION)
+    def test_show_sg_quotas_for_user_using_too_old_microversion(self):
+        quotas = self.shares_v2_client.show_quotas(
+            self.tenant_id, self.user_id,
+            version=PRE_SHARE_GROUPS_MICROVERSION)
+
+        for key in ('share_groups', 'share_group_snapshots'):
+            self.assertNotIn(key, quotas)
+
+    @ddt.data(
+        ('id', True),
+        ('name', False),
+    )
+    @ddt.unpack
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    @base.skip_if_microversion_lt("2.39")
+    def test_show_share_type_quotas(self, share_type_key, is_st_public):
+        # Create share type
+        share_type = self.create_share_type(
+            data_utils.rand_name("tempest-manila"),
+            is_public=is_st_public,
+            cleanup_in_class=False,
+            extra_specs=self.add_extra_specs_to_dict(),
+        )
+        if 'share_type' in share_type:
+            share_type = share_type['share_type']
+
+        # Get current project quotas
+        p_quotas = self.shares_v2_client.show_quotas(self.tenant_id)
+
+        # Get current quotas
+        st_quotas = self.shares_v2_client.show_quotas(
+            self.tenant_id, share_type=share_type[share_type_key])
+
+        # Share type quotas have values equal to project's
+        for key in ('shares', 'gigabytes', 'snapshots', 'snapshot_gigabytes'):
+            self.assertEqual(st_quotas[key], p_quotas[key])
+
+        # Verify that we do not have share groups related quotas
+        # for share types.
+        for key in ('share_groups', 'share_group_snapshots'):
+            self.assertNotIn(key, st_quotas)
 
 
+@ddt.ddt
 class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
 
     force_tenant_isolation = True
-    client_version = '2'
 
     @classmethod
     def resource_setup(cls):
@@ -75,8 +145,7 @@
 
     def setUp(self):
         super(self.__class__, self).setUp()
-        self.client = self.get_client_with_isolated_creds(
-            client_version=self.client_version)
+        self.client = self.get_client_with_isolated_creds(client_version='2')
         self.tenant_id = self.client.tenant_id
         self.user_id = self.client.user_id
 
@@ -90,6 +159,24 @@
         updated = self.client.update_quotas(self.tenant_id, shares=new_quota)
         self.assertEqual(new_quota, int(updated["shares"]))
 
+    @ddt.data(
+        "share_groups",
+        "share_group_snapshots",
+    )
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    @testtools.skipUnless(
+        CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+    @utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
+    def test_update_tenant_quota_share_groups(self, quota_key):
+        # Get current quotas
+        quotas = self.client.show_quotas(self.tenant_id)
+        new_quota = int(quotas[quota_key]) + 2
+
+        # Set new quota
+        updated = self.client.update_quotas(
+            self.tenant_id, **{quota_key: new_quota})
+        self.assertEqual(new_quota, int(updated[quota_key]))
+
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
     def test_update_user_quota_shares(self):
         # get current quotas
@@ -101,6 +188,65 @@
             self.tenant_id, self.user_id, shares=new_quota)
         self.assertEqual(new_quota, int(updated["shares"]))
 
+    @ddt.data(
+        "share_groups",
+        "share_group_snapshots",
+    )
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    @testtools.skipUnless(
+        CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+    @utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
+    def test_update_user_quota_share_groups(self, quota_key):
+        # Get current quotas
+        quotas = self.client.show_quotas(self.tenant_id, self.user_id)
+        new_quota = int(quotas[quota_key]) - 1
+
+        # Set new quota
+        updated = self.client.update_quotas(
+            self.tenant_id, self.user_id, **{quota_key: new_quota})
+        self.assertEqual(new_quota, int(updated[quota_key]))
+
+    def _create_share_type(self):
+        share_type = self.create_share_type(
+            data_utils.rand_name("tempest-manila"),
+            cleanup_in_class=False,
+            client=self.shares_v2_client,
+            extra_specs=self.add_extra_specs_to_dict(),
+        )
+        if 'share_type' in share_type:
+            share_type = share_type['share_type']
+        return share_type
+
+    @ddt.data(
+        ('id', True),
+        ('name', False),
+    )
+    @ddt.unpack
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    @base.skip_if_microversion_lt("2.39")
+    def test_update_share_type_quota(self, share_type_key, is_st_public):
+        share_type = self._create_share_type()
+
+        # Get current quotas
+        quotas = self.client.show_quotas(
+            self.tenant_id, share_type=share_type[share_type_key])
+
+        # Update quotas
+        for q in ('shares', 'gigabytes', 'snapshots', 'snapshot_gigabytes'):
+            new_quota = int(quotas[q]) - 1
+
+            # Set new quota
+            updated = self.client.update_quotas(
+                self.tenant_id, share_type=share_type[share_type_key],
+                **{q: new_quota})
+            self.assertEqual(new_quota, int(updated[q]))
+
+        current_quotas = self.client.show_quotas(
+            self.tenant_id, share_type=share_type[share_type_key])
+
+        for q in ('shares', 'gigabytes', 'snapshots', 'snapshot_gigabytes'):
+            self.assertEqual(int(quotas[q]) - 1, current_quotas[q])
+
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
     def test_update_tenant_quota_snapshots(self):
         # get current quotas
@@ -205,44 +351,108 @@
 
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
     def test_reset_tenant_quotas(self):
-        # get default_quotas
+        # Get default_quotas
         default = self.client.default_quotas(self.tenant_id)
 
-        # get current quotas
+        # Get current quotas
         custom = self.client.show_quotas(self.tenant_id)
 
-        # make quotas for update
-        shares = int(custom["shares"]) + 2
-        snapshots = int(custom["snapshots"]) + 2
-        gigabytes = int(custom["gigabytes"]) + 2
-        snapshot_gigabytes = int(custom["snapshot_gigabytes"]) + 2
-        share_networks = int(custom["share_networks"]) + 2
+        # Make quotas for update
+        data = {
+            "shares": int(custom["shares"]) + 2,
+            "snapshots": int(custom["snapshots"]) + 2,
+            "gigabytes": int(custom["gigabytes"]) + 2,
+            "snapshot_gigabytes": int(custom["snapshot_gigabytes"]) + 2,
+            "share_networks": int(custom["share_networks"]) + 2,
+        }
+        if (utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION) and
+                CONF.share.run_share_group_tests):
+            data["share_groups"] = int(custom["share_groups"]) + 2
+            data["share_group_snapshots"] = (
+                int(custom["share_group_snapshots"]) + 2)
 
         # set new quota
-        updated = self.client.update_quotas(
-            self.tenant_id,
-            shares=shares,
-            snapshots=snapshots,
-            gigabytes=gigabytes,
-            snapshot_gigabytes=snapshot_gigabytes,
-            share_networks=share_networks)
-        self.assertEqual(shares, int(updated["shares"]))
-        self.assertEqual(snapshots, int(updated["snapshots"]))
-        self.assertEqual(gigabytes, int(updated["gigabytes"]))
-        self.assertEqual(snapshot_gigabytes,
-                         int(updated["snapshot_gigabytes"]))
-        self.assertEqual(share_networks, int(updated["share_networks"]))
+        updated = self.client.update_quotas(self.tenant_id, **data)
+        self.assertEqual(data["shares"], int(updated["shares"]))
+        self.assertEqual(data["snapshots"], int(updated["snapshots"]))
+        self.assertEqual(data["gigabytes"], int(updated["gigabytes"]))
+        self.assertEqual(
+            data["snapshot_gigabytes"], int(updated["snapshot_gigabytes"]))
+        self.assertEqual(
+            data["share_networks"], int(updated["share_networks"]))
+        if (utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION) and
+                CONF.share.run_share_group_tests):
+            self.assertEqual(
+                data["share_groups"], int(updated["share_groups"]))
+            self.assertEqual(
+                data["share_group_snapshots"],
+                int(updated["share_group_snapshots"]))
 
-        # reset customized quotas
+        # Reset customized quotas
         self.client.reset_quotas(self.tenant_id)
 
-        # verify quotas
+        # Verify quotas
         reseted = self.client.show_quotas(self.tenant_id)
         self.assertEqual(int(default["shares"]), int(reseted["shares"]))
         self.assertEqual(int(default["snapshots"]), int(reseted["snapshots"]))
         self.assertEqual(int(default["gigabytes"]), int(reseted["gigabytes"]))
-        self.assertEqual(int(default["share_networks"]),
-                         int(reseted["share_networks"]))
+        self.assertEqual(
+            int(default["snapshot_gigabytes"]),
+            int(reseted["snapshot_gigabytes"]))
+        self.assertEqual(
+            int(default["share_networks"]), int(reseted["share_networks"]))
+        if (utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION) and
+                CONF.share.run_share_group_tests):
+            self.assertEqual(
+                int(default["share_groups"]), int(reseted["share_groups"]))
+            self.assertEqual(
+                int(default["share_group_snapshots"]),
+                int(reseted["share_group_snapshots"]))
+
+    @ddt.data(
+        ('id', True),
+        ('name', False),
+    )
+    @ddt.unpack
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    @base.skip_if_microversion_lt("2.39")
+    def test_reset_share_type_quotas(self, share_type_key, is_st_public):
+        share_type = self._create_share_type()
+
+        # get default_quotas
+        default_quotas = self.client.default_quotas(self.tenant_id)
+
+        # set new quota for project
+        updated_p_quota = self.client.update_quotas(
+            self.tenant_id,
+            shares=int(default_quotas['shares']) + 5,
+            snapshots=int(default_quotas['snapshots']) + 5,
+            gigabytes=int(default_quotas['gigabytes']) + 5,
+            snapshot_gigabytes=int(default_quotas['snapshot_gigabytes']) + 5)
+
+        # set new quota for project
+        self.client.update_quotas(
+            self.tenant_id,
+            share_type=share_type[share_type_key],
+            shares=int(default_quotas['shares']) + 3,
+            snapshots=int(default_quotas['snapshots']) + 3,
+            gigabytes=int(default_quotas['gigabytes']) + 3,
+            snapshot_gigabytes=int(default_quotas['snapshot_gigabytes']) + 3)
+
+        # reset share type quotas
+        self.client.reset_quotas(
+            self.tenant_id, share_type=share_type[share_type_key])
+
+        # verify quotas
+        current_p_quota = self.client.show_quotas(self.tenant_id)
+        current_st_quota = self.client.show_quotas(
+            self.tenant_id, share_type=share_type[share_type_key])
+        for key in ('shares', 'snapshots', 'gigabytes', 'snapshot_gigabytes'):
+            self.assertEqual(updated_p_quota[key], current_p_quota[key])
+
+            # Default share type quotas are current project quotas
+            self.assertNotEqual(default_quotas[key], current_st_quota[key])
+            self.assertEqual(current_p_quota[key], current_st_quota[key])
 
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
     def test_unlimited_quota_for_shares(self):
@@ -329,3 +539,197 @@
         quotas = self.client.show_quotas(self.tenant_id, self.user_id)
 
         self.assertEqual(-1, quotas.get('share_networks'))
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    @testtools.skipUnless(
+        CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+    @utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
+    def test_unlimited_quota_for_share_groups(self):
+        self.client.update_quotas(self.tenant_id, share_groups=-1)
+
+        quotas = self.client.show_quotas(self.tenant_id)
+
+        self.assertEqual(-1, quotas.get('share_groups'))
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    @testtools.skipUnless(
+        CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+    @utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
+    def test_unlimited_user_quota_for_share_group_snapshots(self):
+        self.client.update_quotas(
+            self.tenant_id, self.user_id, share_group_snapshots=-1)
+
+        quotas = self.client.show_quotas(self.tenant_id, self.user_id)
+
+        self.assertEqual(-1, quotas.get('share_group_snapshots'))
+
+    @ddt.data(11, -1)
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_update_user_quotas_bigger_than_project_quota(self, user_quota):
+        self.client.update_quotas(self.tenant_id, shares=10)
+        self.client.update_quotas(
+            self.tenant_id, user_id=self.user_id, force=True,
+            shares=user_quota)
+
+    @ddt.data(11, -1)
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    @base.skip_if_microversion_lt("2.39")
+    def test_update_share_type_quotas_bigger_than_project_quota(self, st_q):
+        share_type = self._create_share_type()
+        self.client.update_quotas(self.tenant_id, shares=10)
+
+        self.client.update_quotas(
+            self.tenant_id, share_type=share_type['name'], force=True,
+            shares=st_q)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    @base.skip_if_microversion_lt("2.39")
+    def test_set_share_type_quota_bigger_than_users_quota(self):
+        share_type = self._create_share_type()
+        self.client.update_quotas(self.tenant_id, force=False, shares=13)
+        self.client.update_quotas(
+            self.tenant_id, user_id=self.user_id, force=False, shares=11)
+
+        # Share type quota does not depend on user's quota, so we should be
+        # able to update it.
+        self.client.update_quotas(
+            self.tenant_id, share_type=share_type['name'], force=False,
+            shares=12)
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    @base.skip_if_microversion_lt("2.39")
+    def test_quotas_usages(self):
+        # Create share types
+        st_1, st_2 = (self._create_share_type() for i in (1, 2))
+
+        # Set quotas for project, user and both share types
+        self.client.update_quotas(self.tenant_id, shares=3, gigabytes=10)
+        self.client.update_quotas(
+            self.tenant_id, user_id=self.user_id, shares=2, gigabytes=7)
+        for st in (st_1['id'], st_2['name']):
+            self.client.update_quotas(
+                self.tenant_id, share_type=st, shares=2, gigabytes=4)
+
+        # Create share, 4Gb, st1 - ok
+        share_1 = self.create_share(
+            size=4, share_type_id=st_1['id'], client=self.client,
+            cleanup_in_class=False)
+
+        # Try create shares twice, failing on user and share type quotas
+        for size, st_id in ((3, st_1['id']), (4, st_2['id'])):
+            self.assertRaises(
+                lib_exc.OverLimit,
+                self.create_share,
+                size=size, share_type_id=st_id, client=self.client,
+                cleanup_in_class=False)
+
+        # Create share, 3Gb, st2 - ok
+        share_2 = self.create_share(
+            size=3, share_type_id=st_2['id'], client=self.client,
+            cleanup_in_class=False)
+
+        # Check quota usages
+        for g_l, g_use, s_l, s_use, kwargs in (
+                (10, 7, 3, 2, {}),
+                (7, 7, 2, 2, {'user_id': self.user_id}),
+                (4, 4, 2, 1, {'share_type': st_1['id']}),
+                (4, 3, 2, 1, {'share_type': st_2['name']})):
+            quotas = self.client.detail_quotas(
+                tenant_id=self.tenant_id, **kwargs)
+            self.assertEqual(0, quotas['gigabytes']['reserved'])
+            self.assertEqual(g_l, quotas['gigabytes']['limit'])
+            self.assertEqual(g_use, quotas['gigabytes']['in_use'])
+            self.assertEqual(0, quotas['shares']['reserved'])
+            self.assertEqual(s_l, quotas['shares']['limit'])
+            self.assertEqual(s_use, quotas['shares']['in_use'])
+
+        # Delete shares and then check usages
+        for share_id in (share_1['id'], share_2['id']):
+            self.client.delete_share(share_id)
+            self.client.wait_for_resource_deletion(share_id=share_id)
+        for kwargs in ({}, {'share_type': st_1['name']},
+                       {'user_id': self.user_id}, {'share_type': st_2['id']}):
+            quotas = self.client.detail_quotas(
+                tenant_id=self.tenant_id, **kwargs)
+            for key in ('shares', 'gigabytes'):
+                self.assertEqual(0, quotas[key]['reserved'])
+                self.assertEqual(0, quotas[key]['in_use'])
+
+    def _check_sg_usages(self, quotas, in_use, limit):
+        """Helper method for 'test_share_group_quotas_usages' test."""
+        self.assertEqual(0, int(quotas['share_groups']['reserved']))
+        self.assertEqual(in_use, int(quotas['share_groups']['in_use']))
+        self.assertEqual(limit, int(quotas['share_groups']['limit']))
+
+    def _check_sgs_usages(self, quotas, in_use):
+        """Helper method for 'test_share_group_quotas_usages' test."""
+        self.assertEqual(0, int(quotas['share_group_snapshots']['reserved']))
+        self.assertEqual(
+            in_use, int(quotas['share_group_snapshots']['in_use']))
+        self.assertEqual(1, int(quotas['share_group_snapshots']['limit']))
+
+    def _check_usages(self, sg_in_use, sgs_in_use):
+        """Helper method for 'test_share_group_quotas_usages' test."""
+        p_quotas = self.client.detail_quotas(tenant_id=self.tenant_id)
+        u_quotas = self.client.detail_quotas(
+            tenant_id=self.tenant_id, user_id=self.user_id)
+        self._check_sg_usages(p_quotas, sg_in_use, 3)
+        self._check_sg_usages(u_quotas, sg_in_use, 2)
+        self._check_sgs_usages(p_quotas, sgs_in_use)
+        self._check_sgs_usages(u_quotas, sgs_in_use)
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    @testtools.skipUnless(
+        CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+    @base.skip_if_microversion_lt(SHARE_GROUPS_MICROVERSION)
+    def test_share_group_quotas_usages(self):
+        # Set quotas for project (3 SG, 1 SGS) and user (2 SG, 1 SGS)
+        self.client.update_quotas(
+            self.tenant_id, share_groups=3, share_group_snapshots=1)
+        self.client.update_quotas(
+            self.tenant_id, user_id=self.user_id,
+            share_groups=2, share_group_snapshots=1)
+
+        # Check usages, they should be 0s
+        self._check_usages(0, 0)
+
+        # Create SG1 and check usages
+        share_group1 = self.create_share_group(
+            cleanup_in_class=False, client=self.client)
+        self._check_usages(1, 0)
+
+        # Create SGS1 and check usages
+        sg_snapshot = self.create_share_group_snapshot_wait_for_active(
+            share_group1['id'], cleanup_in_class=False, client=self.client)
+        self._check_usages(1, 1)
+
+        # Create SG2 from SGS1 and check usages
+        share_group2 = self.create_share_group(
+            cleanup_in_class=False, client=self.client,
+            source_share_group_snapshot_id=sg_snapshot['id'])
+        self._check_usages(2, 1)
+
+        # Try create SGS2, fail, then check usages
+        self.assertRaises(
+            lib_exc.OverLimit,
+            self.create_share_group,
+            client=self.client, cleanup_in_class=False)
+        self._check_usages(2, 1)
+
+        # Delete SG2 and check usages
+        self.client.delete_share_group(share_group2['id'])
+        self.client.wait_for_resource_deletion(
+            share_group_id=share_group2['id'])
+        self._check_usages(1, 1)
+
+        # Delete SGS1 and check usages
+        self.client.delete_share_group_snapshot(sg_snapshot['id'])
+        self.client.wait_for_resource_deletion(
+            share_group_snapshot_id=sg_snapshot['id'])
+        self._check_usages(1, 0)
+
+        # Delete SG1 and check usages
+        self.client.delete_share_group(share_group1['id'])
+        self.client.wait_for_resource_deletion(
+            share_group_id=share_group1['id'])
+        self._check_usages(0, 0)
diff --git a/manila_tempest_tests/tests/api/admin/test_quotas_negative.py b/manila_tempest_tests/tests/api/admin/test_quotas_negative.py
index b8557e1..91b2507 100644
--- a/manila_tempest_tests/tests/api/admin/test_quotas_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_quotas_negative.py
@@ -15,12 +15,17 @@
 
 import ddt
 from tempest import config
+from tempest.lib.common.utils import data_utils
 from tempest.lib import exceptions as lib_exc
+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
+PRE_SHARE_GROUPS_MICROVERSION = "2.39"
+SHARE_GROUPS_MICROVERSION = "2.40"
 
 
 @ddt.ddt
@@ -48,50 +53,35 @@
         self.assertRaises(lib_exc.NotFound,
                           client.reset_quotas, "")
 
+    @ddt.data(
+        {"shares": -2},
+        {"snapshots": -2},
+        {"gigabytes": -2},
+        {"snapshot_gigabytes": -2},
+        {"share_networks": -2},
+    )
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_update_shares_quota_with_wrong_data(self):
+    def test_update_quota_with_wrong_data(self, kwargs):
         # -1 is acceptable value as unlimited
         client = self.get_client_with_isolated_creds()
-        self.assertRaises(lib_exc.BadRequest,
-                          client.update_quotas,
-                          client.tenant_id,
-                          shares=-2)
+        self.assertRaises(
+            lib_exc.BadRequest,
+            client.update_quotas, client.tenant_id, **kwargs)
 
+    @ddt.data(
+        {"share_groups": -2},
+        {"share_group_snapshots": -2},
+    )
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_update_snapshots_quota_with_wrong_data(self):
+    @testtools.skipUnless(
+        CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+    @utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
+    def test_update_sg_quota_with_wrong_data(self, kwargs):
         # -1 is acceptable value as unlimited
-        client = self.get_client_with_isolated_creds()
-        self.assertRaises(lib_exc.BadRequest,
-                          client.update_quotas,
-                          client.tenant_id,
-                          snapshots=-2)
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_update_gigabytes_quota_with_wrong_data(self):
-        # -1 is acceptable value as unlimited
-        client = self.get_client_with_isolated_creds()
-        self.assertRaises(lib_exc.BadRequest,
-                          client.update_quotas,
-                          client.tenant_id,
-                          gigabytes=-2)
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_update_snapshot_gigabytes_quota_with_wrong_data(self):
-        # -1 is acceptable value as unlimited
-        client = self.get_client_with_isolated_creds()
-        self.assertRaises(lib_exc.BadRequest,
-                          client.update_quotas,
-                          client.tenant_id,
-                          snapshot_gigabytes=-2)
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_update_share_networks_quota_with_wrong_data(self):
-        # -1 is acceptable value as unlimited
-        client = self.get_client_with_isolated_creds()
-        self.assertRaises(lib_exc.BadRequest,
-                          client.update_quotas,
-                          client.tenant_id,
-                          share_networks=-2)
+        client = self.get_client_with_isolated_creds(client_version='2')
+        self.assertRaises(
+            lib_exc.BadRequest,
+            client.update_quotas, client.tenant_id, **kwargs)
 
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
     def test_create_share_with_size_bigger_than_quota(self):
@@ -105,6 +95,21 @@
                           size=overquota)
 
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    @testtools.skipUnless(
+        CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+    @utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
+    def test_create_share_group_with_exceeding_quota_limit(self):
+        client = self.get_client_with_isolated_creds(client_version='2')
+        client.update_quotas(client.tenant_id, share_groups=0)
+
+        # Try schedule share group creation
+        self.assertRaises(
+            lib_exc.OverLimit,
+            self.create_share_group,
+            client=client,
+            cleanup_in_class=False)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
     def test_try_set_user_quota_shares_bigger_than_tenant_quota(self):
         client = self.get_client_with_isolated_creds()
 
@@ -117,6 +122,7 @@
                           client.update_quotas,
                           client.tenant_id,
                           client.user_id,
+                          force=False,
                           shares=bigger_value)
 
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@@ -132,6 +138,7 @@
                           client.update_quotas,
                           client.tenant_id,
                           client.user_id,
+                          force=False,
                           snapshots=bigger_value)
 
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@@ -147,6 +154,7 @@
                           client.update_quotas,
                           client.tenant_id,
                           client.user_id,
+                          force=False,
                           gigabytes=bigger_value)
 
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@@ -162,6 +170,7 @@
                           client.update_quotas,
                           client.tenant_id,
                           client.user_id,
+                          force=False,
                           snapshot_gigabytes=bigger_value)
 
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
@@ -177,6 +186,7 @@
                           client.update_quotas,
                           client.tenant_id,
                           client.user_id,
+                          force=False,
                           share_networks=bigger_value)
 
     @ddt.data(
@@ -215,3 +225,133 @@
             self.shares_v2_client.tenant_id,
             version=version, url=url,
         )
+
+    @ddt.data('show', 'reset', 'update')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    @base.skip_if_microversion_lt("2.39")
+    def test_share_type_quotas_using_nonexistent_share_type(self, op):
+        client = self.get_client_with_isolated_creds(client_version='2')
+
+        kwargs = {"share_type": "fake_nonexistent_share_type"}
+        if op == 'update':
+            tenant_quotas = client.show_quotas(client.tenant_id)
+            kwargs['shares'] = tenant_quotas['shares']
+
+        self.assertRaises(
+            lib_exc.NotFound,
+            getattr(client, op + '_quotas'),
+            client.tenant_id,
+            **kwargs)
+
+    def _create_share_type(self):
+        share_type = self.create_share_type(
+            data_utils.rand_name("tempest-manila"),
+            cleanup_in_class=False,
+            client=self.shares_v2_client,
+            extra_specs=self.add_extra_specs_to_dict(),
+        )
+        if 'share_type' in share_type:
+            share_type = share_type['share_type']
+        return share_type
+
+    @ddt.data('id', 'name')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    @base.skip_if_microversion_lt("2.39")
+    def test_try_update_share_type_quota_for_share_networks(self, key):
+        client = self.get_client_with_isolated_creds(client_version='2')
+        share_type = self._create_share_type()
+        tenant_quotas = client.show_quotas(client.tenant_id)
+
+        # Try to set 'share_networks' quota for share type
+        self.assertRaises(
+            lib_exc.BadRequest,
+            client.update_quotas,
+            client.tenant_id,
+            share_type=share_type[key],
+            share_networks=int(tenant_quotas["share_networks"]),
+        )
+
+    @ddt.data('share_groups', 'share_group_snapshots')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    @base.skip_if_microversion_lt(SHARE_GROUPS_MICROVERSION)
+    def test_try_update_share_type_quota_for_share_groups(self, quota_name):
+        client = self.get_client_with_isolated_creds(client_version='2')
+        share_type = self._create_share_type()
+        tenant_quotas = client.show_quotas(client.tenant_id)
+
+        self.assertRaises(
+            lib_exc.BadRequest,
+            client.update_quotas,
+            client.tenant_id,
+            share_type=share_type["name"],
+            **{quota_name: int(tenant_quotas[quota_name])}
+        )
+
+    @ddt.data('share_groups', 'share_group_snapshots')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    @base.skip_if_microversion_not_supported(PRE_SHARE_GROUPS_MICROVERSION)
+    @base.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
+    def test_share_group_quotas_using_too_old_microversion(self, quota_key):
+        client = self.get_client_with_isolated_creds(client_version='2')
+        tenant_quotas = client.show_quotas(
+            client.tenant_id, version=SHARE_GROUPS_MICROVERSION)
+        kwargs = {
+            "version": PRE_SHARE_GROUPS_MICROVERSION,
+            quota_key: tenant_quotas[quota_key],
+        }
+
+        self.assertRaises(
+            lib_exc.BadRequest,
+            client.update_quotas,
+            client.tenant_id,
+            **kwargs)
+
+    @ddt.data('show', 'reset', 'update')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    @base.skip_if_microversion_lt("2.38")
+    def test_share_type_quotas_using_too_old_microversion(self, op):
+        client = self.get_client_with_isolated_creds(client_version='2')
+        share_type = self._create_share_type()
+        kwargs = {"version": "2.38", "share_type": share_type["name"]}
+        if op == 'update':
+            tenant_quotas = client.show_quotas(client.tenant_id)
+            kwargs['shares'] = tenant_quotas['shares']
+
+        self.assertRaises(
+            lib_exc.BadRequest,
+            getattr(client, op + '_quotas'),
+            client.tenant_id,
+            **kwargs)
+
+    @ddt.data('show', 'reset', 'update')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    @base.skip_if_microversion_lt("2.39")
+    def test_quotas_providing_share_type_and_user_id(self, op):
+        client = self.get_client_with_isolated_creds(client_version='2')
+        share_type = self._create_share_type()
+        kwargs = {"share_type": share_type["name"], "user_id": client.user_id}
+        if op == 'update':
+            tenant_quotas = client.show_quotas(client.tenant_id)
+            kwargs['shares'] = tenant_quotas['shares']
+
+        self.assertRaises(
+            lib_exc.BadRequest,
+            getattr(client, op + '_quotas'),
+            client.tenant_id,
+            **kwargs)
+
+    @ddt.data(11, -1)
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    @base.skip_if_microversion_lt("2.39")
+    def test_update_share_type_quotas_bigger_than_project_quota(self, st_q):
+        client = self.get_client_with_isolated_creds(client_version='2')
+        share_type = self._create_share_type()
+        client.update_quotas(client.tenant_id, shares=10)
+
+        self.assertRaises(
+            lib_exc.BadRequest,
+            client.update_quotas,
+            client.tenant_id,
+            share_type=share_type['name'],
+            force=False,
+            shares=st_q)
diff --git a/manila_tempest_tests/tests/api/admin/test_user_messages.py b/manila_tempest_tests/tests/api/admin/test_user_messages.py
index 1d23487..a887970 100644
--- a/manila_tempest_tests/tests/api/admin/test_user_messages.py
+++ b/manila_tempest_tests/tests/api/admin/test_user_messages.py
@@ -13,7 +13,7 @@
 from oslo_utils import timeutils
 from oslo_utils import uuidutils
 from tempest import config
-from tempest import test
+from tempest.lib import decorators
 
 from manila_tempest_tests.tests.api import base
 
@@ -43,7 +43,7 @@
         super(UserMessageTest, self).setUp()
         self.message = self.create_user_message()
 
-    @test.attr(type=[base.TAG_POSITIVE, base.TAG_API])
+    @decorators.attr(type=[base.TAG_POSITIVE, base.TAG_API])
     def test_list_messages(self):
         body = self.shares_v2_client.list_messages()
         self.assertIsInstance(body, list)
@@ -51,7 +51,7 @@
         message = body[0]
         self.assertEqual(set(MESSAGE_KEYS), set(message.keys()))
 
-    @test.attr(type=[base.TAG_POSITIVE, base.TAG_API])
+    @decorators.attr(type=[base.TAG_POSITIVE, base.TAG_API])
     def test_list_messages_sorted_and_paginated(self):
         self.create_user_message()
         self.create_user_message()
@@ -68,7 +68,7 @@
         self.assertEqual(2, len(ids))
         self.assertEqual(ids, sorted(ids))
 
-    @test.attr(type=[base.TAG_POSITIVE, base.TAG_API])
+    @decorators.attr(type=[base.TAG_POSITIVE, base.TAG_API])
     def test_list_messages_filtered(self):
         self.create_user_message()
         params = {'resource_id': self.message['resource_id']}
@@ -77,7 +77,7 @@
         ids = [x['id'] for x in body]
         self.assertEqual([self.message['id']], ids)
 
-    @test.attr(type=[base.TAG_POSITIVE, base.TAG_API])
+    @decorators.attr(type=[base.TAG_POSITIVE, base.TAG_API])
     def test_show_message(self):
         self.addCleanup(self.shares_v2_client.delete_message,
                         self.message['id'])
@@ -87,7 +87,12 @@
         self.assertEqual(set(MESSAGE_KEYS), set(message.keys()))
         self.assertTrue(uuidutils.is_uuid_like(message['id']))
         self.assertEqual('001', message['action_id'])
-        self.assertEqual('002', message['detail_id'])
+        # don't check specific detail_id which may vary
+        # depending on order of filters, we can still check
+        # user_message
+        self.assertIn(
+            'No storage could be allocated for this share request',
+            message['user_message'])
         self.assertEqual('SHARE', message['resource_type'])
         self.assertTrue(uuidutils.is_uuid_like(message['resource_id']))
         self.assertEqual('ERROR', message['message_level'])
@@ -96,7 +101,7 @@
         self.assertGreater(expires_at, created_at)
         self.assertEqual(set(MESSAGE_KEYS), set(message.keys()))
 
-    @test.attr(type=[base.TAG_POSITIVE, base.TAG_API])
+    @decorators.attr(type=[base.TAG_POSITIVE, base.TAG_API])
     def test_delete_message(self):
         self.shares_v2_client.delete_message(self.message['id'])
         self.shares_v2_client.wait_for_resource_deletion(
diff --git a/manila_tempest_tests/tests/api/admin/test_user_messages_negative.py b/manila_tempest_tests/tests/api/admin/test_user_messages_negative.py
index 47eed3b..ccca166 100644
--- a/manila_tempest_tests/tests/api/admin/test_user_messages_negative.py
+++ b/manila_tempest_tests/tests/api/admin/test_user_messages_negative.py
@@ -12,8 +12,8 @@
 from oslo_utils import uuidutils
 import six
 from tempest import config
+from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 from manila_tempest_tests.tests.api import base
 
@@ -29,7 +29,7 @@
         super(UserMessageNegativeTest, self).setUp()
         self.message = self.create_user_message()
 
-    @test.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
+    @decorators.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
     def test_show_message_of_other_tenants(self):
         isolated_client = self.get_client_with_isolated_creds(
             type_of_creds='alt', client_version='2')
@@ -37,13 +37,13 @@
                           isolated_client.get_message,
                           self.message['id'])
 
-    @test.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
+    @decorators.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
     def test_show_nonexistent_message(self):
         self.assertRaises(lib_exc.NotFound,
                           self.shares_v2_client.get_message,
                           six.text_type(uuidutils.generate_uuid()))
 
-    @test.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
+    @decorators.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
     def test_delete_message_of_other_tenants(self):
         isolated_client = self.get_client_with_isolated_creds(
             type_of_creds='alt', client_version='2')
@@ -51,7 +51,7 @@
                           isolated_client.delete_message,
                           self.message['id'])
 
-    @test.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
+    @decorators.attr(type=[base.TAG_NEGATIVE, base.TAG_API])
     def test_delete_nonexistent_message(self):
         self.assertRaises(lib_exc.NotFound,
                           self.shares_v2_client.delete_message,
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index 764a852..65f1b30 100644
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -23,8 +23,9 @@
 import six
 from tempest import clients
 from tempest.common import credentials_factory as common_creds
-from tempest.common import dynamic_creds
+
 from tempest import config
+from tempest.lib.common import dynamic_creds
 from tempest.lib.common.utils import data_utils
 from tempest.lib import exceptions
 from tempest import test
@@ -151,8 +152,16 @@
 
     @classmethod
     def _get_dynamic_creds(cls, name, network_resources=None):
+        identity_version = CONF.identity.auth_version
+        if identity_version == 'v3':
+            identity_uri = CONF.identity.uri_v3
+            identity_admin_endpoint_type = CONF.identity.v3_endpoint_type
+        elif identity_version == 'v2':
+            identity_uri = CONF.identity.uri
+            identity_admin_endpoint_type = CONF.identity.v2_admin_endpoint_type
+
         return dynamic_creds.DynamicCredentialProvider(
-            identity_version=CONF.identity.auth_version,
+            identity_version=identity_version,
             name=name,
             network_resources=network_resources,
             credentials_domain=CONF.auth.default_credentials_domain_name,
@@ -167,7 +176,9 @@
             project_network_cidr=CONF.network.project_network_cidr,
             project_network_mask_bits=CONF.network.project_network_mask_bits,
             public_network_id=CONF.network.public_network_id,
-            resource_prefix=CONF.resources_prefix)
+            resource_prefix=CONF.resources_prefix,
+            identity_admin_endpoint_type=identity_admin_endpoint_type,
+            identity_uri=identity_uri)
 
     @classmethod
     def get_client_with_isolated_creds(cls,
diff --git a/manila_tempest_tests/tests/api/test_rules.py b/manila_tempest_tests/tests/api/test_rules.py
index 0f16c51..229263e 100644
--- a/manila_tempest_tests/tests/api/test_rules.py
+++ b/manila_tempest_tests/tests/api/test_rules.py
@@ -13,9 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import itertools
 
 import ddt
+import itertools
 from tempest import config
 from tempest.lib import exceptions as lib_exc
 import testtools
@@ -92,11 +92,15 @@
         cls.access_to = "2.2.2.2"
 
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
-    @ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
-    def test_create_delete_access_rules_with_one_ip(self, version):
-
-        # test data
-        access_to = "1.1.1.1"
+    @ddt.data(*itertools.chain(
+        itertools.product({'1.0', '2.9', '2.37', LATEST_MICROVERSION},
+                          {utils.rand_ip()}),
+        itertools.product({'2.37', LATEST_MICROVERSION},
+                          {utils.rand_ipv6_ip()})
+    ))
+    @ddt.unpack
+    def test_create_delete_access_rules_with_one_ip(self, version,
+                                                    access_to):
 
         # create rule
         if utils.is_microversion_eq(version, '1.0'):
@@ -140,11 +144,14 @@
                 rule_id=rule["id"], share_id=self.share['id'], version=version)
 
     @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
-    @ddt.data(*set(['1.0', '2.9', '2.27', '2.28', LATEST_MICROVERSION]))
-    def test_create_delete_access_rule_with_cidr(self, version):
-
-        # test data
-        access_to = "1.2.3.4/32"
+    @ddt.data(*itertools.chain(
+        itertools.product({'1.0', '2.9', '2.37', LATEST_MICROVERSION},
+                          {utils.rand_ip(network=True)}),
+        itertools.product({'2.37', LATEST_MICROVERSION},
+                          {utils.rand_ipv6_ip(network=True)})
+    ))
+    @ddt.unpack
+    def test_create_delete_access_rule_with_cidr(self, version, access_to):
 
         # create rule
         if utils.is_microversion_eq(version, '1.0'):
diff --git a/manila_tempest_tests/tests/api/test_rules_negative.py b/manila_tempest_tests/tests/api/test_rules_negative.py
index 2bc09ee..22f232f 100644
--- a/manila_tempest_tests/tests/api/test_rules_negative.py
+++ b/manila_tempest_tests/tests/api/test_rules_negative.py
@@ -46,60 +46,23 @@
             cls.snap = cls.create_snapshot_wait_for_active(cls.share["id"])
 
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    @ddt.data('shares_client', 'shares_v2_client')
-    def test_create_access_rule_ip_with_wrong_target_1(self, client_name):
-        self.assertRaises(lib_exc.BadRequest,
-                          getattr(self, client_name).create_access_rule,
-                          self.share["id"], "ip", "1.2.3.256")
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    @ddt.data('shares_client', 'shares_v2_client')
-    def test_create_access_rule_ip_with_wrong_target_2(self, client_name):
-        self.assertRaises(lib_exc.BadRequest,
-                          getattr(self, client_name).create_access_rule,
-                          self.share["id"], "ip", "1.1.1.-")
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    @ddt.data('shares_client', 'shares_v2_client')
-    def test_create_access_rule_ip_with_wrong_target_3(self, client_name):
-        self.assertRaises(lib_exc.BadRequest,
-                          getattr(self, client_name).create_access_rule,
-                          self.share["id"], "ip", "1.2.3.4/33")
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    @ddt.data('shares_client', 'shares_v2_client')
-    def test_create_access_rule_ip_with_wrong_target_4(self, client_name):
-        self.assertRaises(lib_exc.BadRequest,
-                          getattr(self, client_name).create_access_rule,
-                          self.share["id"], "ip", "1.2.3.*")
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    @ddt.data('shares_client', 'shares_v2_client')
-    def test_create_access_rule_ip_with_wrong_target_5(self, client_name):
-        self.assertRaises(lib_exc.BadRequest,
-                          getattr(self, client_name).create_access_rule,
-                          self.share["id"], "ip", "1.2.3.*/23")
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    @ddt.data('shares_client', 'shares_v2_client')
-    def test_create_access_rule_ip_with_wrong_target_6(self, client_name):
-        self.assertRaises(lib_exc.BadRequest,
-                          getattr(self, client_name).create_access_rule,
-                          self.share["id"], "ip", "1.2.3.1|23")
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    @ddt.data('shares_client', 'shares_v2_client')
-    def test_create_access_rule_ip_with_wrong_target_7(self, client_name):
-        self.assertRaises(lib_exc.BadRequest,
-                          getattr(self, client_name).create_access_rule,
-                          self.share["id"], "ip", "1.2.3.1/-1")
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    @ddt.data('shares_client', 'shares_v2_client')
-    def test_create_access_rule_ip_with_wrong_target_8(self, client_name):
-        self.assertRaises(lib_exc.BadRequest,
-                          getattr(self, client_name).create_access_rule,
-                          self.share["id"], "ip", "1.2.3.1/")
+    @ddt.data('1.2.3.256',
+              '1.1.1.-',
+              '1.2.3.4/33',
+              '1.2.3.*',
+              '1.2.3.*/23',
+              '1.2.3.1|23',
+              '1.2.3.1/-1',
+              '1.2.3.1/',
+              'ad80::abaa:0:c2:2/-3',
+              'AD80:ABAA::|26',
+              '2001:DB8:2de:0:0:0:0:e13:200a',
+              )
+    def test_create_access_rule_ip_with_wrong_target(self, ip_address):
+        for client_name in ['shares_client', 'shares_v2_client']:
+            self.assertRaises(lib_exc.BadRequest,
+                              getattr(self, client_name).create_access_rule,
+                              self.share["id"], "ip", ip_address)
 
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     @ddt.data('shares_client', 'shares_v2_client')
diff --git a/manila_tempest_tests/tests/api/test_snapshot_rules_negative.py b/manila_tempest_tests/tests/api/test_snapshot_rules_negative.py
index 9f48b73..b1818e5 100644
--- a/manila_tempest_tests/tests/api/test_snapshot_rules_negative.py
+++ b/manila_tempest_tests/tests/api/test_snapshot_rules_negative.py
@@ -48,10 +48,10 @@
 
     @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
     @ddt.data("1.2.3.256", "1.1.1.-", "1.2.3.4/33", "1.2.3.*", "1.2.3.*/23",
-              "1.2.3.1|23", "1.2.3.1/",  "1.2.3.1/-1", "fe00::1",
-              "fe80::217:f2ff:fe07:ed62", "2001:db8::/48", "::1/128",
-              "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
-              "2001:0db8:0000:85a3:0000:0000:ac1f:8001")
+              "1.2.3.1|23", "1.2.3.1/",  "1.2.3.1/-1",
+              "fe80:217:f2ff:fe07:ed62", "2001:db8::1/148",
+              "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+              "2001:0db8:0000:85a3:0000:0000:ac1f:8001/64")
     def test_create_access_rule_ip_with_wrong_target(self, target):
         self.assertRaises(lib_exc.BadRequest,
                           self.shares_v2_client.create_snapshot_access_rule,
diff --git a/manila_tempest_tests/utils.py b/manila_tempest_tests/utils.py
index 5c93443..80eebea 100644
--- a/manila_tempest_tests/utils.py
+++ b/manila_tempest_tests/utils.py
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from netaddr import ip
 import random
 import re
 
@@ -90,16 +91,33 @@
     return lambda f: f
 
 
-def rand_ip():
+def rand_ip(network=False):
     """This uses the TEST-NET-3 range of reserved IP addresses.
 
     Using this range, which are reserved solely for use in
     documentation and example source code, should avoid any potential
     conflicts in real-world testing.
     """
-    TEST_NET_3 = '203.0.113.'
-    final_octet = six.text_type(random.randint(0, 255))
-    return TEST_NET_3 + final_octet
+    test_net_3 = '203.0.113.'
+    address = test_net_3 + six.text_type(random.randint(0, 255))
+    if network:
+        mask_length = six.text_type(random.randint(24, 32))
+        address = '/'.join((address, mask_length))
+        ip_network = ip.IPNetwork(address)
+        return '/'.join((six.text_type(ip_network.network), mask_length))
+    return address
+
+
+def rand_ipv6_ip(network=False):
+    """This uses the IPv6 documentation range of 2001:DB8::/32"""
+    ran_add = ["%x" % random.randrange(0, 16**4) for i in range(6)]
+    address = "2001:0DB8:" + ":".join(ran_add)
+    if network:
+        mask_length = six.text_type(random.randint(32, 128))
+        address = '/'.join((address, mask_length))
+        ip_network = ip.IPNetwork(address)
+        return '/'.join((six.text_type(ip_network.network), mask_length))
+    return address
 
 
 def choose_matching_backend(share, pools, share_type):