Add S-RBAC tests for manila

The tests validate policy share actions for admin,member
and reader users in a project scope.
This patch adds tests for the following resources/features:
- share
- share snapshot
- share type
- share network
- scheduler stats

Below settings were used for ease of code development
and testing:
1. DHHS = False
2. Dummy driver as it supports all features
3. Manila-tempest-plugin as a base repo to test the changes

Depends-On: https://review.opendev.org/c/openstack/manila/+/858761
Change-Id: I53bb9851445038f81032485817389ec31e2b7341
diff --git a/manila_tempest_tests/tests/rbac/__init__.py b/manila_tempest_tests/tests/rbac/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/manila_tempest_tests/tests/rbac/__init__.py
diff --git a/manila_tempest_tests/tests/rbac/base.py b/manila_tempest_tests/tests/rbac/base.py
new file mode 100644
index 0000000..db53795
--- /dev/null
+++ b/manila_tempest_tests/tests/rbac/base.py
@@ -0,0 +1,163 @@
+# Copyright 2022 Red Hat, 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.
+
+
+from tempest import clients
+from tempest import config
+from tempest.lib import auth
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+
+from manila_tempest_tests.common import waiters
+
+CONF = config.CONF
+
+
+class ShareRbacBaseTests(object):
+
+    identity_version = 'v3'
+    protocols = ['nfs', 'cifs', 'glusterfs', 'hdfs', 'cephfs', 'maprfs']
+
+    @classmethod
+    def skip_checks(cls):
+        super(ShareRbacBaseTests, cls).skip_checks()
+        if not CONF.enforce_scope.manila:
+            raise cls.skipException(
+                "Tempest is not configured to enforce_scope for manila, "
+                "skipping RBAC tests. To enable these tests set "
+                "`tempest.conf [enforce_scope] manila=True`."
+            )
+        if not CONF.share.default_share_type_name:
+            raise cls.skipException("Secure rbac tests require a default "
+                                    "share type")
+        if not any(p in CONF.share.enable_protocols for p in cls.protocols):
+            message = "%s tests are disabled" % cls.protocol
+            raise cls.skipException(message)
+
+    @classmethod
+    def delete_resource(cls, client, **kwargs):
+        key_names = {
+            'st': 'share_type',
+            'sn': 'share_network',
+        }
+        key, resource_id = list(kwargs.items())[0]
+        key = key.split('_')[0]
+        resource_name = key_names[key] if key in key_names else key
+
+        del_action = getattr(client, 'delete_{}'.format(resource_name))
+        test_utils.call_and_ignore_notfound_exc(
+            del_action, resource_id)
+        test_utils.call_and_ignore_notfound_exc(
+            client.wait_for_resource_deletion, **kwargs)
+
+    @classmethod
+    def create_share(cls, client, share_type_id, size=None, name=None,
+                     metadata=None):
+        kwargs = {}
+        name = name or data_utils.rand_name('share')
+        metadata = metadata or {}
+        kwargs.update({
+            'share_protocol': cls.protocol,
+            'size': size or CONF.share.share_size,
+            'name': name or data_utils.rand_name('share'),
+            'share_type_id': share_type_id,
+            'metadata': metadata,
+        })
+        share = client.create_share(**kwargs)['share']
+        waiters.wait_for_resource_status(client, share['id'], 'available')
+        cls.addClassResourceCleanup(
+            cls.delete_resource, client,
+            share_id=share['id'])
+        return share
+
+    @classmethod
+    def create_snapshot(cls, client, share_id, name=None):
+        name = name or data_utils.rand_name('snapshot')
+        snapshot = client.create_snapshot(share_id, name=name)['snapshot']
+        waiters.wait_for_resource_status(
+            client, snapshot['id'], 'available', resource_name='snapshot')
+        cls.addClassResourceCleanup(
+            cls.delete_resource, client, snapshot_id=snapshot['id'])
+        return snapshot
+
+    @classmethod
+    def create_share_network(cls, client, name=None):
+        name = name or data_utils.rand_name('share_network')
+        share_network = client.create_share_network(name=name)['share_network']
+
+        cls.addClassResourceCleanup(
+            cls.delete_resource, client, sn_id=share_network['id'])
+        return share_network
+
+    @classmethod
+    def get_share_type(cls):
+        return cls.shares_v2_client.get_default_share_type()['share_type']
+
+    def do_request(self, method, expected_status=200, client=None, **payload):
+        if not client:
+            client = self.client
+        if isinstance(expected_status, type(Exception)):
+            self.assertRaises(expected_status,
+                              getattr(client, method),
+                              **payload)
+        else:
+            response = getattr(client, method)(**payload)
+            self.assertEqual(response.response.status, expected_status)
+            return response
+
+    @classmethod
+    def setup_user_client(cls, client, project_id=None):
+        """Set up project user with its own client.
+
+        This is useful for testing protection of resources in separate
+        projects.
+        NOTE(lkuchlan): Tempest creates 'project_member' and 'project_reader'
+        dynamic credentials in different projects. So this method is also
+        necessary for testing protection of resources in a specific project.
+
+        Returns a client object and the user's ID.
+        """
+
+        projects_client = client.identity_v3.ProjectsClient()
+        users_client = client.identity_v3.UsersClient()
+        roles_client = client.identity_v3.RolesClient()
+
+        user_dict = {
+            'name': data_utils.rand_name('user'),
+            'password': data_utils.rand_password(),
+        }
+        user_id = users_client.create_user(
+            **user_dict)['user']['id']
+        cls.addClassResourceCleanup(users_client.delete_user, user_id)
+
+        if not project_id:
+            project_id = projects_client.create_project(
+                data_utils.rand_name())['project']['id']
+            cls.addClassResourceCleanup(
+                projects_client.delete_project,
+                project_id)
+
+        member_role_id = roles_client.list_roles(
+            name='member')['roles'][0]['id']
+        roles_client.create_user_role_on_project(
+            project_id, user_id, member_role_id)
+        creds = auth.KeystoneV3Credentials(
+            user_id=user_id,
+            password=user_dict['password'],
+            project_id=project_id)
+        auth_provider = clients.get_auth_provider(creds)
+        creds = auth_provider.fill_credentials()
+        client = clients.Manager(credentials=creds)
+        return client
diff --git a/manila_tempest_tests/tests/rbac/test_scheduler_stats.py b/manila_tempest_tests/tests/rbac/test_scheduler_stats.py
new file mode 100644
index 0000000..c1194b0
--- /dev/null
+++ b/manila_tempest_tests/tests/rbac/test_scheduler_stats.py
@@ -0,0 +1,73 @@
+# Copyright 2022 Red Hat, 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 abc
+
+from tempest import config
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from testtools import testcase as tc
+
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests.tests.rbac import base as rbac_base
+
+CONF = config.CONF
+
+
+class ShareRbacSchedulerStatsTests(rbac_base.ShareRbacBaseTests,
+                                   metaclass=abc.ABCMeta):
+
+    @classmethod
+    def setup_clients(cls):
+        super(ShareRbacSchedulerStatsTests, cls).setup_clients()
+        cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+        cls.client = cls.persona.share_v2.SharesV2Client()
+
+    @abc.abstractmethod
+    def test_list_storage_pools(self):
+        pass
+
+
+class ProjectAdminTests(ShareRbacSchedulerStatsTests, base.BaseSharesTest):
+
+    credentials = ['project_admin']
+
+    @decorators.idempotent_id('1ec4d0f5-0d60-4bbc-88a4-57fa92f6f62f')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_list_storage_pools(self):
+        self.do_request(
+            'list_pools', expected_status=200)
+
+
+class ProjectMemberTests(ShareRbacSchedulerStatsTests, base.BaseSharesTest):
+
+    credentials = ['project_member']
+
+    @decorators.idempotent_id('905aa5ea-eff9-4022-be41-df7a8593809d')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_list_storage_pools(self):
+        self.do_request(
+            'list_pools', expected_status=lib_exc.Forbidden)
+
+
+class ProjectReaderTests(ShareRbacSchedulerStatsTests, base.BaseSharesTest):
+
+    credentials = ['project_reader']
+
+    @decorators.idempotent_id('faab12f9-ff51-458d-af47-362d872761e9')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_list_storage_pools(self):
+        self.do_request(
+            'list_pools', expected_status=lib_exc.Forbidden)
diff --git a/manila_tempest_tests/tests/rbac/test_share_network.py b/manila_tempest_tests/tests/rbac/test_share_network.py
new file mode 100644
index 0000000..c1ca6a2
--- /dev/null
+++ b/manila_tempest_tests/tests/rbac/test_share_network.py
@@ -0,0 +1,291 @@
+# Copyright 2022 Red Hat, 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 abc
+
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from testtools import testcase as tc
+
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests.tests.rbac import base as rbac_base
+
+CONF = config.CONF
+
+
+class ShareRbacShareNetworkTests(rbac_base.ShareRbacBaseTests,
+                                 metaclass=abc.ABCMeta):
+
+    @classmethod
+    def setup_clients(cls):
+        super(ShareRbacShareNetworkTests, cls).setup_clients()
+        cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+        cls.client = cls.persona.share_v2.SharesV2Client()
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareRbacShareNetworkTests, cls).resource_setup()
+        cls.share_type = cls.get_share_type()
+
+    @abc.abstractmethod
+    def test_create_share_network(self):
+        pass
+
+    @abc.abstractmethod
+    def test_list_share_network(self):
+        pass
+
+    @abc.abstractmethod
+    def test_show_share_network(self):
+        pass
+
+    @abc.abstractmethod
+    def test_delete_share_network(self):
+        pass
+
+    @abc.abstractmethod
+    def test_update_share_network(self):
+        pass
+
+
+class ProjectAdminTests(ShareRbacShareNetworkTests, base.BaseSharesTest):
+
+    credentials = ['project_admin', 'project_alt_member']
+
+    @classmethod
+    def setup_clients(cls):
+        super(ProjectAdminTests, cls).setup_clients()
+        project_member = cls.setup_user_client(
+            cls.persona, project_id=cls.persona.credentials.project_id)
+        cls.share_member_client = project_member.share_v2.SharesV2Client()
+        cls.alt_project_share_v2_client = (
+            cls.os_project_alt_member.share_v2.SharesV2Client())
+
+    @decorators.idempotent_id('358dd850-cd81-4b81-aefa-3dfcb7aa4551')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_create_share_network(self):
+        share_network = self.do_request(
+            'create_share_network', expected_status=200)['share_network']
+        self.addCleanup(
+            self.delete_resource, self.client, sn_id=share_network['id'])
+
+    @decorators.idempotent_id('deb20301-9d7c-4c08-b1f0-fc2c403ea708')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_list_share_network(self):
+        share_network = self.create_share_network(self.share_member_client)
+        alt_share_network = self.create_share_network(
+            self.alt_project_share_v2_client)
+        params = {"all_tenants": 1}
+        share_network_list = self.do_request(
+            'list_share_networks', expected_status=200,
+            params=params)['share_networks']
+        share_network_id_list = [
+            s['id'] for s in share_network_list
+        ]
+
+        self.assertIn(share_network['id'], share_network_id_list)
+        self.assertIn(alt_share_network['id'], share_network_id_list)
+
+    @decorators.idempotent_id('43a3be84-d08b-4f17-89cf-02abda6df580')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_show_share_network(self):
+        share_network = self.create_share_network(self.share_member_client)
+        self.do_request(
+            'get_share_network', expected_status=200,
+            share_network_id=share_network['id'])
+
+        alt_share_network = self.create_share_network(
+            self.alt_project_share_v2_client)
+        self.do_request(
+            'get_share_network', expected_status=200,
+            share_network_id=alt_share_network['id'])
+
+    @decorators.idempotent_id('6c403ed6-b810-4794-8e9b-d57f173443a2')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_delete_share_network(self):
+        share_network = self.create_share_network(self.share_member_client)
+        self.do_request(
+            'delete_share_network', expected_status=202,
+            sn_id=share_network['id'])
+
+        alt_share_network = self.create_share_network(
+            self.alt_project_share_v2_client)
+        self.do_request(
+            'delete_share_network', expected_status=202,
+            sn_id=alt_share_network['id'])
+
+    @decorators.idempotent_id('abd2443d-3490-462a-8e51-73b6a8f48795')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_update_share_network(self):
+        share_network = self.create_share_network(self.share_member_client)
+        name = data_utils.rand_name("updated_share_network")
+        self.do_request(
+            'update_share_network', expected_status=200,
+            sn_id=share_network['id'], name=name)
+
+        alt_share_network = self.create_share_network(
+            self.alt_project_share_v2_client)
+        self.do_request(
+            'update_share_network', expected_status=200,
+            sn_id=alt_share_network['id'], name=name)
+
+
+class ProjectMemberTests(ShareRbacShareNetworkTests, base.BaseSharesTest):
+
+    credentials = ['project_member', 'project_alt_member']
+
+    @classmethod
+    def setup_clients(cls):
+        super(ProjectMemberTests, cls).setup_clients()
+        cls.alt_project_share_v2_client = (
+            cls.os_project_alt_member.share_v2.SharesV2Client())
+
+    @decorators.idempotent_id('d051c749-3d1c-4485-86c5-6eb860b49cad')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_create_share_network(self):
+        share_network = self.do_request(
+            'create_share_network', expected_status=200)['share_network']
+        self.addCleanup(
+            self.delete_resource, self.client, sn_id=share_network['id'])
+
+    @decorators.idempotent_id('ac33cd51-1efe-4aaf-99ab-b510b7551571')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_list_share_network(self):
+        share_client = getattr(self, 'share_member_client', self.client)
+        share_network = self.create_share_network(share_client)
+        alt_share_network = self.create_share_network(
+            self.alt_project_share_v2_client)
+        share_network_list = self.do_request(
+            'list_share_networks', expected_status=200)['share_networks']
+        share_network_id_list = [
+            s['id'] for s in share_network_list
+        ]
+
+        self.assertIn(share_network['id'], share_network_id_list)
+        self.assertNotIn(alt_share_network['id'], share_network_id_list)
+
+    @decorators.idempotent_id('dc3f8f95-f8c5-4030-93dd-e4c56e40b477')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_show_share_network(self):
+        share_client = getattr(self, 'share_member_client', self.client)
+        share_network = self.create_share_network(share_client)
+        self.do_request(
+            'get_share_network', expected_status=200,
+            share_network_id=share_network['id'])
+
+        alt_share_network = self.create_share_network(
+            self.alt_project_share_v2_client)
+        self.do_request(
+            'get_share_network', expected_status=lib_exc.NotFound,
+            share_network_id=alt_share_network['id'])
+
+    @decorators.idempotent_id('717977ab-f077-411a-9bdc-06c8ec9d4f8c')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_delete_share_network(self):
+        share_network = self.create_share_network(self.client)
+        self.do_request(
+            'delete_share_network', expected_status=202,
+            sn_id=share_network['id'])
+
+        alt_share_network = self.create_share_network(
+            self.alt_project_share_v2_client)
+        self.do_request(
+            'delete_share_network', expected_status=lib_exc.NotFound,
+            sn_id=alt_share_network['id'])
+
+    @decorators.idempotent_id('d1fce94c-b163-452d-bf79-13b6edf47e30')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_update_share_network(self):
+        share_network = self.create_share_network(self.client)
+        name = data_utils.rand_name("updated_share_network")
+        self.do_request(
+            'update_share_network', expected_status=200,
+            sn_id=share_network['id'], name=name)
+
+        alt_share_network = self.create_share_network(
+            self.alt_project_share_v2_client)
+        self.do_request(
+            'update_share_network', expected_status=lib_exc.NotFound,
+            sn_id=alt_share_network['id'], name=name)
+
+
+class ProjectReaderTests(ProjectMemberTests):
+    """Test suite for basic share network operations by reader user
+
+    In order to test certain share operations we must create a share network
+    resource for this. Since reader user is limited in resources creation, we
+    are forced to use admin credentials, so we can test other share
+    operations. In this class we use admin user to create a member user within
+    reader project. That way we can perform a reader actions on this resource.
+    """
+
+    credentials = ['project_reader', 'project_admin', 'project_alt_member']
+
+    @classmethod
+    def setup_clients(cls):
+        super(ProjectReaderTests, cls).setup_clients()
+        project_member = cls.setup_user_client(
+            cls.os_project_admin,
+            project_id=cls.persona.credentials.project_id)
+        cls.share_member_client = project_member.share_v2.SharesV2Client()
+        cls.alt_project_share_v2_client = (
+            cls.os_project_alt_member.share_v2.SharesV2Client())
+
+    @decorators.idempotent_id('73dd9f09-7106-4fd5-a484-0eb986002e3b')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_create_share_network(self):
+        self.do_request(
+            'create_share_network', expected_status=lib_exc.Forbidden)
+
+    @decorators.idempotent_id('841e9e69-2a22-4572-9147-b233c8a842bc')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_list_share_network(self):
+        super(ProjectReaderTests, self).test_list_share_network()
+
+    @decorators.idempotent_id('c98893c8-cdc6-42af-a842-1ee9466904ae')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_show_share_network(self):
+        super(ProjectReaderTests, self).test_show_share_network()
+
+    @decorators.idempotent_id('f8f26bce-ff82-4472-a8dd-0f46c1757386')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_delete_share_network(self):
+        share_network = self.create_share_network(self.share_member_client)
+        self.do_request(
+            'delete_share_network', expected_status=lib_exc.Forbidden,
+            sn_id=share_network['id'])
+
+        alt_share_network = self.create_share_network(
+            self.alt_project_share_v2_client)
+        self.do_request(
+            'delete_share_network', expected_status=lib_exc.Forbidden,
+            sn_id=alt_share_network['id'])
+
+    @decorators.idempotent_id('67b745cd-e669-4872-bbb7-9307960fbd77')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_update_share_network(self):
+        share_network = self.create_share_network(self.share_member_client)
+        name = data_utils.rand_name("updated_share_network")
+        self.do_request(
+            'update_share_network', expected_status=lib_exc.Forbidden,
+            sn_id=share_network['id'], name=name)
+
+        alt_share_network = self.create_share_network(
+            self.alt_project_share_v2_client)
+        self.do_request(
+            'update_share_network', expected_status=lib_exc.Forbidden,
+            sn_id=alt_share_network['id'], name=name)
diff --git a/manila_tempest_tests/tests/rbac/test_share_types.py b/manila_tempest_tests/tests/rbac/test_share_types.py
new file mode 100644
index 0000000..bc75597
--- /dev/null
+++ b/manila_tempest_tests/tests/rbac/test_share_types.py
@@ -0,0 +1,190 @@
+# Copyright 2022 Red Hat, 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 abc
+
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from testtools import testcase as tc
+
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests.tests.rbac import base as rbac_base
+
+CONF = config.CONF
+
+
+class ShareRbacShareTypesTests(rbac_base.ShareRbacBaseTests,
+                               metaclass=abc.ABCMeta):
+
+    @classmethod
+    def setup_clients(cls):
+        super(ShareRbacShareTypesTests, cls).setup_clients()
+        cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+        cls.client = cls.persona.share_v2.SharesV2Client()
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareRbacShareTypesTests, cls).resource_setup()
+        cls.share_type = cls.get_share_type()
+
+    def share_type_properties(self):
+        share_type = {}
+        share_type['extra_specs'] = {
+            'driver_handles_share_servers': CONF.share.multitenancy_enabled,
+        }
+        share_type['name'] = data_utils.rand_name("share-type")
+        return share_type
+
+    @abc.abstractmethod
+    def test_create_share_type(self):
+        pass
+
+    @abc.abstractmethod
+    def test_get_share_type(self):
+        pass
+
+    @abc.abstractmethod
+    def test_list_share_type(self):
+        pass
+
+    @abc.abstractmethod
+    def test_update_share_type(self):
+        pass
+
+
+class ProjectAdminTests(ShareRbacShareTypesTests, base.BaseSharesTest):
+
+    credentials = ['project_admin']
+
+    @classmethod
+    def setup_clients(cls):
+        super(ProjectAdminTests, cls).setup_clients()
+        project_member = cls.setup_user_client(
+            cls.persona, project_id=cls.persona.credentials.project_id)
+        cls.share_member_client = project_member.share_v2.SharesV2Client()
+
+    @decorators.idempotent_id('b24bf137-352a-4ebd-b736-27518d32c1bd')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_create_share_type(self):
+        share_type = self.do_request(
+            'create_share_type', expected_status=200,
+            **self.share_type_properties())['share_type']
+        self.addCleanup(self.delete_resource, self.client,
+                        st_id=share_type['id'])
+
+    @decorators.idempotent_id('741d69f3-b3fe-49cf-9e33-6b0696b353ec')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_get_share_type(self):
+        self.do_request(
+            'get_share_type', expected_status=200,
+            share_type_id=self.share_type['id'])
+
+    @decorators.idempotent_id('3f811ac6-a345-424f-863a-1a7a49ba0a32')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_list_share_type(self):
+        share_type_list = self.do_request(
+            'list_share_types', expected_status=200)['share_types']
+        share_type_id_list = [
+            st['id'] for st in share_type_list
+        ]
+        self.assertIn(self.share_type['id'], share_type_id_list)
+
+    @decorators.idempotent_id('3bb9aaab-3c17-45be-a9b1-dd8b6942cb59')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_update_share_type(self):
+        share_type = self.client.create_share_type(
+            **self.share_type_properties())['share_type']
+        self.addCleanup(self.client.delete_share_type, share_type['id'])
+
+        name = data_utils.rand_name("updated_share_type")
+        self.do_request(
+            'update_share_type', expected_status=200,
+            share_type_id=share_type['id'], name=name)
+
+
+class ProjectMemberTests(ShareRbacShareTypesTests, base.BaseSharesTest):
+
+    credentials = ['project_member']
+
+    @decorators.idempotent_id('270761cf-07b4-4fc7-96b5-4deb205adce3')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_create_share_type(self):
+        self.do_request(
+            'create_share_type', expected_status=lib_exc.Forbidden,
+            **self.share_type_properties())
+
+    @decorators.idempotent_id('d3f53218-d92f-489d-8e2e-985178e7fd02')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_get_share_type(self):
+        self.do_request(
+            'get_share_type', expected_status=200,
+            share_type_id=self.share_type['id'])
+
+    @decorators.idempotent_id('757c7ccd-e14e-4c1a-9172-998ae5eed1b8')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_list_share_type(self):
+        share_type_list = self.do_request(
+            'list_share_types', expected_status=200)['share_types']
+        share_type_id_list = [
+            st['id'] for st in share_type_list
+        ]
+        self.assertIn(self.share_type['id'], share_type_id_list)
+
+    @decorators.idempotent_id('5210170c-b749-4645-a86f-7347c3ba3e99')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_update_share_type(self):
+        name = data_utils.rand_name("updated_share_type")
+        self.do_request(
+            'update_share_type', expected_status=lib_exc.Forbidden,
+            share_type_id=self.share_type['id'], name=name)
+
+
+class ProjectReaderTests(ShareRbacShareTypesTests, base.BaseSharesTest):
+
+    credentials = ['project_reader', 'project_member']
+
+    @decorators.idempotent_id('f4c352c4-c12b-4722-9fe7-9a2ec639ee63')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_create_share_type(self):
+        self.do_request(
+            'create_share_type', expected_status=lib_exc.Forbidden,
+            **self.share_type_properties())
+
+    @decorators.idempotent_id('e9d9f244-7778-443b-aadc-bac9f2b687b7')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_get_share_type(self):
+        self.do_request(
+            'get_share_type', expected_status=200,
+            share_type_id=self.share_type['id'])
+
+    @decorators.idempotent_id('cf0e97f1-4853-4cf2-9e9a-041c6e57bab5')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_list_share_type(self):
+        share_type_list = self.do_request(
+            'list_share_types', expected_status=200)['share_types']
+        share_type_id_list = [
+            st['id'] for st in share_type_list
+        ]
+        self.assertIn(self.share_type['id'], share_type_id_list)
+
+    @decorators.idempotent_id('338d579b-ff91-4a30-af53-d0b317919efb')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_update_share_type(self):
+        name = data_utils.rand_name("updated_share_type")
+        self.do_request(
+            'update_share_type', expected_status=lib_exc.Forbidden,
+            share_type_id=self.share_type['id'], name=name)
diff --git a/manila_tempest_tests/tests/rbac/test_shares.py b/manila_tempest_tests/tests/rbac/test_shares.py
new file mode 100644
index 0000000..f6f5297
--- /dev/null
+++ b/manila_tempest_tests/tests/rbac/test_shares.py
@@ -0,0 +1,686 @@
+# Copyright 2022 Red Hat, 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 abc
+
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import waiters
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests.tests.rbac import base as rbac_base
+
+CONF = config.CONF
+
+
+class ShareRbacSharesTests(rbac_base.ShareRbacBaseTests,
+                           metaclass=abc.ABCMeta):
+
+    @classmethod
+    def skip_checks(cls):
+        super(ShareRbacSharesTests, cls).skip_checks()
+        if cls.protocol not in CONF.share.enable_protocols:
+            message = "%s tests are disabled" % cls.protocol
+            raise cls.skipException(message)
+
+    @classmethod
+    def setup_clients(cls):
+        super(ShareRbacSharesTests, cls).setup_clients()
+        cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+        cls.client = cls.persona.share_v2.SharesV2Client()
+        cls.alt_project_share_v2_client = (
+            cls.os_project_alt_member.share_v2.SharesV2Client())
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareRbacSharesTests, cls).resource_setup()
+        cls.share_type = cls.get_share_type()
+
+    def share(self, share_type_id, size=None):
+        share = {}
+        share['name'] = data_utils.rand_name('share')
+        share['size'] = size or CONF.share.share_size
+        share['share_type_id'] = share_type_id
+        share['share_protocol'] = self.protocol
+        return share
+
+    @abc.abstractmethod
+    def test_get_share(self):
+        pass
+
+    @abc.abstractmethod
+    def test_list_share(self):
+        pass
+
+    @abc.abstractmethod
+    def test_create_share(self):
+        pass
+
+    @abc.abstractmethod
+    def test_delete_share(self):
+        pass
+
+    @abc.abstractmethod
+    def test_force_delete_share(self):
+        pass
+
+    @abc.abstractmethod
+    def test_update_share(self):
+        pass
+
+    @abc.abstractmethod
+    def test_reset_share(self):
+        pass
+
+    @abc.abstractmethod
+    def test_shrink_share(self):
+        pass
+
+    @abc.abstractmethod
+    def test_extend_share(self):
+        pass
+
+    @abc.abstractmethod
+    def test_set_share_metadata(self):
+        pass
+
+    @abc.abstractmethod
+    def test_get_share_metadata(self):
+        pass
+
+    @abc.abstractmethod
+    def test_delete_share_metadata(self):
+        pass
+
+
+class TestProjectAdminTestsNFS(ShareRbacSharesTests, base.BaseSharesTest):
+
+    credentials = ['project_admin', 'project_alt_member']
+    protocol = 'nfs'
+
+    @classmethod
+    def setup_clients(cls):
+        super(TestProjectAdminTestsNFS, cls).setup_clients()
+        project_member = cls.setup_user_client(
+            cls.persona, project_id=cls.persona.credentials.project_id)
+        cls.share_member_client = project_member.share_v2.SharesV2Client()
+        cls.alt_project_share_v2_client = (
+            cls.os_project_alt_member.share_v2.SharesV2Client())
+
+    @decorators.idempotent_id('14a52454-cba0-4973-926a-28e924ae2e63')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_share(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'])
+        self.do_request(
+            'get_share', expected_status=200, share_id=share['id'])
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'get_share', expected_status=200,
+            share_id=alt_share['id'])
+
+    @decorators.idempotent_id('5f8c06e6-5b80-45f8-aefb-1b55617d1bd1')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_list_share(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'])
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+
+        params = {"all_tenants": 1}
+        share_list = self.do_request(
+            'list_shares', expected_status=200, params=params)['shares']
+        share_id_list = [
+            s['id'] for s in share_list
+        ]
+
+        self.assertIn(share['id'], share_id_list)
+        self.assertIn(alt_share['id'], share_id_list)
+
+    @decorators.idempotent_id('34b84af3-a9ea-4c19-8414-e4e44648099c')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_share(self):
+        share = self.do_request(
+            'create_share', expected_status=200,
+            **self.share(self.share_type['id']))['share']
+        waiters.wait_for_resource_status(self.client,
+                                         share['id'], 'available')
+        self.addCleanup(self.delete_resource, self.client,
+                        share_id=share['id'])
+
+    @decorators.idempotent_id('44f2eae6-44d4-4962-a94a-d2717b74728f')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_share(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'])
+        self.do_request(
+            'delete_share', expected_status=202, share_id=share['id'])
+        self.client.wait_for_resource_deletion(share_id=share['id'])
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'delete_share', expected_status=202,
+            share_id=alt_share['id'])
+        self.client.wait_for_resource_deletion(share_id=alt_share['id'])
+
+    @decorators.idempotent_id('2e915a27-488d-4e33-b2f8-37758ef11653')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_force_delete_share(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'])
+        self.do_request(
+            'force_delete', expected_status=202, s_id=share['id'])
+        self.client.wait_for_resource_deletion(share_id=share['id'])
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'force_delete', expected_status=202,
+            s_id=alt_share['id'])
+        self.client.wait_for_resource_deletion(share_id=alt_share['id'])
+
+    @decorators.idempotent_id('5c2bda4c-0179-4af9-b18c-430a7d31f962')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_update_share(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'])
+        name = data_utils.rand_name("updated_share")
+        self.do_request(
+            'update_share', expected_status=200,
+            share_id=share['id'], name=name)
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        name = data_utils.rand_name("updated_share")
+        self.do_request(
+            'update_share', expected_status=200,
+            share_id=alt_share['id'], name=name)
+
+    @decorators.idempotent_id('44fb7049-8fc0-4584-9ff1-7527395d2ec5')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_reset_share(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'])
+        self.do_request(
+            'reset_state', expected_status=202, s_id=share['id'],
+            status="error")
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'reset_state', expected_status=202,
+            s_id=alt_share['id'], status="error")
+
+    @decorators.idempotent_id('cc49ae58-6696-4030-a029-a66bae2efa96')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_shrink_share(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'],
+            size=CONF.share.share_size + 1)
+        self.do_request(
+            'shrink_share', expected_status=202, share_id=share['id'],
+            new_size=CONF.share.share_size)
+        waiters.wait_for_resource_status(self.client, share['id'], 'available')
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'],
+            size=CONF.share.share_size + 1)
+        self.do_request(
+            'shrink_share', expected_status=202,
+            share_id=alt_share['id'], new_size=CONF.share.share_size)
+        waiters.wait_for_resource_status(
+            self.alt_project_share_v2_client, alt_share['id'], 'available')
+
+    @decorators.idempotent_id('2cfa04e5-16cc-43e4-b892-c1a11b0a2f2d')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_extend_share(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'])
+        self.do_request(
+            'extend_share', expected_status=202, share_id=share['id'],
+            new_size=CONF.share.share_size + 1)
+        waiters.wait_for_resource_status(self.client, share['id'], 'available')
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'extend_share', expected_status=202,
+            share_id=alt_share['id'], new_size=CONF.share.share_size + 1)
+        waiters.wait_for_resource_status(
+            self.alt_project_share_v2_client, alt_share['id'], 'available')
+
+    @decorators.idempotent_id('d6014579-d772-441a-a9b1-01b1e87caeaa')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_share_metadata(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'])
+        self.do_request(
+            'set_metadata', expected_status=200, share_id=share['id'],
+            metadata={'key': 'value'})
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'set_metadata', expected_status=200,
+            share_id=alt_share['id'], metadata={'key': 'value'})
+
+    @decorators.idempotent_id('2d91e97e-d0e5-4112-8b22-60cd4659586c')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_share_metadata(self):
+        metadata = {'key': 'value'}
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'],
+            metadata=metadata)
+        self.do_request(
+            'get_metadata', expected_status=200, share_id=share['id'])
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'],
+            metadata=metadata)
+        self.do_request(
+            'get_metadata', expected_status=200,
+            share_id=alt_share['id'])
+
+    @decorators.idempotent_id('4cd807d6-bac4-4d0f-a207-c84dfe77f032')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_share_metadata(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'],
+            metadata={'key': 'value'})
+        self.do_request(
+            'delete_metadata', expected_status=200, share_id=share['id'],
+            key='key')
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'],
+            metadata={'key': 'value'})
+        self.do_request(
+            'delete_metadata', expected_status=200,
+            share_id=alt_share['id'], key='key')
+
+
+class TestProjectMemberTestsNFS(ShareRbacSharesTests, base.BaseSharesTest):
+
+    credentials = ['project_member', 'project_alt_member']
+    protocol = 'nfs'
+
+    @classmethod
+    def setup_clients(cls):
+        super(TestProjectMemberTestsNFS, cls).setup_clients()
+        cls.alt_project_share_v2_client = (
+            cls.os_project_alt_member.share_v2.SharesV2Client())
+
+    @decorators.idempotent_id('75b9fd40-ae63-4caf-9c93-0fe24b2ce904')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_share(self):
+        share_client = getattr(self, 'share_member_client', self.client)
+        share = self.create_share(share_client, self.share_type['id'])
+        self.do_request(
+            'get_share', expected_status=200, share_id=share['id'])
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'get_share', expected_status=lib_exc.NotFound,
+            share_id=alt_share['id'])
+
+    @decorators.idempotent_id('92fd157a-f357-4a08-9fc6-9e77a55b89a8')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_list_share(self):
+        share_client = getattr(self, 'share_member_client', self.client)
+        share = self.create_share(share_client, self.share_type['id'])
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+
+        # We expect this key to be ignored since project_member isn't an admin
+        params = {"all_tenants": 1}
+        share_list = self.do_request(
+            'list_shares', expected_status=200, params=params)['shares']
+        share_id_list = [
+            s['id'] for s in share_list
+        ]
+
+        self.assertIn(share['id'], share_id_list)
+        self.assertNotIn(alt_share['id'], share_id_list)
+
+    @decorators.idempotent_id('7a6eef6b-bf8e-4cb3-a39c-6dc7fbe115ab')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_share(self):
+        share = self.do_request(
+            'create_share', expected_status=200,
+            **self.share(self.share_type['id']))['share']
+        waiters.wait_for_resource_status(self.client,
+                                         share['id'], 'available')
+        self.addCleanup(self.client.wait_for_resource_deletion,
+                        share_id=share['id'])
+        self.addCleanup(self.client.delete_share, share['id'])
+
+    @decorators.idempotent_id('6c546ed7-ebfd-4ac5-a626-d333a25a9e66')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_share(self):
+        share = self.create_share(self.client, self.share_type['id'])
+        self.do_request(
+            'delete_share', expected_status=202, share_id=share['id'])
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'delete_share', expected_status=lib_exc.NotFound,
+            share_id=alt_share['id'])
+
+    @decorators.idempotent_id('2349d2b0-6314-4018-85e5-696f8d1ca94a')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_force_delete_share(self):
+        share_client = getattr(self, 'share_member_client', self.client)
+        share = self.create_share(share_client, self.share_type['id'])
+        self.do_request(
+            'force_delete', expected_status=lib_exc.Forbidden,
+            s_id=share['id'])
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'force_delete', expected_status=lib_exc.Forbidden,
+            s_id=alt_share['id'])
+
+    @decorators.idempotent_id('20d6360d-5cea-4305-be36-7e1429007598')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_update_share(self):
+        share = self.create_share(self.client, self.share_type['id'])
+        name = data_utils.rand_name("rename_share")
+        self.do_request(
+            'update_share', expected_status=200, share_id=share['id'],
+            name=name)
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        alt_name = data_utils.rand_name("rename_share")
+        self.do_request(
+            'update_share', expected_status=lib_exc.NotFound,
+            share_id=alt_share['id'], name=alt_name)
+
+    @decorators.idempotent_id('483cbaef-a53d-433a-9259-f2ecc209f405')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_reset_share(self):
+        share_client = getattr(self, 'share_member_client', self.client)
+        share = self.create_share(share_client, self.share_type['id'])
+        self.do_request(
+            'reset_state', expected_status=lib_exc.Forbidden,
+            s_id=share['id'], status="error")
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'reset_state', expected_status=lib_exc.NotFound,
+            s_id=alt_share['id'], status="error")
+
+    @decorators.idempotent_id('56a07567-d0a9-460a-9267-fcd82306a371')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_shrink_share(self):
+        share = self.create_share(self.client, self.share_type['id'], size=2)
+        self.do_request(
+            'shrink_share', expected_status=202,
+            share_id=share['id'], new_size=CONF.share.share_size)
+        waiters.wait_for_resource_status(self.client, share['id'], 'available')
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'], size=2)
+        self.do_request(
+            'shrink_share', expected_status=lib_exc.NotFound,
+            share_id=alt_share['id'], new_size=CONF.share.share_size)
+
+    @decorators.idempotent_id('c09e6a72-5b99-4be6-8ffe-8ecaad0be990')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_extend_share(self):
+        share = self.create_share(self.client, self.share_type['id'])
+        self.do_request(
+            'extend_share', expected_status=202,
+            share_id=share['id'], new_size=CONF.share.share_size + 1)
+        waiters.wait_for_resource_status(self.client, share['id'], 'available')
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'extend_share', expected_status=lib_exc.NotFound,
+            share_id=alt_share['id'], new_size=CONF.share.share_size + 1)
+
+    @decorators.idempotent_id('f1c03630-987c-4f19-938d-4a0ef6529177')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_share_metadata(self):
+        share = self.create_share(
+            self.client, self.share_type['id'])
+        self.do_request(
+            'set_metadata', expected_status=200, share_id=share['id'],
+            metadata={'key': 'value'})
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'set_metadata', expected_status=lib_exc.Forbidden,
+            share_id=alt_share['id'], metadata={'key': 'value'})
+
+    @decorators.idempotent_id('a69a2b85-3374-4621-83a9-89937ddb520b')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_share_metadata(self):
+        metadata = {'key': 'value'}
+        share_client = getattr(self, 'share_member_client', self.client)
+        share = self.create_share(share_client, self.share_type['id'],
+                                  metadata=metadata)
+        self.do_request(
+            'get_metadata', expected_status=200, share_id=share['id'])
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'],
+            metadata=metadata)
+        self.do_request(
+            'get_metadata', expected_status=lib_exc.Forbidden,
+            share_id=alt_share['id'])
+
+    @decorators.idempotent_id('bea5518a-338e-494d-9034-1d03658ed58b')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_share_metadata(self):
+        share = self.create_share(
+            self.client, self.share_type['id'], metadata={'key': 'value'})
+        self.do_request(
+            'delete_metadata', expected_status=200, share_id=share['id'],
+            key='key')
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'],
+            metadata={'key': 'value'})
+        self.do_request(
+            'delete_metadata', expected_status=lib_exc.Forbidden,
+            share_id=alt_share['id'], key='key')
+
+
+class TestProjectReaderTestsNFS(TestProjectMemberTestsNFS):
+    """Test suite for basic share operations by reader user
+
+    In order to test certain share operations we must create a share resource
+    for this. Since reader user is limited in resources creation, we are forced
+    to use admin credentials, so we can test other share operations.
+    In this class we use admin user to create a member user within reader
+    project. That way we can perform a reader actions on this resource.
+    """
+
+    credentials = ['project_reader', 'project_admin', 'project_alt_member']
+
+    @classmethod
+    def setup_clients(cls):
+        super(TestProjectReaderTestsNFS, cls).setup_clients()
+        project_member = cls.setup_user_client(
+            cls.os_project_admin,
+            project_id=cls.persona.credentials.project_id)
+        cls.share_member_client = project_member.share_v2.SharesV2Client()
+
+    @decorators.idempotent_id('dc439eaf-c885-4002-be8f-4c488beeca81')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_share(self):
+        super(TestProjectReaderTestsNFS, self).test_get_share()
+
+    @decorators.idempotent_id('1fbb1078-4386-4b52-aa88-e6be4a286791')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_list_share(self):
+        super(TestProjectReaderTestsNFS, self).test_list_share()
+
+    @decorators.idempotent_id('350ba4c9-def9-4865-824a-de1ddff5dcf9')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_share(self):
+        self.do_request(
+            'create_share', expected_status=lib_exc.Forbidden,
+            **self.share(self.share_type['id']))
+
+    @decorators.idempotent_id('eb92b142-fd8d-47e3-99fe-944cce747ad7')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_share(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'])
+        self.do_request(
+            'delete_share', expected_status=lib_exc.Forbidden,
+            share_id=share['id'])
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'delete_share', expected_status=lib_exc.NotFound,
+            share_id=alt_share['id'])
+
+    @decorators.idempotent_id('cb040955-5897-409f-aea0-84b6ae16b77e')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_force_delete_share(self):
+        super(TestProjectReaderTestsNFS, self).test_force_delete_share()
+
+    @decorators.idempotent_id('3184269a-11ca-4484-8a4d-b855a6e1800f')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_update_share(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'])
+        name = data_utils.rand_name("rename_share")
+        self.do_request(
+            'update_share', expected_status=lib_exc.Forbidden,
+            share_id=share['id'], name=name)
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        alt_name = data_utils.rand_name("rename_share")
+        self.do_request(
+            'update_share', expected_status=lib_exc.Forbidden,
+            share_id=alt_share['id'], name=alt_name)
+
+    @decorators.idempotent_id('e5ae5b56-38c0-44ec-b8e0-4bc2a5c1d28a')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_reset_share(self):
+        super(TestProjectReaderTestsNFS, self).test_reset_share()
+
+    @decorators.idempotent_id('f85818b1-b93a-4b89-8aa4-b099e582be7c')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_shrink_share(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'],
+            size=CONF.share.share_size + 1)
+        self.do_request(
+            'shrink_share', expected_status=lib_exc.Forbidden,
+            share_id=share['id'], new_size=CONF.share.share_size)
+        waiters.wait_for_resource_status(self.client, share['id'], 'available')
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'],
+            size=CONF.share.share_size + 1)
+        self.do_request(
+            'shrink_share', expected_status=lib_exc.NotFound,
+            share_id=alt_share['id'], new_size=CONF.share.share_size)
+
+    @decorators.idempotent_id('0b57aedb-6b68-498f-814e-173c47e6c307')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_extend_share(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'])
+        self.do_request(
+            'extend_share', expected_status=lib_exc.Forbidden,
+            share_id=share['id'], new_size=CONF.share.share_size + 1)
+        waiters.wait_for_resource_status(self.client, share['id'], 'available')
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'extend_share', expected_status=lib_exc.NotFound,
+            share_id=alt_share['id'], new_size=CONF.share.share_size + 1)
+
+    @decorators.idempotent_id('3def3f4e-33fc-4726-8818-6cffbc2cab51')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_set_share_metadata(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'])
+        self.do_request(
+            'set_metadata', expected_status=lib_exc.Forbidden,
+            share_id=share['id'], metadata={'key': 'value'})
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'])
+        self.do_request(
+            'set_metadata', expected_status=lib_exc.Forbidden,
+            share_id=alt_share['id'], metadata={'key': 'value'})
+
+    @decorators.idempotent_id('28cacc77-556f-4707-ba2b-5ef3e56d6ef9')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_share_metadata(self):
+        super(TestProjectReaderTestsNFS, self).test_get_share_metadata()
+
+    @decorators.idempotent_id('55486589-a4ef-44f2-b489-96bc29dcd243')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_share_metadata(self):
+        share = self.create_share(
+            self.share_member_client, self.share_type['id'],
+            metadata={'key': 'value'})
+        self.do_request(
+            'delete_metadata', expected_status=lib_exc.Forbidden,
+            share_id=share['id'], key='key')
+
+        alt_share = self.create_share(
+            self.alt_project_share_v2_client, self.share_type['id'],
+            metadata={'key': 'value'})
+        self.do_request(
+            'delete_metadata', expected_status=lib_exc.Forbidden,
+            share_id=alt_share['id'], key='key')
+
+
+class TestProjectAdminTestsCEPHFS(TestProjectAdminTestsNFS):
+    protocol = 'cephfs'
+
+
+class TestProjectMemberTestsCEPHFS(TestProjectMemberTestsNFS):
+    protocol = 'cephfs'
+
+
+class TestProjectReaderTestsCEPHFS(TestProjectReaderTestsNFS):
+    protocol = 'cephfs'
+
+
+class TestProjectAdminTestsCIFS(TestProjectAdminTestsNFS):
+    protocol = 'cifs'
+
+
+class TestProjectMemberTestsCIFS(TestProjectMemberTestsNFS):
+    protocol = 'cifs'
+
+
+class TestProjectReaderTestsCIFS(TestProjectReaderTestsNFS):
+    protocol = 'cifs'
diff --git a/manila_tempest_tests/tests/rbac/test_snapshots.py b/manila_tempest_tests/tests/rbac/test_snapshots.py
new file mode 100644
index 0000000..a546fb0
--- /dev/null
+++ b/manila_tempest_tests/tests/rbac/test_snapshots.py
@@ -0,0 +1,430 @@
+# Copyright 2022 Red Hat, 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 abc
+
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import waiters
+from manila_tempest_tests.tests.api import base
+from manila_tempest_tests.tests.rbac import base as rbac_base
+
+CONF = config.CONF
+
+
+class ShareRbacSnapshotsTests(rbac_base.ShareRbacBaseTests,
+                              metaclass=abc.ABCMeta):
+
+    @classmethod
+    def skip_checks(cls):
+        super(ShareRbacSnapshotsTests, cls).skip_checks()
+        if cls.protocol not in CONF.share.enable_protocols:
+            message = "%s tests are disabled" % cls.protocol
+            raise cls.skipException(message)
+
+    @classmethod
+    def setup_clients(cls):
+        super(ShareRbacSnapshotsTests, cls).setup_clients()
+        cls.persona = getattr(cls, 'os_%s' % cls.credentials[0])
+        cls.client = cls.persona.share_v2.SharesV2Client()
+        cls.alt_project_share_v2_client = (
+            cls.os_project_alt_member.share_v2.SharesV2Client())
+
+    @abc.abstractmethod
+    def test_get_snapshot(self):
+        pass
+
+    @abc.abstractmethod
+    def test_list_snapshot(self):
+        pass
+
+    @abc.abstractmethod
+    def test_create_snapshot(self):
+        pass
+
+    @abc.abstractmethod
+    def test_delete_snapshot(self):
+        pass
+
+    @abc.abstractmethod
+    def test_force_delete_snapshot(self):
+        pass
+
+    @abc.abstractmethod
+    def test_rename_snapshot(self):
+        pass
+
+    @abc.abstractmethod
+    def test_reset_snapshot(self):
+        pass
+
+
+class TestProjectAdminTestsNFS(ShareRbacSnapshotsTests, base.BaseSharesTest):
+
+    credentials = ['project_admin', 'project_alt_member']
+    protocol = 'nfs'
+
+    @classmethod
+    def setup_clients(cls):
+        super(TestProjectAdminTestsNFS, cls).setup_clients()
+        project_member = cls.setup_user_client(
+            cls.persona, project_id=cls.persona.credentials.project_id)
+        cls.share_member_client = project_member.share_v2.SharesV2Client()
+
+    @classmethod
+    def resource_setup(cls):
+        super(TestProjectAdminTestsNFS, cls).resource_setup()
+        share_type = cls.get_share_type()
+        cls.share = cls.create_share(cls.client, share_type['id'])
+        cls.alt_share = cls.create_share(
+            cls.alt_project_share_v2_client, share_type['id'])
+
+    @decorators.idempotent_id('e55b1a01-0fcb-42aa-8cc4-b041fc75f1e4')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_snapshot(self):
+        snapshot = self.create_snapshot(
+            self.share_member_client, self.share['id'])
+        self.do_request(
+            'get_snapshot', expected_status=200, snapshot_id=snapshot['id'])
+
+        alt_snapshot = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'get_snapshot', expected_status=200,
+            snapshot_id=alt_snapshot['id'])
+
+    @decorators.idempotent_id('3b209017-f5ad-4daa-8932-582a75975bbe')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_list_snapshot(self):
+        snap = self.create_snapshot(
+            self.share_member_client, self.share['id'])
+        alt_snap = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+
+        params = {"all_tenants": 1}
+        snapshot_list = self.do_request(
+            'list_snapshots', expected_status=200, params=params)['snapshots']
+        snapshot_id_list = [
+            s['id'] for s in snapshot_list
+        ]
+
+        self.assertIn(snap['id'], snapshot_id_list)
+        self.assertIn(alt_snap['id'], snapshot_id_list)
+
+    @decorators.idempotent_id('2b90d3e9-ec71-468a-86e9-e8955139ad48')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_snapshot(self):
+        snapshot = self.do_request(
+            'create_snapshot', expected_status=202,
+            share_id=self.share['id'])['snapshot']
+        waiters.wait_for_resource_status(
+            self.client, snapshot['id'], 'available', resource_name='snapshot')
+        self.addCleanup(self.delete_resource, self.client,
+                        snapshot_id=snapshot['id'])
+
+    @decorators.idempotent_id('6de91ee0-d27e-409a-957b-75489d4e7291')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_snapshot(self):
+        snap = self.create_snapshot(
+            self.share_member_client, self.share['id'])
+        self.do_request(
+            'delete_snapshot', expected_status=202, snap_id=snap['id'])
+        self.client.wait_for_resource_deletion(snapshot_id=snap['id'])
+
+        alt_snap = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'delete_snapshot', expected_status=202,
+            snap_id=alt_snap['id'])
+        self.client.wait_for_resource_deletion(snapshot_id=alt_snap['id'])
+
+    @decorators.idempotent_id('3ac10dfb-3445-4052-855a-a17056d16a9c')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_force_delete_snapshot(self):
+        snap = self.create_snapshot(
+            self.share_member_client, self.share['id'])
+        self.do_request(
+            'force_delete', expected_status=202, s_id=snap['id'],
+            s_type='snapshots')
+        self.client.wait_for_resource_deletion(snapshot_id=snap['id'])
+
+        alt_snap = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'force_delete', expected_status=202,
+            s_id=alt_snap['id'], s_type='snapshots')
+        self.client.wait_for_resource_deletion(snapshot_id=alt_snap['id'])
+
+    @decorators.idempotent_id('513c8fef-9597-4e6c-a811-fb89b456d457')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_rename_snapshot(self):
+        snap = self.create_snapshot(
+            self.share_member_client, self.share['id'])
+        name = data_utils.rand_name("updated_snapshot")
+        self.do_request(
+            'rename_snapshot', expected_status=200, snapshot_id=snap['id'],
+            name=name)
+
+        alt_snap = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'rename_snapshot', expected_status=200,
+            snapshot_id=alt_snap['id'], name=name)
+
+    @decorators.idempotent_id('a5e99bfb-8767-4680-9e39-bde767e4b8f8')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_reset_snapshot(self):
+        snap = self.create_snapshot(
+            self.share_member_client, self.share['id'])
+        self.do_request(
+            'snapshot_reset_state', expected_status=202,
+            snapshot_id=snap['id'], status='error')
+
+        alt_snap = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'snapshot_reset_state', expected_status=202,
+            snapshot_id=alt_snap['id'], status='error')
+
+
+class TestProjectMemberTestsNFS(ShareRbacSnapshotsTests, base.BaseSharesTest):
+
+    credentials = ['project_member', 'project_alt_member']
+    protocol = 'nfs'
+
+    @classmethod
+    def resource_setup(cls):
+        super(TestProjectMemberTestsNFS, cls).resource_setup()
+        share_type = cls.get_share_type()
+        share_client = getattr(cls, 'share_member_client', cls.client)
+        cls.share = cls.create_share(share_client, share_type['id'])
+        cls.alt_share = cls.create_share(
+            cls.alt_project_share_v2_client, share_type['id'])
+
+    @decorators.idempotent_id('4ba65029-5c8b-4e96-940a-094d9f662cf6')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_snapshot(self):
+        share_client = getattr(self, 'share_member_client', self.client)
+        snapshot = self.create_snapshot(share_client, self.share['id'])
+        self.do_request(
+            'get_snapshot', expected_status=200, snapshot_id=snapshot['id'])
+
+        alt_snapshot = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'get_snapshot', expected_status=lib_exc.NotFound,
+            snapshot_id=alt_snapshot['id'])
+
+    @decorators.idempotent_id('0dcc1f68-86e2-432e-ad50-51c3cb78b986')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_list_snapshot(self):
+        share_client = getattr(self, 'share_member_client', self.client)
+        snap = self.create_snapshot(share_client, self.share['id'])
+        alt_snap = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+
+        # We expect this key to be ignored since project_member isn't an admin
+        params = {"all_tenants": 1}
+        snapshot_list = self.do_request(
+            'list_snapshots', expected_status=200, params=params)['snapshots']
+        snapshot_id_list = [
+            s['id'] for s in snapshot_list
+        ]
+
+        self.assertIn(snap['id'], snapshot_id_list)
+        self.assertNotIn(alt_snap['id'], snapshot_id_list)
+
+    @decorators.idempotent_id('d880b3f0-9027-4141-b28a-13e797919af7')
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_snapshot(self):
+        snapshot = self.do_request(
+            'create_snapshot', expected_status=202,
+            share_id=self.share['id'])['snapshot']
+        waiters.wait_for_resource_status(
+            self.client, snapshot['id'], 'available', resource_name='snapshot')
+        self.addCleanup(self.delete_resource, self.client,
+                        snapshot_id=snapshot['id'])
+
+    @decorators.idempotent_id('e3fdd270-971f-4478-9e64-9bd11166bab6')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_snapshot(self):
+        snap = self.create_snapshot(self.client, self.share['id'])
+        self.do_request(
+            'delete_snapshot', expected_status=202, snap_id=snap['id'])
+        self.client.wait_for_resource_deletion(snapshot_id=snap['id'])
+
+        alt_snap = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'delete_snapshot', expected_status=lib_exc.NotFound,
+            snap_id=alt_snap['id'])
+
+    @decorators.idempotent_id('a93d6946-1d86-40a1-af01-90e843f8f575')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_force_delete_snapshot(self):
+        share_client = getattr(self, 'share_member_client', self.client)
+        snap = self.create_snapshot(share_client, self.share['id'])
+        self.do_request(
+            'force_delete', expected_status=lib_exc.Forbidden, s_id=snap['id'],
+            s_type='snapshots')
+
+        alt_snap = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'force_delete', expected_status=lib_exc.Forbidden,
+            s_id=alt_snap['id'], s_type='snapshots')
+
+    @decorators.idempotent_id('6da7bf79-25ab-4475-a5e0-1046781e9bc7')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_rename_snapshot(self):
+        snap = self.create_snapshot(self.client, self.share['id'])
+        name = data_utils.rand_name("updated_snapshot")
+        self.do_request(
+            'rename_snapshot', expected_status=200, snapshot_id=snap['id'],
+            name=name)
+
+        alt_snap = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'rename_snapshot', expected_status=lib_exc.NotFound,
+            snapshot_id=alt_snap['id'], name=name)
+
+    @decorators.idempotent_id('22ba2e2e-6788-4075-9e92-af140d3b1238')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_reset_snapshot(self):
+        share_client = getattr(self, 'share_member_client', self.client)
+        snap = self.create_snapshot(share_client, self.share['id'])
+        self.do_request(
+            'snapshot_reset_state', expected_status=lib_exc.Forbidden,
+            snapshot_id=snap['id'], status='error')
+
+        alt_snap = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'snapshot_reset_state', expected_status=lib_exc.Forbidden,
+            snapshot_id=alt_snap['id'], status='error')
+
+
+class TestProjectReaderTestsNFS(TestProjectMemberTestsNFS):
+    """Test suite for basic share snapshot operations by reader user
+
+    In order to test certain share operations we must create a share snapshot
+    resource for this. Since reader user is limited in resources creation, we
+    are forced to use admin credentials, so we can test other share
+    operations. In this class we use admin user to create a member user within
+    reader project. That way we can perform a reader actions on this resource.
+    """
+
+    credentials = ['project_reader', 'project_admin', 'project_alt_member']
+
+    @classmethod
+    def setup_clients(cls):
+        super(TestProjectReaderTestsNFS, cls).setup_clients()
+        project_member = cls.setup_user_client(
+            cls.os_project_admin,
+            project_id=cls.persona.credentials.project_id)
+        cls.share_member_client = project_member.share_v2.SharesV2Client()
+
+    @classmethod
+    def resource_setup(cls):
+        super(TestProjectReaderTestsNFS, cls).resource_setup()
+        share_type = cls.get_share_type()
+        cls.share = cls.create_share(cls.share_member_client, share_type['id'])
+        cls.alt_share = cls.create_share(
+            cls.alt_project_share_v2_client, share_type['id'])
+
+    @decorators.idempotent_id('46a09178-0264-4f56-9a5f-9a0583e72e4d')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_snapshot(self):
+        super(TestProjectReaderTestsNFS, self).test_get_snapshot()
+
+    @decorators.idempotent_id('fef4285a-a489-4fec-97af-763c2e33282e')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_list_snapshot(self):
+        super(TestProjectReaderTestsNFS, self).test_list_snapshot()
+
+    @decorators.idempotent_id('17a80156-8cd6-420e-8ffe-97103edef4c3')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_snapshot(self):
+        self.do_request(
+            'create_snapshot', expected_status=lib_exc.Forbidden,
+            share_id=self.share['id'])
+
+    @decorators.idempotent_id('b0ca5483-ebdb-484c-a975-525e4d7deca2')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_snapshot(self):
+        snap = self.create_snapshot(self.share_member_client, self.share['id'])
+        self.do_request(
+            'delete_snapshot', expected_status=lib_exc.Forbidden,
+            snap_id=snap['id'])
+
+        alt_snap = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'delete_snapshot', expected_status=lib_exc.NotFound,
+            snap_id=alt_snap['id'])
+
+    @decorators.idempotent_id('ed0af390-e3d0-432b-9147-c0d569181b92')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_force_delete_snapshot(self):
+        super(TestProjectReaderTestsNFS, self).test_force_delete_snapshot()
+
+    @decorators.idempotent_id('21db863f-c2a4-4d07-b435-2a000255ea3b')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_rename_snapshot(self):
+        snap = self.create_snapshot(self.share_member_client, self.share['id'])
+        name = data_utils.rand_name("updated_snapshot")
+        self.do_request(
+            'rename_snapshot', expected_status=lib_exc.Forbidden,
+            snapshot_id=snap['id'], name=name)
+
+        alt_snap = self.create_snapshot(
+            self.alt_project_share_v2_client, self.alt_share['id'])
+        self.do_request(
+            'rename_snapshot', expected_status=lib_exc.NotFound,
+            snapshot_id=alt_snap['id'], name=name)
+
+    @decorators.idempotent_id('b8c9c9a4-3b2a-4b1c-80d8-2ec87d708111')
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_reset_snapshot(self):
+        super(TestProjectReaderTestsNFS, self).test_reset_snapshot()
+
+
+class TestProjectAdminTestsCEPHFS(TestProjectAdminTestsNFS):
+    protocol = 'cephfs'
+
+
+class TestProjectMemberTestsCEPHFS(TestProjectMemberTestsNFS):
+    protocol = 'cephfs'
+
+
+class TestProjectReaderTestsCEPHFS(TestProjectReaderTestsNFS):
+    protocol = 'cephfs'
+
+
+class TestProjectAdminTestsCIFS(TestProjectAdminTestsNFS):
+    protocol = 'cifs'
+
+
+class TestProjectMemberTestsCIFS(TestProjectMemberTestsNFS):
+    protocol = 'cifs'
+
+
+class TestProjectReaderTestsCIFS(TestProjectReaderTestsNFS):
+    protocol = 'cifs'