[Tempest] Add functional tests for share groups feature

Add functional tempest tests to new 'share group' feature [1].

[1] I79a80a62ae4e0015d6161edc2b93fd1f9ba69537

Co-Authored-By: Andrew Kerr <andrew.kerr@netapp.com>
Co-Authored-By: Valeriy Ponomaryov <vponomaryov@mirantis.com>
Partially-implements-blueprint: manila-share-groups
Depends-On: I8e29baed62355fc31caeec9c7a66eaebfcbdf184
Change-Id: I820eb959082995d961b1be992e4b2d1d1a985c1c
diff --git a/manila_tempest_tests/common/constants.py b/manila_tempest_tests/common/constants.py
index a478487..4ca87d2 100644
--- a/manila_tempest_tests/common/constants.py
+++ b/manila_tempest_tests/common/constants.py
@@ -60,3 +60,24 @@
 STATUS_RESTORING = 'restoring'
 STATUS_REVERTING = 'reverting'
 STATUS_REVERTING_ERROR = 'reverting_error'
+
+# Share groups
+MIN_SHARE_GROUP_MICROVERSION = '2.31'
+SHARE_GROUP_SIMPLE_KEYS = {
+    'id', 'name', 'links',
+}
+SHARE_GROUP_DETAIL_REQUIRED_KEYS = {
+    'id', 'name', 'description', 'created_at', 'status', 'share_types',
+    'project_id', 'host', 'links', 'share_group_type_id',
+}
+SHARE_GROUP_SNAPSHOT_SIMPLE_KEYS = {
+    'id', 'name', 'links',
+}
+SHARE_GROUP_SNAPSHOT_DETAIL_REQUIRED_KEYS = {
+    'id', 'name', 'description', 'created_at', 'status', 'project_id',
+    'links', 'share_group_id', 'members',
+}
+
+SHARE_GROUP_TYPE_REQUIRED_KEYS = {
+    'id', 'name', 'share_types', 'is_public', 'group_specs',
+}
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index d25cb8d..9af95eb 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -170,11 +170,10 @@
                 help="Defines whether to run tests that revert shares "
                      "to snapshots or not. Enable this feature if used "
                      "driver supports it."),
-    cfg.BoolOpt("run_consistency_group_tests",
-                default=False,
-                help="Defines whether to run consistency group tests or not. "
-                     "Disable this feature if used driver doesn't support "
-                     "it."),
+    cfg.BoolOpt("run_share_group_tests",
+                default=True,
+                deprecated_name="run_consistency_group_tests",
+                help="Defines whether to run share group tests or not."),
     cfg.BoolOpt("run_replication_tests",
                 default=False,
                 help="Defines whether to run replication tests or not. "
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 aa176cb..a524051 100644
--- a/manila_tempest_tests/services/share/v2/json/shares_client.py
+++ b/manila_tempest_tests/services/share/v2/json/shares_client.py
@@ -173,12 +173,16 @@
         if "share_instance_id" in kwargs:
             return self._is_resource_deleted(
                 self.get_share_instance, kwargs.get("share_instance_id"))
-        elif "cg_id" in kwargs:
+        elif "share_group_id" in kwargs:
             return self._is_resource_deleted(
-                self.get_consistency_group, kwargs.get("cg_id"))
-        elif "cgsnapshot_id" in kwargs:
+                self.get_share_group, kwargs.get("share_group_id"))
+        elif "share_group_snapshot_id" in kwargs:
             return self._is_resource_deleted(
-                self.get_cgsnapshot, kwargs.get("cgsnapshot_id"))
+                self.get_share_group_snapshot,
+                kwargs.get("share_group_snapshot_id"))
+        elif "share_group_type_id" in kwargs:
+            return self._is_resource_deleted(
+                self.get_share_group_type, kwargs.get("share_group_type_id"))
         elif "replica_id" in kwargs:
             return self._is_resource_deleted(
                 self.get_share_replica, kwargs.get("replica_id"))
@@ -192,8 +196,9 @@
                      name=None, snapshot_id=None, description=None,
                      metadata=None, share_network_id=None,
                      share_type_id=None, is_public=False,
-                     consistency_group_id=None, availability_zone=None,
-                     version=LATEST_MICROVERSION):
+                     share_group_id=None, availability_zone=None,
+                     version=LATEST_MICROVERSION, experimental=False):
+        headers = EXPERIMENTAL if experimental else None
         metadata = metadata or {}
         if name is None:
             name = data_utils.rand_name("tempest-created-share")
@@ -222,29 +227,37 @@
             post_body["share"]["share_network_id"] = share_network_id
         if share_type_id:
             post_body["share"]["share_type"] = share_type_id
-        if consistency_group_id:
-            post_body["share"]["consistency_group_id"] = consistency_group_id
+        if share_group_id:
+            post_body["share"]["share_group_id"] = share_group_id
         body = json.dumps(post_body)
-        resp, body = self.post("shares", body, version=version)
+        resp, body = self.post("shares", body, headers=headers,
+                               extra_headers=experimental, version=version)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
     def list_shares(self, detailed=False, params=None,
-                    version=LATEST_MICROVERSION):
+                    version=LATEST_MICROVERSION, experimental=False):
         """Get list of shares w/o filters."""
+        headers = EXPERIMENTAL if experimental else None
         uri = 'shares/detail' if detailed else 'shares'
         uri += '?%s' % urlparse.urlencode(params) if params else ''
-        resp, body = self.get(uri, version=version)
+        resp, body = self.get(uri, headers=headers, extra_headers=experimental,
+                              version=version)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
     def list_shares_with_detail(self, params=None,
-                                version=LATEST_MICROVERSION):
+                                version=LATEST_MICROVERSION,
+                                experimental=False):
         """Get detailed list of shares w/o filters."""
-        return self.list_shares(detailed=True, params=params, version=version)
+        return self.list_shares(detailed=True, params=params,
+                                version=version, experimental=experimental)
 
-    def get_share(self, share_id, version=LATEST_MICROVERSION):
-        resp, body = self.get("shares/%s" % share_id, version=version)
+    def get_share(self, share_id, version=LATEST_MICROVERSION,
+                  experimental=False):
+        headers = EXPERIMENTAL if experimental else None
+        resp, body = self.get("shares/%s" % share_id, headers=headers,
+                              extra_headers=experimental, version=version)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
@@ -881,62 +894,68 @@
 
 ###############
 
-    def create_consistency_group(self, name=None, description=None,
-                                 share_type_ids=(), share_network_id=None,
-                                 source_cgsnapshot_id=None,
-                                 version=LATEST_MICROVERSION):
-        """Create a new consistency group."""
-        uri = 'consistency-groups'
+    def create_share_group(self, name=None, description=None,
+                           share_group_type_id=None, share_type_ids=(),
+                           share_network_id=None,
+                           source_share_group_snapshot_id=None,
+                           availability_zone=None,
+                           version=LATEST_MICROVERSION):
+        """Create a new share group."""
+        uri = 'share-groups'
         post_body = {}
         if name:
             post_body['name'] = name
         if description:
             post_body['description'] = description
+        if share_group_type_id:
+            post_body['share_group_type_id'] = share_group_type_id
         if share_type_ids:
             post_body['share_types'] = share_type_ids
-        if source_cgsnapshot_id:
-            post_body['source_cgsnapshot_id'] = source_cgsnapshot_id
+        if source_share_group_snapshot_id:
+            post_body['source_share_group_snapshot_id'] = (
+                source_share_group_snapshot_id)
         if share_network_id:
             post_body['share_network_id'] = share_network_id
-        body = json.dumps({'consistency_group': post_body})
+        if availability_zone:
+            post_body['availability_zone'] = availability_zone
+        body = json.dumps({'share_group': post_body})
+
         resp, body = self.post(uri, body, headers=EXPERIMENTAL,
                                extra_headers=True, version=version)
+
         self.expected_success(202, resp.status)
         return self._parse_resp(body)
 
-    def delete_consistency_group(self, consistency_group_id,
-                                 version=LATEST_MICROVERSION):
-        """Delete a consistency group."""
-        uri = 'consistency-groups/%s' % consistency_group_id
+    def delete_share_group(self, share_group_id, version=LATEST_MICROVERSION):
+        """Delete a share group."""
+        uri = 'share-groups/%s' % share_group_id
         resp, body = self.delete(uri, headers=EXPERIMENTAL,
                                  extra_headers=True, version=version)
         self.expected_success(202, resp.status)
-        return body
+        return self._parse_resp(body)
 
-    def list_consistency_groups(self, detailed=False, params=None,
-                                version=LATEST_MICROVERSION):
-        """Get list of consistency groups w/o filters."""
-        uri = 'consistency-groups%s' % ('/detail' if detailed else '')
+    def list_share_groups(self, detailed=False, params=None,
+                          version=LATEST_MICROVERSION):
+        """Get list of share groups w/o filters."""
+        uri = 'share-groups%s' % ('/detail' if detailed else '')
         uri += '?%s' % (urlparse.urlencode(params) if params else '')
         resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
                               version=version)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
-    def get_consistency_group(self, consistency_group_id,
-                              version=LATEST_MICROVERSION):
-        """Get consistency group info."""
-        uri = 'consistency-groups/%s' % consistency_group_id
+    def get_share_group(self, share_group_id, version=LATEST_MICROVERSION):
+        """Get share group info."""
+        uri = 'share-groups/%s' % share_group_id
         resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
                               version=version)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
-    def update_consistency_group(self, consistency_group_id, name=None,
-                                 description=None,
-                                 version=LATEST_MICROVERSION, **kwargs):
-        """Update an existing consistency group."""
-        uri = 'consistency-groups/%s' % consistency_group_id
+    def update_share_group(self, share_group_id, name=None, description=None,
+                           version=LATEST_MICROVERSION, **kwargs):
+        """Update an existing share group."""
+        uri = 'share-groups/%s' % share_group_id
         post_body = {}
         if name:
             post_body['name'] = name
@@ -944,147 +963,291 @@
             post_body['description'] = description
         if kwargs:
             post_body.update(kwargs)
-        body = json.dumps({'consistency_group': post_body})
+        body = json.dumps({'share_group': post_body})
+
         resp, body = self.put(uri, body, headers=EXPERIMENTAL,
                               extra_headers=True, version=version)
+
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
-    def consistency_group_reset_state(self, id, status,
-                                      version=LATEST_MICROVERSION):
-        self.reset_state(id, status=status,
-                         s_type='consistency-groups', headers=EXPERIMENTAL,
-                         version=version)
+    def share_group_reset_state(self, share_group_id, status='error',
+                                version=LATEST_MICROVERSION):
+        self.reset_state(share_group_id, status=status, s_type='groups',
+                         headers=EXPERIMENTAL, version=version)
 
-    def consistency_group_force_delete(self, id, version=LATEST_MICROVERSION):
-        self.force_delete(id, s_type='consistency-groups',
+    def share_group_force_delete(self, share_group_id,
+                                 version=LATEST_MICROVERSION):
+        self.force_delete(share_group_id, s_type='share-groups',
                           headers=EXPERIMENTAL, version=version)
 
-    def wait_for_consistency_group_status(self, consistency_group_id, status):
-        """Waits for a consistency group to reach a given status."""
-        body = self.get_consistency_group(consistency_group_id)
-        consistency_group_name = body['name']
-        consistency_group_status = body['status']
+    def wait_for_share_group_status(self, share_group_id, status):
+        """Waits for a share group to reach a given status."""
+        body = self.get_share_group(share_group_id)
+        sg_name = body['name']
+        sg_status = body['status']
         start = int(time.time())
 
-        while consistency_group_status != status:
+        while sg_status != status:
             time.sleep(self.build_interval)
-            body = self.get_consistency_group(consistency_group_id)
-            consistency_group_status = body['status']
-            if 'error' in consistency_group_status and status != 'error':
-                raise share_exceptions.ConsistencyGroupBuildErrorException(
-                    consistency_group_id=consistency_group_id)
+            body = self.get_share_group(share_group_id)
+            sg_status = body['status']
+            if 'error' in sg_status and status != 'error':
+                raise share_exceptions.ShareGroupBuildErrorException(
+                    share_group_id=share_group_id)
 
             if int(time.time()) - start >= self.build_timeout:
-                consistency_group_name = (
-                    consistency_group_name if consistency_group_name else
-                    consistency_group_id
-                )
-                message = ('Consistency Group %s failed to reach %s status '
+                sg_name = sg_name or share_group_id
+                message = ('Share Group %s failed to reach %s status '
                            'within the required time (%s s). '
                            'Current status: %s' %
-                           (consistency_group_name, status,
-                            self.build_timeout, consistency_group_status))
+                           (sg_name, status, self.build_timeout, sg_status))
                 raise exceptions.TimeoutException(message)
 
 ###############
 
-    def create_cgsnapshot(self, consistency_group_id,
-                          name=None, description=None,
-                          version=LATEST_MICROVERSION):
-        """Create a new cgsnapshot of an existing consistency group."""
-        uri = 'cgsnapshots'
-        post_body = {'consistency_group_id': consistency_group_id}
-        if name:
+    def create_share_group_type(self, name=None, share_types=(),
+                                is_public=None, group_specs=None,
+                                version=LATEST_MICROVERSION):
+        """Create a new share group type."""
+        uri = 'share-group-types'
+        post_body = {}
+        if isinstance(share_types, (tuple, list)):
+            share_types = list(share_types)
+        else:
+            share_types = [share_types]
+        if name is not None:
             post_body['name'] = name
-        if description:
-            post_body['description'] = description
-        body = json.dumps({'cgsnapshot': post_body})
+        if share_types:
+            post_body['share_types'] = share_types
+        if is_public is not None:
+            post_body['is_public'] = is_public
+        if group_specs:
+            post_body['group_specs'] = group_specs
+        body = json.dumps({'share_group_type': post_body})
         resp, body = self.post(uri, body, headers=EXPERIMENTAL,
                                extra_headers=True, version=version)
-        self.expected_success(202, resp.status)
+        self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
-    def delete_cgsnapshot(self, cgsnapshot_id,
-                          version=LATEST_MICROVERSION):
-        """Delete an existing cgsnapshot."""
-        uri = 'cgsnapshots/%s' % cgsnapshot_id
-        resp, body = self.delete(uri, headers=EXPERIMENTAL,
-                                 extra_headers=True, version=version)
-        self.expected_success(202, resp.status)
-        return body
-
-    def list_cgsnapshots(self, detailed=False, params=None,
-                         version=LATEST_MICROVERSION):
-        """Get list of cgsnapshots w/o filters."""
-        uri = 'cgsnapshots/detail' if detailed else 'cgsnapshots'
+    def list_share_group_types(self, detailed=False, params=None,
+                               version=LATEST_MICROVERSION):
+        """Get list of share group types."""
+        uri = 'share-group-types%s' % ('/detail' if detailed else '')
         uri += '?%s' % (urlparse.urlencode(params) if params else '')
         resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
                               version=version)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
-    def list_cgsnapshot_members(self, cgsnapshot_id,
+    def get_share_group_type(self, share_group_type_id,
+                             version=LATEST_MICROVERSION):
+        """Get share group type info."""
+        uri = 'share-group-types/%s' % share_group_type_id
+        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
+                              version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def get_default_share_group_type(self, version=LATEST_MICROVERSION):
+        """Get default share group type info."""
+        uri = 'share-group-types/default'
+        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
+                              version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def delete_share_group_type(self, share_group_type_id,
                                 version=LATEST_MICROVERSION):
-        """Get list of members of a cgsnapshots."""
-        uri = 'cgsnapshots/%s/members' % cgsnapshot_id
+        """Delete an existing share group type."""
+        uri = 'share-group-types/%s' % share_group_type_id
+        resp, body = self.delete(uri, headers=EXPERIMENTAL,
+                                 extra_headers=True, version=version)
+        self.expected_success(204, resp.status)
+        return self._parse_resp(body)
+
+    def add_access_to_share_group_type(self, share_group_type_id, project_id,
+                                       version=LATEST_MICROVERSION):
+        uri = 'share-group-types/%s/action' % share_group_type_id
+        post_body = {'project': project_id}
+        post_body = json.dumps({'addProjectAccess': post_body})
+        resp, body = self.post(uri, post_body, headers=EXPERIMENTAL,
+                               extra_headers=True, version=version)
+        self.expected_success(202, resp.status)
+        return self._parse_resp(body)
+
+    def remove_access_from_share_group_type(self, share_group_type_id,
+                                            project_id,
+                                            version=LATEST_MICROVERSION):
+        uri = 'share-group-types/%s/action' % share_group_type_id
+        post_body = {'project': project_id}
+        post_body = json.dumps({'removeProjectAccess': post_body})
+        resp, body = self.post(uri, post_body, headers=EXPERIMENTAL,
+                               extra_headers=True, version=version)
+        self.expected_success(202, resp.status)
+        return self._parse_resp(body)
+
+    def list_access_to_share_group_type(self, share_group_type_id,
+                                        version=LATEST_MICROVERSION):
+        uri = 'share-group-types/%s/access' % share_group_type_id
         resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
                               version=version)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
-    def get_cgsnapshot(self, cgsnapshot_id, version=LATEST_MICROVERSION):
-        """Get cgsnapshot info."""
-        uri = 'cgsnapshots/%s' % cgsnapshot_id
+###############
+
+    def create_share_group_type_specs(self, share_group_type_id,
+                                      group_specs_dict,
+                                      version=LATEST_MICROVERSION):
+        url = "share-group-types/%s/group-specs" % share_group_type_id
+        post_body = json.dumps({'group_specs': group_specs_dict})
+        resp, body = self.post(url, post_body, headers=EXPERIMENTAL,
+                               extra_headers=True, version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def get_share_group_type_spec(self, share_group_type_id, group_spec_key,
+                                  version=LATEST_MICROVERSION):
+        uri = "group-types/%s/group_specs/%s" % (
+            share_group_type_id, group_spec_key)
         resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
                               version=version)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
-    def update_cgsnapshot(self, cgsnapshot_id, name=None, description=None,
-                          version=LATEST_MICROVERSION):
-        """Update an existing cgsnapshot."""
-        uri = 'cgsnapshots/%s' % cgsnapshot_id
+    def list_share_group_type_specs(self, share_group_type_id, params=None,
+                                    version=LATEST_MICROVERSION):
+        uri = "share-group-types/%s/group_specs" % share_group_type_id
+        if params is not None:
+            uri += '?%s' % urlparse.urlencode(params)
+        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
+                              version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def update_share_group_type_spec(self, share_group_type_id, group_spec_key,
+                                     group_spec_value,
+                                     version=LATEST_MICROVERSION):
+        uri = "share-group-types/%s/group-specs/%s" % (
+            share_group_type_id, group_spec_key)
+        group_spec = {group_spec_key: group_spec_value}
+        post_body = json.dumps(group_spec)
+        resp, body = self.put(uri, post_body, headers=EXPERIMENTAL,
+                              extra_headers=True, version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def update_share_group_type_specs(self, share_group_type_id,
+                                      group_specs_dict,
+                                      version=LATEST_MICROVERSION):
+        return self.create_share_group_type_specs(
+            share_group_type_id, group_specs_dict, version=version)
+
+    def delete_share_group_type_spec(self, share_type_id, group_spec_key,
+                                     version=LATEST_MICROVERSION):
+        uri = "share-group-types/%s/group-specs/%s" % (
+            share_type_id, group_spec_key)
+        resp, body = self.delete(uri, headers=EXPERIMENTAL, extra_headers=True,
+                                 version=version)
+        self.expected_success(204, resp.status)
+        return body
+
+###############
+
+    def create_share_group_snapshot(self, share_group_id, name=None,
+                                    description=None,
+                                    version=LATEST_MICROVERSION):
+        """Create a new share group snapshot of an existing share group."""
+        uri = 'share-group-snapshots'
+        post_body = {'share_group_id': share_group_id}
+        if name:
+            post_body['name'] = name
+        if description:
+            post_body['description'] = description
+        body = json.dumps({'share_group_snapshot': post_body})
+        resp, body = self.post(uri, body, headers=EXPERIMENTAL,
+                               extra_headers=True, version=version)
+        self.expected_success(202, resp.status)
+        return self._parse_resp(body)
+
+    def delete_share_group_snapshot(self, share_group_snapshot_id,
+                                    version=LATEST_MICROVERSION):
+        """Delete an existing share group snapshot."""
+        uri = 'share-group-snapshots/%s' % share_group_snapshot_id
+        resp, body = self.delete(uri, headers=EXPERIMENTAL,
+                                 extra_headers=True, version=version)
+        self.expected_success(202, resp.status)
+        return body
+
+    def list_share_group_snapshots(self, detailed=False, params=None,
+                                   version=LATEST_MICROVERSION):
+        """Get list of share group snapshots w/o filters."""
+        uri = 'share-group-snapshots%s' % ('/detail' if detailed else '')
+        uri += '?%s' % (urlparse.urlencode(params) if params else '')
+        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
+                              version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def get_share_group_snapshot(self, share_group_snapshot_id,
+                                 version=LATEST_MICROVERSION):
+        """Get share group snapshot info."""
+        uri = 'share-group-snapshots/%s' % share_group_snapshot_id
+        resp, body = self.get(uri, headers=EXPERIMENTAL, extra_headers=True,
+                              version=version)
+        self.expected_success(200, resp.status)
+        return self._parse_resp(body)
+
+    def update_share_group_snapshot(self, share_group_snapshot_id, name=None,
+                                    description=None,
+                                    version=LATEST_MICROVERSION):
+        """Update an existing share group snapshot."""
+        uri = 'share-group-snapshots/%s' % share_group_snapshot_id
         post_body = {}
         if name:
             post_body['name'] = name
         if description:
             post_body['description'] = description
-        body = json.dumps({'cgsnapshot': post_body})
+        body = json.dumps({'share_group_snapshot': post_body})
         resp, body = self.put(uri, body, headers=EXPERIMENTAL,
                               extra_headers=True, version=version)
         self.expected_success(200, resp.status)
         return self._parse_resp(body)
 
-    def cgsnapshot_reset_state(self, id, status,
-                               version=LATEST_MICROVERSION):
-        self.reset_state(id, status=status,
-                         s_type='cgsnapshots', headers=EXPERIMENTAL,
-                         version=version)
+    def share_group_snapshot_reset_state(self, share_group_snapshot_id,
+                                         status='error',
+                                         version=LATEST_MICROVERSION):
+        self.reset_state(
+            share_group_snapshot_id, status=status,
+            s_type='group-snapshots', headers=EXPERIMENTAL, version=version)
 
-    def cgsnapshot_force_delete(self, id, version=LATEST_MICROVERSION):
-        self.force_delete(id, s_type='cgsnapshots', headers=EXPERIMENTAL,
-                          version=version)
+    def share_group_snapshot_force_delete(self, share_group_snapshot_id,
+                                          version=LATEST_MICROVERSION):
+        self.force_delete(
+            share_group_snapshot_id, s_type='share-group-snapshots',
+            headers=EXPERIMENTAL, version=version)
 
-    def wait_for_cgsnapshot_status(self, cgsnapshot_id, status):
-        """Waits for a cgsnapshot to reach a given status."""
-        body = self.get_cgsnapshot(cgsnapshot_id)
-        cgsnapshot_name = body['name']
-        cgsnapshot_status = body['status']
+    def wait_for_share_group_snapshot_status(self, share_group_snapshot_id,
+                                             status):
+        """Waits for a share group snapshot to reach a given status."""
+        body = self.get_share_group_snapshot(share_group_snapshot_id)
+        sg_snapshot_name = body['name']
+        sg_snapshot_status = body['status']
         start = int(time.time())
 
-        while cgsnapshot_status != status:
+        while sg_snapshot_status != status:
             time.sleep(self.build_interval)
-            body = self.get_cgsnapshot(cgsnapshot_id)
-            cgsnapshot_status = body['status']
-            if 'error' in cgsnapshot_status and status != 'error':
-                raise share_exceptions.CGSnapshotBuildErrorException(
-                    cgsnapshot_id=cgsnapshot_id)
+            body = self.get_share_group_snapshot(share_group_snapshot_id)
+            sg_snapshot_status = body['status']
+            if 'error' in sg_snapshot_status and status != 'error':
+                raise share_exceptions.ShareGroupSnapshotBuildErrorException(
+                    share_group_snapshot_id=share_group_snapshot_id)
 
             if int(time.time()) - start >= self.build_timeout:
-                message = ('CGSnapshot %s failed to reach %s status '
+                message = ('Share Group Snapshot %s failed to reach %s status '
                            'within the required time (%s s).' %
-                           (cgsnapshot_name, status, self.build_timeout))
+                           (sg_snapshot_name, status, self.build_timeout))
                 raise exceptions.TimeoutException(message)
 
 ###############
diff --git a/manila_tempest_tests/share_exceptions.py b/manila_tempest_tests/share_exceptions.py
index 9b84d02..a309b84 100644
--- a/manila_tempest_tests/share_exceptions.py
+++ b/manila_tempest_tests/share_exceptions.py
@@ -24,9 +24,9 @@
     message = "Share instance %(id)s failed to build and is in ERROR status"
 
 
-class ConsistencyGroupBuildErrorException(exceptions.TempestException):
-    message = ("Consistency group %(consistency_group_id)s failed to build "
-               "and is in ERROR status")
+class ShareGroupBuildErrorException(exceptions.TempestException):
+    message = ("Share group %(share_group_id)s failed to build and "
+               "is in ERROR status")
 
 
 class AccessRuleBuildErrorException(exceptions.TempestException):
@@ -42,9 +42,9 @@
                "ERROR status.")
 
 
-class CGSnapshotBuildErrorException(exceptions.TempestException):
-    message = ("CGSnapshot %(cgsnapshot_id)s failed to build and is in ERROR "
-               "status")
+class ShareGroupSnapshotBuildErrorException(exceptions.TempestException):
+    message = ("Share Group Snapshot %(share_group_snapshot_id)s failed "
+               "to build and is in ERROR status")
 
 
 class ShareProtocolNotSpecified(exceptions.TempestException):
diff --git a/manila_tempest_tests/tests/api/admin/test_consistency_group_actions.py b/manila_tempest_tests/tests/api/admin/test_consistency_group_actions.py
deleted file mode 100644
index 8b2a21c..0000000
--- a/manila_tempest_tests/tests/api/admin/test_consistency_group_actions.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# Copyright 2015 Andrew Kerr
-# 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 config
-from tempest.lib.common.utils import data_utils
-import testtools
-from testtools import testcase as tc
-
-from manila_tempest_tests.tests.api import base
-
-CONF = config.CONF
-
-
-@testtools.skipUnless(CONF.share.run_consistency_group_tests,
-                      'Consistency Group tests disabled.')
-class ConsistencyGroupActionsTest(base.BaseSharesAdminTest):
-
-    @classmethod
-    def resource_setup(cls):
-        super(ConsistencyGroupActionsTest, cls).resource_setup()
-        # Create 2 share_types
-        name = data_utils.rand_name("tempest-manila")
-        extra_specs = cls.add_extra_specs_to_dict()
-        share_type = cls.create_share_type(name, extra_specs=extra_specs)
-        cls.share_type = share_type['share_type']
-
-        name = data_utils.rand_name("tempest-manila")
-        share_type = cls.create_share_type(name, extra_specs=extra_specs)
-        cls.share_type2 = share_type['share_type']
-
-        # Create a consistency group
-        cls.consistency_group = cls.create_consistency_group(
-            share_type_ids=[cls.share_type['id'], cls.share_type2['id']])
-        cls.consistency_group = cls.shares_v2_client.get_consistency_group(
-            cls.consistency_group['id'])
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
-    def test_create_cg_from_cgsnapshot_with_multiple_share_types_v2_4(self):
-        # Create cgsnapshot
-        cgsnapshot = self.create_cgsnapshot_wait_for_active(
-            self.consistency_group["id"],
-            cleanup_in_class=False,
-            version='2.4',
-        )
-
-        new_consistency_group = self.create_consistency_group(
-            cleanup_in_class=False,
-            source_cgsnapshot_id=cgsnapshot['id'],
-            version='2.4',
-        )
-
-        # Verify share_types are the same
-        expected_types = sorted(self.consistency_group['share_types'])
-        actual_types = sorted(new_consistency_group['share_types'])
-        self.assertEqual(expected_types, actual_types,
-                         'Expected share types of %s, but got %s.' % (
-                             expected_types, actual_types))
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
-    def test_create_cg_from_multi_typed_populated_cgsnapshot_v2_4(self):
-        share_name = data_utils.rand_name("tempest-share-name")
-        share_desc = data_utils.rand_name("tempest-share-description")
-
-        shares = self.create_shares([
-            {'kwargs': {
-                'cleanup_in_class': False,
-                'name': share_name,
-                'description': share_desc,
-                'consistency_group_id': self.consistency_group['id'],
-                'share_type_id': st_id,
-            }} for st_id in (self.share_type['id'], self.share_type2['id'])
-        ])
-
-        cg_shares = self.shares_v2_client.list_shares(
-            detailed=True,
-            params={'consistency_group_id': self.consistency_group['id']},
-            version='2.4',
-        )
-
-        cg_share_ids = [s['id'] for s in cg_shares]
-        for share_id in (shares[0]['id'], shares[1]['id']):
-            self.assertIn(share_id, cg_share_ids, 'Share %s not in '
-                                                  'consistency group %s.' %
-                          (share_id, self.consistency_group['id']))
-
-        cgsnap_name = data_utils.rand_name("tempest-cgsnap-name")
-        cgsnap_desc = data_utils.rand_name("tempest-cgsnap-description")
-        cgsnapshot = self.create_cgsnapshot_wait_for_active(
-            self.consistency_group["id"],
-            name=cgsnap_name,
-            description=cgsnap_desc,
-            cleanup_in_class=False,
-            version='2.4',
-        )
-
-        new_cg = self.create_consistency_group(
-            cleanup_in_class=False, source_cgsnapshot_id=cgsnapshot['id'],
-            version='2.4')
-        new_cg_shares = self.shares_v2_client.list_shares(
-            detailed=True,
-            params={'consistency_group_id': new_cg['id']},
-            version='2.4')
-
-        # TODO(akerr): Skip until bug 1483886 is resolved
-        # Verify that the new shares correspond to correct share types
-        # expected_share_types = [self.share_type['id'], self.share_type2[
-        # 'id']]
-        # actual_share_types = [s['share_type'] for s in new_cg_shares]
-        # self.assertEqual(sorted(expected_share_types),
-        #                  sorted(actual_share_types),
-        #                  'Expected shares of types %s, got %s.' % (
-        #                      sorted(expected_share_types),
-        #                     sorted(actual_share_types)))
-
-        # Ensure that share_server information of the child CG and associated
-        # shares match with that of the parent CG
-        self.assertEqual(self.consistency_group['share_network_id'],
-                         new_cg['share_network_id'])
-        self.assertEqual(self.consistency_group['share_server_id'],
-                         new_cg['share_server_id'])
-
-        for share in new_cg_shares:
-            msg = ('Share %(share)s has %(attr)s=%(value)s and it does not '
-                   'match that of the parent CG where %(attr)s=%(orig)s.')
-            payload = {
-                'share': share['id'],
-                'attr': 'share_network_id',
-                'value': share['share_network_id'],
-                'orig': self.consistency_group['share_network_id'],
-            }
-            self.assertEqual(self.consistency_group['share_network_id'],
-                             share['share_network_id'], msg % payload)
-
-            payload.update({'attr': 'share_server_id',
-                            'value': share['share_server_id'],
-                            'orig': self.consistency_group['share_server_id'],
-                            })
-            self.assertEqual(self.consistency_group['share_server_id'],
-                             share['share_server_id'], msg % payload)
diff --git a/manila_tempest_tests/tests/api/admin/test_consistency_groups.py b/manila_tempest_tests/tests/api/admin/test_consistency_groups.py
deleted file mode 100644
index 22678e5..0000000
--- a/manila_tempest_tests/tests/api/admin/test_consistency_groups.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# Copyright 2015 Andrew Kerr
-# 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 config
-from tempest.lib.common.utils import data_utils
-import testtools
-from testtools import testcase as tc
-
-from manila_tempest_tests.tests.api import base
-
-CONF = config.CONF
-CG_REQUIRED_ELEMENTS = {"id", "name", "description", "created_at", "status",
-                        "share_types", "project_id", "host", "links"}
-
-
-@testtools.skipUnless(CONF.share.run_consistency_group_tests,
-                      'Consistency Group tests disabled.')
-class ConsistencyGroupsTest(base.BaseSharesAdminTest):
-
-    @classmethod
-    def resource_setup(cls):
-        super(ConsistencyGroupsTest, cls).resource_setup()
-        # Create 2 share_types
-        name = data_utils.rand_name("tempest-manila")
-        extra_specs = cls.add_extra_specs_to_dict()
-        share_type = cls.create_share_type(name, extra_specs=extra_specs)
-        cls.share_type = share_type['share_type']
-
-        name = data_utils.rand_name("tempest-manila")
-        share_type = cls.create_share_type(name, extra_specs=extra_specs)
-        cls.share_type2 = share_type['share_type']
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_cg_with_multiple_share_types_v2_4(self):
-        # Create a consistency group
-        consistency_group = self.create_consistency_group(
-            cleanup_in_class=False,
-            share_type_ids=[self.share_type['id'], self.share_type2['id']],
-            version='2.4',
-        )
-
-        self.assertTrue(CG_REQUIRED_ELEMENTS.issubset(
-            consistency_group.keys()),
-            'At least one expected element missing from consistency group '
-            'response. Expected %(expected)s, got %(actual)s.' % {
-                "expected": CG_REQUIRED_ELEMENTS,
-                "actual": consistency_group.keys()})
-
-        actual_share_types = consistency_group['share_types']
-        expected_share_types = [self.share_type['id'], self.share_type2['id']]
-        self.assertEqual(sorted(expected_share_types),
-                         sorted(actual_share_types),
-                         'Incorrect share types applied to consistency group '
-                         '%s. Expected %s, got %s' % (consistency_group['id'],
-                                                      expected_share_types,
-                                                      actual_share_types))
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    @testtools.skipIf(
-        not CONF.share.multitenancy_enabled, "Only for multitenancy.")
-    def test_create_cg_from_cgsnapshot_verify_share_server_information(self):
-        # Create a consistency group
-        orig_consistency_group = self.create_consistency_group(
-            cleanup_in_class=False,
-            share_type_ids=[self.share_type['id']],
-            version='2.4')
-
-        # Get latest CG information
-        orig_consistency_group = self.shares_v2_client.get_consistency_group(
-            orig_consistency_group['id'], version='2.4')
-
-        # Assert share server information
-        self.assertIsNotNone(orig_consistency_group['share_network_id'])
-        self.assertIsNotNone(orig_consistency_group['share_server_id'])
-
-        cg_snapshot = self.create_cgsnapshot_wait_for_active(
-            orig_consistency_group['id'], cleanup_in_class=False,
-            version='2.4')
-        new_consistency_group = self.create_consistency_group(
-            cleanup_in_class=False, version='2.4',
-            source_cgsnapshot_id=cg_snapshot['id'])
-
-        # Assert share server information
-        self.assertEqual(orig_consistency_group['share_network_id'],
-                         new_consistency_group['share_network_id'])
-        self.assertEqual(orig_consistency_group['share_server_id'],
-                         new_consistency_group['share_server_id'])
diff --git a/manila_tempest_tests/tests/api/admin/test_consistency_groups_negative.py b/manila_tempest_tests/tests/api/admin/test_consistency_groups_negative.py
deleted file mode 100644
index a850379..0000000
--- a/manila_tempest_tests/tests/api/admin/test_consistency_groups_negative.py
+++ /dev/null
@@ -1,292 +0,0 @@
-# Copyright 2015 Andrew Kerr
-# 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 config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import exceptions
-import testtools
-from testtools import testcase as tc
-
-from manila_tempest_tests.tests.api import base
-
-CONF = config.CONF
-
-
-@testtools.skipUnless(CONF.share.run_consistency_group_tests,
-                      'Consistency Group tests disabled.')
-class ConsistencyGroupsNegativeTest(base.BaseSharesAdminTest):
-
-    @classmethod
-    def resource_setup(cls):
-        super(ConsistencyGroupsNegativeTest, cls).resource_setup()
-        # Create share_type
-        name = data_utils.rand_name("tempest-manila")
-        extra_specs = cls.add_extra_specs_to_dict()
-        share_type = cls.create_share_type(name, extra_specs=extra_specs)
-        cls.share_type = share_type['share_type']
-
-        # Create a consistency group
-        cls.consistency_group = cls.create_consistency_group(
-            share_type_ids=[cls.share_type['id']])
-
-        # Create share inside consistency group
-        cls.share_name = data_utils.rand_name("tempest-share-name")
-        cls.share_desc = data_utils.rand_name("tempest-share-description")
-        cls.share = cls.create_share(
-            name=cls.share_name,
-            description=cls.share_desc,
-            consistency_group_id=cls.consistency_group['id'],
-            share_type_id=cls.share_type['id'],
-        )
-
-        # Create a cgsnapshot of the consistency group
-        cls.cgsnap_name = data_utils.rand_name("tempest-cgsnap-name")
-        cls.cgsnap_desc = data_utils.rand_name("tempest-cgsnap-description")
-        cls.cgsnapshot = cls.create_cgsnapshot_wait_for_active(
-            cls.consistency_group["id"],
-            name=cls.cgsnap_name,
-            description=cls.cgsnap_desc)
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_delete_share_type_in_use_by_cg(self):
-        # Attempt delete of share type
-        self.assertRaises(exceptions.BadRequest,
-                          self.shares_client.delete_share_type,
-                          self.share_type['id'])
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_share_of_unsupported_type_in_cg_v2_4(self):
-        # Attempt to create share of default type in the cg
-        self.assertRaises(exceptions.BadRequest,
-                          self.create_share,
-                          size=1,
-                          consistency_group_id=self.consistency_group['id'],
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_share_in_cg_that_is_not_available_v2_4(self):
-        consistency_group = self.create_consistency_group(
-            cleanup_in_class=False, version='2.4')
-        self.addCleanup(self.shares_v2_client.consistency_group_reset_state,
-                        consistency_group['id'],
-                        status='available',
-                        version='2.4')
-        # creating
-        self.shares_v2_client.consistency_group_reset_state(
-            consistency_group['id'], status='creating', version='2.4')
-        self.shares_v2_client.wait_for_consistency_group_status(
-            consistency_group['id'], 'creating')
-        self.assertRaises(exceptions.BadRequest, self.create_share,
-                          name=self.share_name,
-                          description=self.share_desc,
-                          consistency_group_id=consistency_group['id'],
-                          cleanup_in_class=False,
-                          version='2.4')
-        # deleting
-        self.shares_v2_client.consistency_group_reset_state(
-            consistency_group['id'], status='deleting', version='2.4')
-        self.shares_v2_client.wait_for_consistency_group_status(
-            consistency_group['id'], 'deleting')
-        self.assertRaises(exceptions.BadRequest, self.create_share,
-                          name=self.share_name,
-                          description=self.share_desc,
-                          consistency_group_id=consistency_group['id'],
-                          cleanup_in_class=False,
-                          version='2.4')
-        # error
-        self.shares_v2_client.consistency_group_reset_state(
-            consistency_group['id'], status='error', version='2.4')
-        self.shares_v2_client.wait_for_consistency_group_status(
-            consistency_group['id'], 'error')
-        self.assertRaises(exceptions.BadRequest, self.create_share,
-                          name=self.share_name,
-                          description=self.share_desc,
-                          consistency_group_id=consistency_group['id'],
-                          cleanup_in_class=False,
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_cgsnapshot_of_cg_that_is_not_available_v2_4(self):
-        consistency_group = self.create_consistency_group(
-            cleanup_in_class=False, version='2.4')
-        self.addCleanup(self.shares_v2_client.consistency_group_reset_state,
-                        consistency_group['id'],
-                        status='available',
-                        version='2.4')
-        # creating
-        self.shares_v2_client.consistency_group_reset_state(
-            consistency_group['id'], status='creating', version='2.4')
-        self.shares_v2_client.wait_for_consistency_group_status(
-            consistency_group['id'], 'creating')
-        self.assertRaises(exceptions.Conflict,
-                          self.create_cgsnapshot_wait_for_active,
-                          consistency_group['id'],
-                          cleanup_in_class=False,
-                          version='2.4')
-        # deleting
-        self.shares_v2_client.consistency_group_reset_state(
-            consistency_group['id'], status='deleting', version='2.4')
-        self.shares_v2_client.wait_for_consistency_group_status(
-            consistency_group['id'], 'deleting')
-        self.assertRaises(exceptions.Conflict,
-                          self.create_cgsnapshot_wait_for_active,
-                          consistency_group['id'],
-                          cleanup_in_class=False,
-                          version='2.4')
-        # error
-        self.shares_v2_client.consistency_group_reset_state(
-            consistency_group['id'], status='error', version='2.4')
-        self.shares_v2_client.wait_for_consistency_group_status(
-            consistency_group['id'], 'error')
-        self.assertRaises(exceptions.Conflict,
-                          self.create_cgsnapshot_wait_for_active,
-                          consistency_group['id'],
-                          cleanup_in_class=False,
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_cgsnapshot_of_cg_with_share_in_error_state_v2_4(self):
-        consistency_group = self.create_consistency_group(version='2.4')
-        share_name = data_utils.rand_name("tempest-share-name")
-        share_desc = data_utils.rand_name("tempest-share-description")
-        share = self.create_share(
-            name=share_name,
-            description=share_desc,
-            consistency_group_id=consistency_group['id'],
-            cleanup_in_class=False,
-            version='2.4',
-        )
-        self.shares_client.reset_state(s_id=share['id'])
-        self.shares_client.wait_for_share_status(share['id'], 'error')
-        self.assertRaises(exceptions.Conflict,
-                          self.create_cgsnapshot_wait_for_active,
-                          consistency_group['id'],
-                          cleanup_in_class=False,
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_delete_cgsnapshot_not_in_available_or_error_v2_4(self):
-        cgsnapshot = self.create_cgsnapshot_wait_for_active(
-            self.consistency_group['id'],
-            cleanup_in_class=False,
-            version='2.4',
-        )
-        self.addCleanup(self.shares_v2_client.cgsnapshot_reset_state,
-                        cgsnapshot['id'],
-                        status='available',
-                        version='2.4')
-
-        # creating
-        self.shares_v2_client.cgsnapshot_reset_state(cgsnapshot['id'],
-                                                     status='creating',
-                                                     version='2.4')
-        self.shares_v2_client.wait_for_cgsnapshot_status(cgsnapshot['id'],
-                                                         'creating')
-        self.assertRaises(exceptions.Conflict,
-                          self.shares_v2_client.delete_cgsnapshot,
-                          cgsnapshot['id'],
-                          version='2.4')
-        # deleting
-        self.shares_v2_client.cgsnapshot_reset_state(cgsnapshot['id'],
-                                                     status='deleting',
-                                                     version='2.4')
-        self.shares_v2_client.wait_for_cgsnapshot_status(cgsnapshot['id'],
-                                                         'deleting')
-        self.assertRaises(exceptions.Conflict,
-                          self.shares_v2_client.delete_cgsnapshot,
-                          cgsnapshot['id'],
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_delete_cg_not_in_available_or_error_v2_4(self):
-        consistency_group = self.create_consistency_group(
-            cleanup_in_class=False, version='2.4')
-        self.addCleanup(self.shares_v2_client.consistency_group_reset_state,
-                        consistency_group['id'],
-                        status='available',
-                        version='2.4')
-        # creating
-        self.shares_v2_client.consistency_group_reset_state(
-            consistency_group['id'], status='creating', version='2.4')
-        self.shares_v2_client.wait_for_consistency_group_status(
-            consistency_group['id'], 'creating')
-        self.assertRaises(exceptions.Conflict,
-                          self.shares_v2_client.delete_consistency_group,
-                          consistency_group['id'],
-                          version='2.4')
-        # deleting
-        self.shares_v2_client.consistency_group_reset_state(
-            consistency_group['id'], status='deleting', version='2.4')
-        self.shares_v2_client.wait_for_consistency_group_status(
-            consistency_group['id'], 'deleting')
-        self.assertRaises(exceptions.Conflict,
-                          self.shares_v2_client.delete_consistency_group,
-                          consistency_group['id'],
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_cg_with_conflicting_share_types_v2_4(self):
-        # Create conflicting share types
-        name = data_utils.rand_name("tempest-manila")
-        extra_specs = {"driver_handles_share_servers": False}
-        share_type = self.create_share_type(name, extra_specs=extra_specs)
-        single_tenant_share_type = share_type['share_type']
-
-        name = data_utils.rand_name("tempest-manila")
-        extra_specs = {"driver_handles_share_servers": True}
-        share_type = self.create_share_type(name, extra_specs=extra_specs)
-        multi_tenant_share_type = share_type['share_type']
-
-        self.assertRaises(exceptions.BadRequest,
-                          self.create_consistency_group,
-                          share_type_ids=[single_tenant_share_type['id'],
-                                          multi_tenant_share_type['id']],
-                          cleanup_in_class=False,
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_cg_with_multi_tenant_share_type_and_no_share_network_v2_4(
-            self):
-        # Create multi tenant share type
-        name = data_utils.rand_name("tempest-manila")
-        extra_specs = {"driver_handles_share_servers": True}
-        share_type = self.create_share_type(name, extra_specs=extra_specs)
-        multi_tenant_share_type = share_type['share_type']
-
-        def create_cg():
-            cg = self.shares_v2_client.create_consistency_group(
-                share_type_ids=[multi_tenant_share_type['id']],
-                version='2.4'
-            )
-            resource = {
-                "type": "consistency_group",
-                "id": cg["id"],
-                "client": self.shares_client
-            }
-            self.method_resources.insert(0, resource)
-            return cg
-
-        self.assertRaises(exceptions.BadRequest, create_cg)
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_update_cg_share_types(self):
-        consistency_group = self.create_consistency_group(
-            cleanup_in_class=False, version='2.4')
-
-        self.assertRaises(exceptions.BadRequest,
-                          self.shares_v2_client.update_consistency_group,
-                          consistency_group['id'],
-                          share_types=[self.share_type['id']],
-                          version='2.4')
diff --git a/manila_tempest_tests/tests/api/admin/test_share_group_types.py b/manila_tempest_tests/tests/api/admin/test_share_group_types.py
new file mode 100644
index 0000000..a6bda73
--- /dev/null
+++ b/manila_tempest_tests/tests/api/admin/test_share_group_types.py
@@ -0,0 +1,236 @@
+# Copyright 2016 Andrew Kerr
+# 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 config
+from tempest.lib.common.utils import data_utils
+import testtools
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import constants
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+
+
+@testtools.skipUnless(
+    CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
+class ShareGroupTypesTest(base.BaseSharesAdminTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareGroupTypesTest, cls).resource_setup()
+
+        # Create 2 share_types
+        name = data_utils.rand_name("tempest-manila")
+        extra_specs = cls.add_extra_specs_to_dict()
+        share_type = cls.create_share_type(name, extra_specs=extra_specs)
+        cls.share_type = share_type['share_type']
+
+        name = data_utils.rand_name("tempest-manila")
+        share_type = cls.create_share_type(name, extra_specs=extra_specs)
+        cls.share_type2 = share_type['share_type']
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_create_get_delete_share_group_type_min(self):
+        name = data_utils.rand_name("tempest-manila")
+
+        # Create share group type
+        sg_type_c = self.create_share_group_type(
+            name=name,
+            share_types=self.share_type['id'],
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        self.assertEqual(
+            [self.share_type['id']],
+            sg_type_c['share_types'],
+            'Share type not applied correctly.')
+
+        # Read share group type
+        sg_type_r = self.shares_v2_client.get_share_group_type(sg_type_c['id'])
+        keys = set(sg_type_r.keys())
+        self.assertTrue(
+            constants.SHARE_GROUP_TYPE_REQUIRED_KEYS.issubset(keys),
+            'At least one expected key missing from share group type '
+            'response. Expected %s, got %s.' % (
+                constants.SHARE_GROUP_TYPE_REQUIRED_KEYS, keys))
+        self.assertEqual(sg_type_c['name'], sg_type_r['name'])
+
+        # Delete share group type
+        self.shares_v2_client.delete_share_group_type(
+            sg_type_r['id'], version=constants.MIN_SHARE_GROUP_MICROVERSION)
+        self.shares_v2_client.wait_for_resource_deletion(
+            share_group_type_id=sg_type_r['id'])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_create_share_group_type_multiple_share_types_min(self):
+        name = data_utils.rand_name("tempest-manila")
+
+        sg_type = self.create_share_group_type(
+            name=name,
+            share_types=[self.share_type['id'], self.share_type2['id']],
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        self.assertEqual(
+            {self.share_type['id'], self.share_type2['id']},
+            set(sg_type['share_types']),
+            'Share types not applied correctly.')
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_create_share_group_type_with_one_spec_min(self):
+        name = data_utils.rand_name("tempest-manila")
+        group_specs = {'key': 'value'}
+
+        sg_type = self.create_share_group_type(
+            name=name,
+            share_types=self.share_type['id'],
+            group_specs=group_specs,
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        self.assertDictMatch(group_specs, sg_type['group_specs'])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_create_share_group_type_with_multiple_specs_min(self):
+        name = data_utils.rand_name("tempest-manila")
+        group_specs = {'key1': 'value1', 'key2': 'value2'}
+
+        sg_type = self.create_share_group_type(
+            name=name,
+            share_types=self.share_type['id'],
+            group_specs=group_specs,
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        self.assertDictMatch(group_specs, sg_type['group_specs'])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_update_single_share_group_type_spec_min(self):
+        name = data_utils.rand_name("tempest-manila")
+        group_specs = {'key1': 'value1', 'key2': 'value2'}
+
+        sg_type = self.create_share_group_type(
+            name=name,
+            share_types=self.share_type['id'],
+            group_specs=group_specs,
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        self.assertDictMatch(group_specs, sg_type['group_specs'])
+
+        group_specs = {'key1': 'value3', 'key2': 'value2'}
+
+        self.shares_v2_client.update_share_group_type_spec(
+            sg_type['id'], 'key1', 'value3')
+        sg_type = self.shares_v2_client.get_share_group_type(sg_type['id'])
+
+        self.assertDictMatch(group_specs, sg_type['group_specs'])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_update_all_share_group_type_specs_min(self):
+        name = data_utils.rand_name("tempest-manila")
+        group_specs = {'key1': 'value1', 'key2': 'value2'}
+
+        sg_type = self.create_share_group_type(
+            name=name,
+            share_types=self.share_type['id'],
+            group_specs=group_specs,
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        self.assertDictMatch(group_specs, sg_type['group_specs'])
+
+        group_specs = {'key1': 'value3', 'key2': 'value4'}
+
+        self.shares_v2_client.update_share_group_type_specs(
+            sg_type['id'], group_specs)
+        sg_type = self.shares_v2_client.get_share_group_type(sg_type['id'])
+
+        self.assertDictMatch(group_specs, sg_type['group_specs'])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_delete_single_share_group_type_spec_min(self):
+        name = data_utils.rand_name("tempest-manila")
+        group_specs = {'key1': 'value1', 'key2': 'value2'}
+
+        sg_type = self.create_share_group_type(
+            name=name,
+            share_types=self.share_type['id'],
+            group_specs=group_specs,
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        self.assertDictMatch(group_specs, sg_type['group_specs'])
+
+        key_to_delete = 'key1'
+        group_specs.pop(key_to_delete)
+
+        self.shares_v2_client.delete_share_group_type_spec(
+            sg_type['id'], key_to_delete)
+        sg_type = self.shares_v2_client.get_share_group_type(
+            sg_type['id'])
+
+        self.assertDictMatch(group_specs, sg_type['group_specs'])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_private_share_group_type_access(self):
+        name = data_utils.rand_name("tempest-manila")
+        group_specs = {"key1": "value1", "key2": "value2"}
+        project_id = self.shares_v2_client.tenant_id
+
+        # Create private share group type
+        sgt_create = self.create_share_group_type(
+            name=name,
+            share_types=[self.share_type['id']],
+            is_public=False,
+            group_specs=group_specs,
+        )
+        self.assertEqual(name, sgt_create['name'])
+        sgt_id = sgt_create["id"]
+
+        # It should not be listed without access
+        sgt_list = self.shares_v2_client.list_share_group_types()
+        self.assertFalse(any(sgt_id == sgt["id"] for sgt in sgt_list))
+
+        # List projects that have access for share group type - none expected
+        access = self.shares_v2_client.list_access_to_share_group_type(sgt_id)
+        self.assertEqual([], access)
+
+        # Add project access to share group type
+        access = self.shares_v2_client.add_access_to_share_group_type(
+            sgt_id, project_id)
+
+        # Now it should be listed
+        sgt_list = self.shares_v2_client.list_share_group_types()
+        self.assertTrue(any(sgt_id == sgt["id"] for sgt in sgt_list))
+
+        # List projects that have access for share group type - one expected
+        access = self.shares_v2_client.list_access_to_share_group_type(sgt_id)
+        expected = [{'share_group_type_id': sgt_id, 'project_id': project_id}]
+        self.assertEqual(expected, access)
+
+        # Remove project access from share group type
+        access = self.shares_v2_client.remove_access_from_share_group_type(
+            sgt_id, project_id)
+
+        # It should not be listed without access
+        sgt_list = self.shares_v2_client.list_share_group_types()
+        self.assertFalse(any(sgt_id == sgt["id"] for sgt in sgt_list))
+
+        # List projects that have access for share group type - none expected
+        access = self.shares_v2_client.list_access_to_share_group_type(sgt_id)
+        self.assertEqual([], access)
diff --git a/manila_tempest_tests/tests/api/admin/test_share_group_types_negative.py b/manila_tempest_tests/tests/api/admin/test_share_group_types_negative.py
new file mode 100644
index 0000000..e7f6824
--- /dev/null
+++ b/manila_tempest_tests/tests/api/admin/test_share_group_types_negative.py
@@ -0,0 +1,128 @@
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import exceptions as lib_exc
+import testtools
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import constants
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+
+
+@testtools.skipUnless(
+    CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
+class ShareGroupTypesAdminNegativeTest(base.BaseSharesMixedTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareGroupTypesAdminNegativeTest, cls).resource_setup()
+        cls.share_type = cls.create_share_type(
+            data_utils.rand_name("unique_st_name"),
+            extra_specs=cls.add_extra_specs_to_dict({"key": "value"}),
+            client=cls.admin_shares_v2_client)
+        cls.share_group_type = cls.create_share_group_type(
+            data_utils.rand_name("unique_sgt_name"),
+            share_types=[cls.share_type['share_type']['id']],
+            client=cls.admin_shares_v2_client)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_create_share_ggroup_with_nonexistent_share_type(self):
+        self.assertRaises(
+            lib_exc.BadRequest,
+            self.admin_shares_v2_client.create_share_group_type,
+            share_types=data_utils.rand_name("fake"))
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_create_share_group_type_with_empty_name(self):
+        self.assertRaises(
+            lib_exc.BadRequest,
+            self.create_share_group_type, '',
+            client=self.admin_shares_v2_client)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_create_share_group_type_with_too_big_name(self):
+        self.assertRaises(
+            lib_exc.BadRequest,
+            self.create_share_group_type,
+            "x" * 256, client=self.admin_shares_v2_client)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_get_share_group_type_using_nonexistent_id(self):
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.admin_shares_v2_client.get_share_group_type,
+            data_utils.rand_name("fake"))
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_try_delete_share_group_type_using_nonexistent_id(self):
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.admin_shares_v2_client.delete_share_group_type,
+            data_utils.rand_name("fake"))
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_try_create_duplicate_of_share_group_type(self):
+        unique_name = data_utils.rand_name("unique_sgt_name")
+        list_of_ids = set()
+        for step in (1, 2):
+            sg_type = self.create_share_group_type(
+                unique_name,
+                share_types=[self.share_type['share_type']['id']],
+                client=self.admin_shares_v2_client,
+                cleanup_in_class=False)
+            self.assertRaises(
+                lib_exc.Conflict,
+                self.create_share_group_type,
+                unique_name,
+                share_types=[self.share_type['share_type']['id']],
+                client=self.admin_shares_v2_client)
+            list_of_ids.add(sg_type['id'])
+            self.assertEqual(unique_name,  sg_type['name'])
+            self.admin_shares_v2_client.delete_share_group_type(sg_type['id'])
+        self.assertEqual(2, len(list_of_ids))
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_add_project_access_to_public_share_group_type(self):
+        self.assertRaises(
+            lib_exc.Conflict,
+            self.admin_shares_v2_client.add_access_to_share_group_type,
+            self.share_group_type["id"],
+            self.admin_shares_v2_client.tenant_id)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_remove_project_access_from_public_share_group_type(self):
+        self.assertRaises(
+            lib_exc.Conflict,
+            self.admin_shares_v2_client.remove_access_from_share_group_type,
+            self.share_group_type["id"],
+            self.admin_shares_v2_client.tenant_id)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_add_project_access_to_nonexistent_share_group_type(self):
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.admin_shares_v2_client.add_access_to_share_group_type,
+            data_utils.rand_name("fake"),
+            self.admin_shares_v2_client.tenant_id)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
+    def test_remove_project_access_from_nonexistent_share_group_type(self):
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.admin_shares_v2_client.remove_access_from_share_group_type,
+            data_utils.rand_name("fake"),
+            self.admin_shares_v2_client.tenant_id)
diff --git a/manila_tempest_tests/tests/api/admin/test_share_groups.py b/manila_tempest_tests/tests/api/admin/test_share_groups.py
new file mode 100644
index 0000000..e289005
--- /dev/null
+++ b/manila_tempest_tests/tests/api/admin/test_share_groups.py
@@ -0,0 +1,175 @@
+# Copyright 2016 Andrew Kerr
+# 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 config
+from tempest.lib.common.utils import data_utils
+import testtools
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import constants
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+
+
+@testtools.skipUnless(
+    CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
+class ShareGroupsTest(base.BaseSharesAdminTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareGroupsTest, cls).resource_setup()
+        # Create 2 share_types
+        name = data_utils.rand_name("tempest-manila")
+        extra_specs = cls.add_extra_specs_to_dict()
+        share_type = cls.create_share_type(name, extra_specs=extra_specs)
+        cls.share_type = share_type['share_type']
+
+        name = data_utils.rand_name("tempest-manila")
+        share_type = cls.create_share_type(name, extra_specs=extra_specs)
+        cls.share_type2 = share_type['share_type']
+
+        cls.sg_type = cls.create_share_group_type(
+            name=name,
+            share_types=[cls.share_type['id'], cls.share_type2['id']],
+            cleanup_in_class=True,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_create_share_group_with_single_share_type_min(self):
+        share_group = self.create_share_group(
+            share_group_type_id=self.sg_type['id'],
+            cleanup_in_class=False,
+            share_type_ids=[self.share_type['id']],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        keys = set(share_group.keys())
+        self.assertTrue(
+            constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(keys),
+            'At least one expected element missing from share group '
+            'response. Expected %(expected)s, got %(actual)s.' % {
+                "expected": constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
+                "actual": keys})
+
+        actual_sg_type = share_group['share_group_type_id']
+        expected_sg_type = self.sg_type['id']
+        self.assertEqual(
+            expected_sg_type, actual_sg_type,
+            'Incorrect share group type applied to share group '
+            '%s. Expected %s, got %s' % (
+                share_group['id'], expected_sg_type, actual_sg_type))
+
+        actual_share_types = share_group['share_types']
+        expected_share_types = [self.share_type['id']]
+        self.assertEqual(
+            sorted(expected_share_types),
+            sorted(actual_share_types),
+            'Incorrect share types applied to share group %s. '
+            'Expected %s, got %s' % (
+                share_group['id'], expected_share_types, actual_share_types))
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_create_share_group_with_multiple_share_types_min(self):
+        share_group = self.create_share_group(
+            share_group_type_id=self.sg_type['id'],
+            cleanup_in_class=False,
+            share_type_ids=[self.share_type['id'], self.share_type2['id']],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        keys = set(share_group.keys())
+        self.assertTrue(
+            constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(keys),
+            'At least one expected element missing from share group '
+            'response. Expected %(expected)s, got %(actual)s.' % {
+                "expected": constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
+                "actual": keys})
+
+        actual_sg_type = share_group['share_group_type_id']
+        expected_sg_type = self.sg_type['id']
+        self.assertEqual(
+            expected_sg_type, actual_sg_type,
+            'Incorrect share group type applied to share group %s. '
+            'Expected %s, got %s' % (
+                share_group['id'], expected_sg_type, actual_sg_type))
+
+        actual_share_types = share_group['share_types']
+        expected_share_types = [self.share_type['id'], self.share_type2['id']]
+        self.assertEqual(
+            sorted(expected_share_types),
+            sorted(actual_share_types),
+            'Incorrect share types applied to share group %s. '
+            'Expected %s, got %s' % (
+                share_group['id'], expected_share_types, actual_share_types))
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_default_share_group_type_applied(self):
+        default_type = self.shares_v2_client.get_default_share_group_type()
+        default_share_types = default_type['share_types']
+
+        share_group = self.create_share_group(
+            cleanup_in_class=False,
+            share_type_ids=default_share_types,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        keys = set(share_group.keys())
+        self.assertTrue(
+            constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(keys),
+            'At least one expected element missing from share group '
+            'response. Expected %(expected)s, got %(actual)s.' % {
+                "expected": constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
+                "actual": keys})
+
+        actual_sg_type = share_group['share_group_type_id']
+        expected_sg_type = default_type['id']
+        self.assertEqual(
+            expected_sg_type, actual_sg_type,
+            'Incorrect share group type applied to share group %s. '
+            'Expected %s, got %s' % (
+                share_group['id'], expected_sg_type, actual_sg_type))
+
+    @testtools.skipUnless(
+        CONF.share.multitenancy_enabled, "Only for multitenancy.")
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    def test_create_sg_from_snapshot_verify_share_server_information_min(self):
+        # Create a share group
+        orig_sg = self.create_share_group(
+            share_group_type_id=self.sg_type['id'],
+            cleanup_in_class=False,
+            share_type_ids=[self.share_type['id']],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        # Get latest share group information
+        orig_sg = self.shares_v2_client.get_share_group(
+            orig_sg['id'], version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        # Assert share server information
+        self.assertIsNotNone(orig_sg['share_network_id'])
+        self.assertIsNotNone(orig_sg['share_server_id'])
+
+        sg_snapshot = self.create_share_group_snapshot_wait_for_active(
+            orig_sg['id'], cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+        new_sg = self.create_share_group(
+            share_group_type_id=self.sg_type['id'],
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+            source_share_group_snapshot_id=sg_snapshot['id'])
+
+        # Assert share server information
+        self.assertEqual(
+            orig_sg['share_network_id'], new_sg['share_network_id'])
+        self.assertEqual(
+            orig_sg['share_server_id'], new_sg['share_server_id'])
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index 48cd3ed..7837195 100644
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -392,7 +392,7 @@
     def _create_share(cls, share_protocol=None, size=None, name=None,
                       snapshot_id=None, description=None, metadata=None,
                       share_network_id=None, share_type_id=None,
-                      consistency_group_id=None, client=None,
+                      share_group_id=None, client=None,
                       cleanup_in_class=True, is_public=False, **kwargs):
         client = client or cls.shares_v2_client
         description = description or "Tempest's share"
@@ -410,12 +410,12 @@
             'share_type_id': share_type_id,
             'is_public': is_public,
         })
-        if consistency_group_id:
-            kwargs['consistency_group_id'] = consistency_group_id
+        if share_group_id:
+            kwargs['share_group_id'] = share_group_id
 
         share = client.create_share(**kwargs)
         resource = {"type": "share", "id": share["id"], "client": client,
-                    "consistency_group_id": consistency_group_id}
+                    "share_group_id": share_group_id}
         cleanup_list = (cls.class_resources if cleanup_in_class else
                         cls.method_resources)
         cleanup_list.insert(0, resource)
@@ -540,41 +540,63 @@
         return [d["share"] for d in data]
 
     @classmethod
-    def create_consistency_group(cls, client=None, cleanup_in_class=True,
-                                 share_network_id=None, **kwargs):
+    def create_share_group(cls, client=None, cleanup_in_class=True,
+                           share_network_id=None, **kwargs):
         client = client or cls.shares_v2_client
-        if kwargs.get('source_cgsnapshot_id') is None:
+        if kwargs.get('source_share_group_snapshot_id') is None:
             kwargs['share_network_id'] = (share_network_id or
                                           client.share_network_id or None)
-        consistency_group = client.create_consistency_group(**kwargs)
+        share_group = client.create_share_group(**kwargs)
         resource = {
-            "type": "consistency_group",
-            "id": consistency_group["id"],
-            "client": client}
+            "type": "share_group",
+            "id": share_group["id"],
+            "client": client,
+        }
         if cleanup_in_class:
             cls.class_resources.insert(0, resource)
         else:
             cls.method_resources.insert(0, resource)
 
-        if kwargs.get('source_cgsnapshot_id'):
-            new_cg_shares = client.list_shares(
+        if kwargs.get('source_share_group_snapshot_id'):
+            new_share_group_shares = client.list_shares(
                 detailed=True,
-                params={'consistency_group_id': consistency_group['id']})
+                params={'share_group_id': share_group['id']},
+                experimental=True)
 
-            for share in new_cg_shares:
+            for share in new_share_group_shares:
                 resource = {"type": "share",
                             "id": share["id"],
                             "client": client,
-                            "consistency_group_id": share.get(
-                                'consistency_group_id')}
+                            "share_group_id": share.get("share_group_id")}
                 if cleanup_in_class:
                     cls.class_resources.insert(0, resource)
                 else:
                     cls.method_resources.insert(0, resource)
 
-        client.wait_for_consistency_group_status(consistency_group['id'],
-                                                 'available')
-        return consistency_group
+        client.wait_for_share_group_status(share_group['id'], 'available')
+        return share_group
+
+    @classmethod
+    def create_share_group_type(cls, name=None, share_types=(), is_public=None,
+                                group_specs=None, client=None,
+                                cleanup_in_class=True, **kwargs):
+        client = client or cls.shares_v2_client
+        share_group_type = client.create_share_group_type(
+            name=name,
+            share_types=share_types,
+            is_public=is_public,
+            group_specs=group_specs,
+            **kwargs)
+        resource = {
+            "type": "share_group_type",
+            "id": share_group_type["id"],
+            "client": client,
+        }
+        if cleanup_in_class:
+            cls.class_resources.insert(0, resource)
+        else:
+            cls.method_resources.insert(0, resource)
+        return share_group_type
 
     @classmethod
     def create_snapshot_wait_for_active(cls, share_id, name=None,
@@ -598,28 +620,26 @@
         return snapshot
 
     @classmethod
-    def create_cgsnapshot_wait_for_active(cls, consistency_group_id,
-                                          name=None, description=None,
-                                          client=None, cleanup_in_class=True,
-                                          **kwargs):
+    def create_share_group_snapshot_wait_for_active(
+            cls, share_group_id, name=None, description=None, client=None,
+            cleanup_in_class=True, **kwargs):
         client = client or cls.shares_v2_client
         if description is None:
-            description = "Tempest's cgsnapshot"
-        cgsnapshot = client.create_cgsnapshot(consistency_group_id,
-                                              name=name,
-                                              description=description,
-                                              **kwargs)
+            description = "Tempest's share group snapshot"
+        sg_snapshot = client.create_share_group_snapshot(
+            share_group_id, name=name, description=description, **kwargs)
         resource = {
-            "type": "cgsnapshot",
-            "id": cgsnapshot["id"],
+            "type": "share_group_snapshot",
+            "id": sg_snapshot["id"],
             "client": client,
         }
         if cleanup_in_class:
             cls.class_resources.insert(0, resource)
         else:
             cls.method_resources.insert(0, resource)
-        client.wait_for_cgsnapshot_status(cgsnapshot["id"], "available")
-        return cgsnapshot
+        client.wait_for_share_group_snapshot_status(
+            sg_snapshot["id"], "available")
+        return sg_snapshot
 
     @classmethod
     def get_availability_zones(cls, client=None):
@@ -800,7 +820,6 @@
 
         :param resources: dict with keys 'type','id','client' and 'deleted'
         """
-
         if resources is None:
             resources = cls.method_resources
         for res in resources:
@@ -814,9 +833,9 @@
                 with handle_cleanup_exceptions():
                     if res["type"] is "share":
                         cls.clear_share_replicas(res_id)
-                        cg_id = res.get('consistency_group_id')
-                        if cg_id:
-                            params = {'consistency_group_id': cg_id}
+                        share_group_id = res.get('share_group_id')
+                        if share_group_id:
+                            params = {'share_group_id': share_group_id}
                             client.delete_share(res_id, params=params)
                         else:
                             client.delete_share(res_id)
@@ -833,12 +852,18 @@
                     elif res["type"] is "share_type":
                         client.delete_share_type(res_id)
                         client.wait_for_resource_deletion(st_id=res_id)
-                    elif res["type"] is "consistency_group":
-                        client.delete_consistency_group(res_id)
-                        client.wait_for_resource_deletion(cg_id=res_id)
-                    elif res["type"] is "cgsnapshot":
-                        client.delete_cgsnapshot(res_id)
-                        client.wait_for_resource_deletion(cgsnapshot_id=res_id)
+                    elif res["type"] is "share_group":
+                        client.delete_share_group(res_id)
+                        client.wait_for_resource_deletion(
+                            share_group_id=res_id)
+                    elif res["type"] is "share_group_type":
+                        client.delete_share_group_type(res_id)
+                        client.wait_for_resource_deletion(
+                            share_group_type_id=res_id)
+                    elif res["type"] is "share_group_snapshot":
+                        client.delete_share_group_snapshot(res_id)
+                        client.wait_for_resource_deletion(
+                            share_group_snapshot_id=res_id)
                     elif res["type"] is "share_replica":
                         client.delete_share_replica(res_id)
                         client.wait_for_resource_deletion(replica_id=res_id)
diff --git a/manila_tempest_tests/tests/api/test_consistency_group_actions.py b/manila_tempest_tests/tests/api/test_consistency_group_actions.py
deleted file mode 100644
index 7a7c54d..0000000
--- a/manila_tempest_tests/tests/api/test_consistency_group_actions.py
+++ /dev/null
@@ -1,377 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright 2015 Andrew Kerr
-# 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 config
-from tempest.lib.common.utils import data_utils
-import testtools
-from testtools import testcase as tc
-
-from manila_tempest_tests.tests.api import base
-
-CONF = config.CONF
-
-CG_SIMPLE_KEYS = {"id", "name", "links"}
-CG_DETAIL_REQUIRED_KEYS = {"id", "name", "description", "created_at", "status",
-                           "project_id", "host", "links"}
-CGSNAPSHOT_SIMPLE_KEYS = {"id", "name", "links"}
-CGSNAPSHOT_DETAIL_REQUIRED_KEYS = {"id", "name", "description", "created_at",
-                                   "status", "project_id", "links"}
-
-
-@testtools.skipUnless(CONF.share.run_consistency_group_tests,
-                      'Consistency Group tests disabled.')
-class ConsistencyGroupActionsTest(base.BaseSharesTest):
-    """Covers consistency group functionality."""
-
-    @classmethod
-    def resource_setup(cls):
-        super(ConsistencyGroupActionsTest, cls).resource_setup()
-
-        # Create first consistency group
-        cls.cg_name = data_utils.rand_name("tempest-cg-name")
-        cls.cg_desc = data_utils.rand_name("tempest-cg-description")
-        cls.cg = cls.create_consistency_group(
-            name=cls.cg_name, description=cls.cg_desc)
-
-        # Create second consistency group for purposes of sorting and snapshot
-        # filtering
-        cls.cg2 = cls.create_consistency_group(
-            name=cls.cg_name, description=cls.cg_desc)
-
-        # Create 2 shares inside first CG and 1 inside second CG
-        cls.share_name = data_utils.rand_name("tempest-share-name")
-        cls.share_desc = data_utils.rand_name("tempest-share-description")
-        cls.share_size = CONF.share.share_size
-        cls.share_size2 = cls.share_size + 1
-        cls.shares = cls.create_shares([
-            {'kwargs': {
-                'name': cls.share_name,
-                'description': cls.share_desc,
-                'size': size,
-                'consistency_group_id': cg_id,
-            }} for size, cg_id in ((cls.share_size, cls.cg['id']),
-                                   (cls.share_size2, cls.cg['id']),
-                                   (cls.share_size, cls.cg2['id']))
-        ])
-
-        # Create CG snapshots
-        cls.cgsnap_name = data_utils.rand_name("tempest-cgsnap-name")
-        cls.cgsnap_desc = data_utils.rand_name("tempest-cgsnap-description")
-
-        cls.cgsnapshot = cls.create_cgsnapshot_wait_for_active(
-            cls.cg["id"],
-            name=cls.cgsnap_name,
-            description=cls.cgsnap_desc)
-
-        cls.cgsnapshot2 = cls.create_cgsnapshot_wait_for_active(
-            cls.cg2['id'], name=cls.cgsnap_name, description=cls.cgsnap_desc)
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_get_consistency_group_v2_4(self):
-
-        # Get consistency group
-        consistency_group = self.shares_v2_client.get_consistency_group(
-            self.cg['id'], version='2.4')
-
-        # Verify keys
-        actual_keys = set(consistency_group.keys())
-        self.assertTrue(CG_DETAIL_REQUIRED_KEYS.issubset(actual_keys),
-                        'Not all required keys returned for consistency '
-                        'group %s.  Expected at least: %s, found %s' % (
-                            consistency_group['id'],
-                            CG_DETAIL_REQUIRED_KEYS,
-                            actual_keys))
-
-        # Verify values
-        msg = "Expected name: '%s', actual name: '%s'" % (
-            self.cg_name, consistency_group["name"])
-        self.assertEqual(self.cg_name, str(consistency_group["name"]), msg)
-
-        msg = "Expected description: '%s', actual description: '%s'" % (
-            self.cg_desc, consistency_group["description"])
-        self.assertEqual(self.cg_desc, str(consistency_group["description"]),
-                         msg)
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_get_share_v2_4(self):
-
-        # Get share
-        share = self.shares_v2_client.get_share(self.shares[0]['id'],
-                                                version='2.4')
-
-        # Verify keys
-        expected_keys = {"status", "description", "links", "availability_zone",
-                         "created_at", "export_location", "share_proto",
-                         "name", "snapshot_id", "id", "size",
-                         "consistency_group_id"}
-        actual_keys = set(share.keys())
-        self.assertTrue(expected_keys.issubset(actual_keys),
-                        'Not all required keys returned for share %s.  '
-                        'Expected at least: %s, found %s' % (share['id'],
-                                                             expected_keys,
-                                                             actual_keys))
-
-        # Verify values
-        msg = "Expected name: '%s', actual name: '%s'" % (self.share_name,
-                                                          share["name"])
-        self.assertEqual(self.share_name, str(share["name"]), msg)
-
-        msg = "Expected description: '%s', actual description: '%s'" % (
-            self.share_desc, share["description"])
-        self.assertEqual(self.share_desc, str(share["description"]), msg)
-
-        msg = "Expected size: '%s', actual size: '%s'" % (self.share_size,
-                                                          share["size"])
-        self.assertEqual(self.share_size, int(share["size"]), msg)
-
-        msg = "Expected consistency_group_id: '%s', actual value: '%s'" % (
-            self.cg["id"], share["consistency_group_id"])
-        self.assertEqual(self.cg["id"], share["consistency_group_id"], msg)
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_list_consistency_groups_v2_4(self):
-
-        # List consistency groups
-        consistency_groups = self.shares_v2_client.list_consistency_groups(
-            version='2.4')
-
-        # Verify keys
-        [self.assertEqual(CG_SIMPLE_KEYS, set(cg.keys())) for cg in
-         consistency_groups]
-
-        # Consistency group ids are in list exactly once
-        for cg_id in (self.cg["id"], self.cg2["id"]):
-            gen = [cgid["id"] for cgid in consistency_groups
-                   if cgid["id"] == cg_id]
-            msg = ("Expected id %s exactly once in consistency group list" %
-                   cg_id)
-            self.assertEqual(1, len(gen), msg)
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_list_consistency_groups_with_detail_v2_4(self):
-
-        # List consistency groups
-        consistency_groups = self.shares_v2_client.list_consistency_groups(
-            detailed=True, version='2.4')
-
-        # Verify keys
-        [self.assertTrue(CG_DETAIL_REQUIRED_KEYS.issubset(set(cg.keys())))
-         for cg in consistency_groups]
-
-        # Consistency group ids are in list exactly once
-        for cg_id in (self.cg["id"], self.cg2["id"]):
-            gen = [cgid["id"] for cgid in consistency_groups
-                   if cgid["id"] == cg_id]
-            msg = ("Expected id %s exactly once in consistency group list" %
-                   cg_id)
-            self.assertEqual(1, len(gen), msg)
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_filter_shares_by_consistency_group_id_v2_4(self):
-
-        shares = self.shares_v2_client.list_shares(
-            detailed=True,
-            params={'consistency_group_id': self.cg['id']},
-            version='2.4'
-        )
-
-        share_ids = [share['id'] for share in shares]
-
-        self.assertEqual(2, len(shares),
-                         'Incorrect number of shares returned. Expected 2, '
-                         'got %s' % len(shares))
-        self.assertIn(self.shares[0]['id'], share_ids,
-                      'Share %s expected in returned list, but got %s'
-                      % (self.shares[0]['id'], share_ids))
-        self.assertIn(self.shares[1]['id'], share_ids,
-                      'Share %s expected in returned list, but got %s'
-                      % (self.shares[0]['id'], share_ids))
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_get_cgsnapshot_v2_4(self):
-
-        # Get consistency group
-        consistency_group = self.shares_v2_client.get_consistency_group(
-            self.cg['id'], version='2.4')
-
-        # Verify keys
-        actual_keys = set(consistency_group.keys())
-        self.assertTrue(CG_DETAIL_REQUIRED_KEYS.issubset(actual_keys),
-                        'Not all required keys returned for consistency '
-                        'group %s.  Expected at least: %s, found %s' % (
-                            consistency_group['id'],
-                            CG_DETAIL_REQUIRED_KEYS,
-                            actual_keys))
-
-        # Verify values
-        msg = "Expected name: '%s', actual name: '%s'" % (
-            self.cg_name, consistency_group["name"])
-        self.assertEqual(self.cg_name, str(consistency_group["name"]), msg)
-
-        msg = "Expected description: '%s', actual description: '%s'" % (
-            self.cg_desc, consistency_group["description"])
-        self.assertEqual(self.cg_desc, str(consistency_group["description"]),
-                         msg)
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_get_cgsnapshot_members_v2_4(self):
-
-        cgsnapshot_members = self.shares_v2_client.list_cgsnapshot_members(
-            self.cgsnapshot['id'], version='2.4')
-        member_share_ids = [member['share_id'] for member in
-                            cgsnapshot_members]
-        self.assertEqual(2, len(cgsnapshot_members),
-                         'Unexpected number of cgsnapshot members. Expected '
-                         '2, got %s.' % len(cgsnapshot_members))
-        # Verify each share is represented in the cgsnapshot appropriately
-        for share_id in (self.shares[0]['id'], self.shares[1]['id']):
-            self.assertIn(share_id, member_share_ids,
-                          'Share missing %s missing from cgsnapshot. Found %s.'
-                          % (share_id, member_share_ids))
-        for share in (self.shares[0], self.shares[1]):
-            for member in cgsnapshot_members:
-                if share['id'] == member['share_id']:
-                    self.assertEqual(share['size'], member['size'])
-                    self.assertEqual(share['share_proto'],
-                                     member['share_protocol'])
-                    # TODO(akerr): Add back assert when bug 1483886 is fixed
-                    # self.assertEqual(share['share_type'],
-                    #                  member['share_type_id'])
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
-    def test_create_consistency_group_from_populated_cgsnapshot_v2_4(self):
-
-        cgsnapshot_members = self.shares_v2_client.list_cgsnapshot_members(
-            self.cgsnapshot['id'], version='2.4')
-
-        new_consistency_group = self.create_consistency_group(
-            cleanup_in_class=False,
-            source_cgsnapshot_id=self.cgsnapshot['id'],
-            version='2.4'
-        )
-
-        new_consistency_group = self.shares_v2_client.get_consistency_group(
-            new_consistency_group['id'], version='2.4')
-
-        # Verify that share_network information matches source CG
-        self.assertEqual(self.cg['share_network_id'],
-                         new_consistency_group['share_network_id'])
-
-        new_shares = self.shares_v2_client.list_shares(
-            params={'consistency_group_id': new_consistency_group['id']},
-            detailed=True,
-            version='2.4'
-        )
-
-        # Verify each new share is available
-        for share in new_shares:
-            self.assertEqual('available', share['status'],
-                             'Share %s is not in available status.'
-                             % share['id'])
-
-        # Verify each cgsnapshot member is represented in the new cg
-        # appropriately
-        share_source_member_ids = [share['source_cgsnapshot_member_id'] for
-                                   share in new_shares]
-        for member in cgsnapshot_members:
-            self.assertIn(member['id'], share_source_member_ids,
-                          'cgsnapshot member %s not represented by '
-                          'consistency group %s.' % (
-                              member['id'], new_consistency_group['id']))
-            for share in new_shares:
-                if share['source_cgsnapshot_member_id'] == member['id']:
-                    self.assertEqual(member['size'], share['size'])
-                    self.assertEqual(member['share_protocol'],
-                                     share['share_proto'])
-                    # TODO(akerr): Add back assert when bug 1483886 is fixed
-                    # self.assertEqual(member['share_type_id'],
-                    #                  share['share_type'])
-                    self.assertEqual(self.cg['share_network_id'],
-                                     share['share_network_id'])
-
-
-@testtools.skipUnless(CONF.share.run_consistency_group_tests,
-                      'Consistency Group tests disabled.')
-class ConsistencyGroupRenameTest(base.BaseSharesTest):
-
-    @classmethod
-    def resource_setup(cls):
-        super(ConsistencyGroupRenameTest, cls).resource_setup()
-
-        # Create consistency group
-        cls.cg_name = data_utils.rand_name("tempest-cg-name")
-        cls.cg_desc = data_utils.rand_name("tempest-cg-description")
-        cls.consistency_group = cls.create_consistency_group(
-            name=cls.cg_name,
-            description=cls.cg_desc,
-        )
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_update_consistency_group_v2_4(self):
-
-        # Get consistency_group
-        consistency_group = self.shares_v2_client.get_consistency_group(
-            self.consistency_group['id'], version='2.4')
-        self.assertEqual(self.cg_name, consistency_group["name"])
-        self.assertEqual(self.cg_desc, consistency_group["description"])
-
-        # Update consistency_group
-        new_name = data_utils.rand_name("tempest-new-name")
-        new_desc = data_utils.rand_name("tempest-new-description")
-        updated = self.shares_v2_client.update_consistency_group(
-            consistency_group["id"],
-            name=new_name,
-            description=new_desc,
-            version='2.4'
-        )
-        self.assertEqual(new_name, updated["name"])
-        self.assertEqual(new_desc, updated["description"])
-
-        # Get consistency_group
-        consistency_group = self.shares_v2_client.get_consistency_group(
-            self.consistency_group['id'], version='2.4')
-        self.assertEqual(new_name, consistency_group["name"])
-        self.assertEqual(new_desc, consistency_group["description"])
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_update_read_consistency_group_with_unicode_v2_4(self):
-        value1 = u'ಠ_ಠ'
-        value2 = u'ಠ_ರೃ'
-        # Create consistency_group
-        consistency_group = self.create_consistency_group(
-            cleanup_in_class=False,
-            name=value1,
-            description=value1,
-            version='2.4'
-        )
-        self.assertEqual(value1, consistency_group["name"])
-        self.assertEqual(value1, consistency_group["description"])
-
-        # Update consistency_group
-        updated = self.shares_v2_client.update_consistency_group(
-            consistency_group["id"],
-            name=value2,
-            description=value2,
-            version='2.4'
-        )
-        self.assertEqual(value2, updated["name"])
-        self.assertEqual(value2, updated["description"])
-
-        # Get consistency_group
-        consistency_group = self.shares_v2_client.get_consistency_group(
-            consistency_group['id'], version='2.4')
-        self.assertEqual(value2, consistency_group["name"])
-        self.assertEqual(value2, consistency_group["description"])
diff --git a/manila_tempest_tests/tests/api/test_consistency_groups.py b/manila_tempest_tests/tests/api/test_consistency_groups.py
deleted file mode 100644
index 8f141da..0000000
--- a/manila_tempest_tests/tests/api/test_consistency_groups.py
+++ /dev/null
@@ -1,144 +0,0 @@
-# Copyright 2015 Andrew Kerr
-# 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 config
-from tempest.lib import exceptions as lib_exc
-import testtools
-from testtools import testcase as tc
-
-from manila_tempest_tests.tests.api import base
-
-CONF = config.CONF
-CG_REQUIRED_ELEMENTS = {"id", "name", "description", "created_at", "status",
-                        "share_types", "project_id", "host", "links"}
-CGSNAPSHOT_REQUIRED_ELEMENTS = {"id", "name", "description", "created_at",
-                                "status", "project_id", "links"}
-
-
-@testtools.skipUnless(CONF.share.run_consistency_group_tests,
-                      'Consistency Group tests disabled.')
-class ConsistencyGroupsTest(base.BaseSharesTest):
-    """Covers consistency group functionality."""
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_BACKEND)
-    def test_create_populate_delete_consistency_group_v2_4(self):
-        # Create a consistency group
-        consistency_group = self.create_consistency_group(
-            cleanup_in_class=False, version='2.4')
-        self.assertTrue(CG_REQUIRED_ELEMENTS.issubset(
-            consistency_group.keys()),
-            'At least one expected element missing from consistency group '
-            'response. Expected %(expected)s, got %(actual)s.' % {
-                "expected": CG_REQUIRED_ELEMENTS,
-                "actual": consistency_group.keys()})
-        # Populate
-        share = self.create_share(consistency_group_id=consistency_group['id'],
-                                  cleanup_in_class=False,
-                                  version='2.4')
-        # Delete
-        params = {"consistency_group_id": consistency_group['id']}
-        self.shares_v2_client.delete_share(share['id'], params=params,
-                                           version='2.4')
-        self.shares_client.wait_for_resource_deletion(share_id=share['id'])
-        self.shares_v2_client.delete_consistency_group(consistency_group['id'],
-                                                       version='2.4')
-        self.shares_v2_client.wait_for_resource_deletion(
-            cg_id=consistency_group['id'])
-
-        # Verify
-        self.assertRaises(lib_exc.NotFound,
-                          self.shares_v2_client.get_consistency_group,
-                          consistency_group['id'])
-        self.assertRaises(lib_exc.NotFound,
-                          self.shares_client.get_share,
-                          share['id'])
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_delete_empty_cgsnapshot_v2_4(self):
-        # Create base consistency group
-        consistency_group = self.create_consistency_group(
-            cleanup_in_class=False, version='2.4')
-        # Create cgsnapshot
-        cgsnapshot = self.create_cgsnapshot_wait_for_active(
-            consistency_group["id"], cleanup_in_class=False, version='2.4')
-
-        self.assertTrue(CGSNAPSHOT_REQUIRED_ELEMENTS.issubset(
-            cgsnapshot.keys()),
-            'At least one expected element missing from cgsnapshot response. '
-            'Expected %(expected)s, got %(actual)s.' % {
-                "expected": CGSNAPSHOT_REQUIRED_ELEMENTS,
-                "actual": cgsnapshot.keys()})
-
-        cgsnapshot_members = self.shares_v2_client.list_cgsnapshot_members(
-            cgsnapshot['id'], version='2.4')
-
-        self.assertEmpty(cgsnapshot_members,
-                         'Expected 0 cgsnapshot members, got %s' % len(
-                             cgsnapshot_members))
-
-        # delete snapshot
-        self.shares_v2_client.delete_cgsnapshot(cgsnapshot["id"],
-                                                version='2.4')
-        self.shares_v2_client.wait_for_resource_deletion(
-            cgsnapshot_id=cgsnapshot["id"])
-        self.assertRaises(lib_exc.NotFound,
-                          self.shares_v2_client.get_cgsnapshot,
-                          cgsnapshot['id'],
-                          version='2.4')
-
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_consistency_group_from_empty_cgsnapshot(self):
-        # Create base consistency group
-        consistency_group = self.create_consistency_group(
-            cleanup_in_class=False)
-
-        # Create cgsnapshot
-        cgsnapshot = self.create_cgsnapshot_wait_for_active(
-            consistency_group["id"], cleanup_in_class=False)
-
-        cgsnapshot_members = self.shares_v2_client.list_cgsnapshot_members(
-            cgsnapshot['id'])
-
-        self.assertEmpty(cgsnapshot_members,
-                         'Expected 0 cgsnapshot members, got %s' % len(
-                             cgsnapshot_members))
-
-        new_consistency_group = self.create_consistency_group(
-            cleanup_in_class=False, source_cgsnapshot_id=cgsnapshot['id'])
-
-        new_shares = self.shares_client.list_shares(
-            params={'consistency_group_id': new_consistency_group['id']})
-
-        self.assertEmpty(new_shares,
-                         'Expected 0 new shares, got %s' % len(new_shares))
-
-        msg = 'Expected cgsnapshot_id %s as source of consistency group %s' % (
-            cgsnapshot['id'], new_consistency_group['source_cgsnapshot_id'])
-        self.assertEqual(new_consistency_group['source_cgsnapshot_id'],
-                         cgsnapshot['id'], msg)
-
-        msg = ('Unexpected share_types on new consistency group. Expected '
-               '%s, got %s.' % (consistency_group['share_types'],
-                                new_consistency_group['share_types']))
-        self.assertEqual(sorted(consistency_group['share_types']),
-                         sorted(new_consistency_group['share_types']), msg)
-
-        # Assert the share_network information is the same
-        msg = 'Expected share_network %s as share_network of cg %s' % (
-            consistency_group['share_network_id'],
-            new_consistency_group['share_network_id'])
-        self.assertEqual(consistency_group['share_network_id'],
-                         new_consistency_group['share_network_id'],
-                         msg)
diff --git a/manila_tempest_tests/tests/api/test_consistency_groups_negative.py b/manila_tempest_tests/tests/api/test_consistency_groups_negative.py
deleted file mode 100644
index 9c38a2b..0000000
--- a/manila_tempest_tests/tests/api/test_consistency_groups_negative.py
+++ /dev/null
@@ -1,226 +0,0 @@
-# Copyright 2015 Andrew Kerr
-# 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 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
-
-CONF = config.CONF
-
-
-@testtools.skipUnless(CONF.share.run_consistency_group_tests,
-                      'Consistency Group tests disabled.')
-class ConsistencyGroupsAPIOnlyNegativeTest(base.BaseSharesTest):
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_delete_cg_without_passing_cg_id_v2_4(self):
-        self.assertRaises(lib_exc.NotFound,
-                          self.shares_v2_client.delete_consistency_group,
-                          '',
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_delete_cg_with_wrong_id_v2_4(self):
-        self.assertRaises(lib_exc.NotFound,
-                          self.shares_v2_client.delete_consistency_group,
-                          "wrong_consistency_group_id",
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_update_cg_with_wrong_id_v2_4(self):
-        self.assertRaises(lib_exc.NotFound,
-                          self.shares_v2_client.update_consistency_group,
-                          'wrong_consistency_group_id',
-                          name='new_name',
-                          description='new_description',
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_get_cg_without_passing_cg_id_v2_4(self):
-        self.assertRaises(lib_exc.NotFound,
-                          self.shares_v2_client.get_consistency_group,
-                          '',
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_filter_shares_on_invalid_cg_id_v2_4(self):
-        shares = self.shares_v2_client.list_shares(
-            detailed=True,
-            params={'consistency_group_id': 'foobar'},
-            version='2.4',
-        )
-
-        self.assertEqual(0, len(shares),
-                         'Incorrect number of shares returned. Expected 0, '
-                         'got %s.' % len(shares))
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_create_cgsnapshot_with_invalid_cg_id_value_v2_4(self):
-        self.assertRaises(lib_exc.BadRequest,
-                          self.create_cgsnapshot_wait_for_active,
-                          'foobar',
-                          cleanup_in_class=False,
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_create_cg_with_invalid_share_type_id_value_v2_4(self):
-        self.assertRaises(lib_exc.BadRequest,
-                          self.create_consistency_group,
-                          share_type_ids=['foobar'],
-                          cleanup_in_class=False,
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_create_cg_with_invalid_share_network_id_value_v2_4(self):
-        self.assertRaises(lib_exc.BadRequest,
-                          self.create_consistency_group,
-                          share_network_id='foobar',
-                          cleanup_in_class=False,
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API)
-    def test_create_cg_with_invalid_source_cgsnapshot_id_value_v2_4(
-            self):
-        self.assertRaises(lib_exc.BadRequest,
-                          self.create_consistency_group,
-                          source_cgsnapshot_id='foobar',
-                          cleanup_in_class=False,
-                          version='2.4')
-
-
-@testtools.skipUnless(CONF.share.run_consistency_group_tests,
-                      'Consistency Group tests disabled.')
-class ConsistencyGroupsNegativeTest(base.BaseSharesTest):
-
-    @classmethod
-    def resource_setup(cls):
-        super(ConsistencyGroupsNegativeTest, cls).resource_setup()
-        # Create a consistency group
-        cls.cg_name = data_utils.rand_name("tempest-cg-name")
-        cls.cg_desc = data_utils.rand_name("tempest-cg-description")
-        cls.consistency_group = cls.create_consistency_group(
-            name=cls.cg_name,
-            description=cls.cg_desc
-        )
-        # Create a share in the consistency group
-        cls.share_name = data_utils.rand_name("tempest-share-name")
-        cls.share_desc = data_utils.rand_name("tempest-share-description")
-        cls.share = cls.create_share(
-            name=cls.share_name,
-            description=cls.share_desc,
-            consistency_group_id=cls.consistency_group['id'],
-        )
-        # Create a cgsnapshot of the consistency group
-        cls.cgsnap_name = data_utils.rand_name("tempest-cgsnap-name")
-        cls.cgsnap_desc = data_utils.rand_name("tempest-cgsnap-description")
-        cls.cgsnapshot = cls.create_cgsnapshot_wait_for_active(
-            cls.consistency_group["id"],
-            name=cls.cgsnap_name,
-            description=cls.cgsnap_desc)
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_cg_with_nonexistent_source_cgsnapshot_id_value_v2_4(self):
-        self.assertRaises(lib_exc.BadRequest,
-                          self.create_consistency_group,
-                          source_cgsnapshot_id=self.share['id'],
-                          cleanup_in_class=False,
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_cg_with_nonexistent_share_network_id_value_v2_4(self):
-        self.assertRaises(lib_exc.BadRequest,
-                          self.create_consistency_group,
-                          share_network_id=self.share['id'],
-                          cleanup_in_class=False,
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_cg_with_nonexistent_share_type_id_value_v2_4(self):
-        self.assertRaises(lib_exc.BadRequest,
-                          self.create_consistency_group,
-                          share_type_ids=[self.share['id']],
-                          cleanup_in_class=False,
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_create_cgsnapshot_with_nonexistent_cg_id_value_v2_4(self):
-        self.assertRaises(lib_exc.BadRequest,
-                          self.create_cgsnapshot_wait_for_active,
-                          self.share['id'],
-                          cleanup_in_class=False,
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_delete_cg_in_use_by_cgsnapshot_v2_4(self):
-        # Attempt delete of share type
-        self.assertRaises(lib_exc.Conflict,
-                          self.shares_v2_client.delete_consistency_group,
-                          self.consistency_group['id'],
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_delete_share_in_use_by_cgsnapshot_v2_4(self):
-        # Attempt delete of share type
-        params = {'consistency_group_id': self.share['consistency_group_id']}
-        self.assertRaises(lib_exc.Forbidden,
-                          self.shares_v2_client.delete_share,
-                          self.share['id'],
-                          params=params,
-                          version='2.4')
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_delete_cg_containing_a_share_v2_4(self):
-        self.assertRaises(lib_exc.Conflict,
-                          self.shares_v2_client.delete_consistency_group,
-                          self.consistency_group['id'],
-                          version='2.4')
-        # Verify consistency group is not put into error state from conflict
-        cg = self.shares_v2_client.get_consistency_group(
-            self.consistency_group['id'], version='2.4')
-        self.assertEqual('available', cg['status'])
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_filter_shares_on_nonexistent_cg_id_v2_4(self):
-        shares = self.shares_v2_client.list_shares(
-            detailed=True,
-            params={'consistency_group_id': self.share['id']},
-            version='2.4'
-        )
-
-        self.assertEqual(0, len(shares),
-                         'Incorrect number of shares returned. Expected 0, '
-                         'got %s.' % len(shares))
-
-    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
-    def test_filter_shares_on_empty_cg_id_v2_4(self):
-        consistency_group = self.create_consistency_group(
-            name='tempest_cg',
-            description='tempest_cg_desc',
-            cleanup_in_class=False,
-            version='2.4',
-        )
-        shares = self.shares_v2_client.list_shares(
-            detailed=True,
-            params={'consistency_group_id': consistency_group['id']},
-            version='2.4',
-        )
-
-        self.assertEqual(0, len(shares),
-                         'Incorrect number of shares returned. Expected 0, '
-                         'got %s.' % len(shares))
diff --git a/manila_tempest_tests/tests/api/test_share_group_actions.py b/manila_tempest_tests/tests/api/test_share_group_actions.py
new file mode 100644
index 0000000..aa582bf
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_share_group_actions.py
@@ -0,0 +1,395 @@
+# -*- coding: utf-8 -*-
+# Copyright 2016 Andrew Kerr
+# 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 config
+from tempest.lib.common.utils import data_utils
+import testtools
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import constants
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+
+
+@testtools.skipUnless(
+    CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
+class ShareGroupActionsTest(base.BaseSharesTest):
+    """Covers share group functionality."""
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareGroupActionsTest, cls).resource_setup()
+
+        # Create first share group
+        cls.share_group_name = data_utils.rand_name("tempest-sg-name")
+        cls.share_group_desc = data_utils.rand_name("tempest-sg-description")
+        cls.share_group = cls.create_share_group(
+            name=cls.share_group_name, description=cls.share_group_desc)
+
+        # Create second share group for purposes of sorting and snapshot
+        # filtering
+        cls.share_group2 = cls.create_share_group(
+            name=cls.share_group_name, description=cls.share_group_desc)
+
+        # Create 2 shares - inside first and second share groups
+        cls.share_name = data_utils.rand_name("tempest-share-name")
+        cls.share_desc = data_utils.rand_name("tempest-share-description")
+        cls.share_size = 1
+        cls.share_size2 = 2
+        cls.shares = cls.create_shares([
+            {'kwargs': {
+                'name': cls.share_name,
+                'description': cls.share_desc,
+                'size': size,
+                'share_group_id': sg_id,
+                'experimental': True,
+            }} for size, sg_id in ((cls.share_size, cls.share_group['id']),
+                                   (cls.share_size2, cls.share_group['id']),
+                                   (cls.share_size, cls.share_group2['id']))
+        ])
+
+        # Create share group snapshots
+        cls.sg_snap_name = data_utils.rand_name("tempest-sg-snap-name")
+        cls.sg_snap_desc = data_utils.rand_name("tempest-sg-snap-desc")
+
+        cls.sg_snapshot = cls.create_share_group_snapshot_wait_for_active(
+            cls.share_group["id"],
+            name=cls.sg_snap_name,
+            description=cls.sg_snap_desc,
+        )
+
+        cls.sg_snapshot2 = cls.create_share_group_snapshot_wait_for_active(
+            cls.share_group2['id'],
+            name=cls.sg_snap_name,
+            description=cls.sg_snap_desc,
+        )
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_share_group_min_supported_sg_microversion(self):
+
+        # Get share group
+        share_group = self.shares_v2_client.get_share_group(
+            self.share_group['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+
+        # Verify keys
+        actual_keys = set(share_group.keys())
+        self.assertTrue(
+            constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(actual_keys),
+            'Not all required keys returned for share group %s. '
+            'Expected at least: %s, found %s' % (
+                share_group['id'],
+                constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
+                actual_keys))
+
+        # Verify values
+        self.assertEqual(self.share_group_name, share_group["name"])
+        self.assertEqual(self.share_group_desc, share_group["description"])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_share_min_supported_sg_microversion(self):
+
+        # Get share
+        share = self.shares_v2_client.get_share(
+            self.shares[0]['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+            experimental=True)
+
+        # Verify keys
+        expected_keys = {
+            "status", "description", "links", "availability_zone",
+            "created_at", "share_proto", "name", "snapshot_id",
+            "id", "size", "share_group_id",
+        }
+        actual_keys = set(share.keys())
+        self.assertTrue(
+            expected_keys.issubset(actual_keys),
+            'Not all required keys returned for share %s.  '
+            'Expected at least: %s, found %s' % (
+                share['id'], expected_keys, actual_keys))
+
+        # Verify values
+        self.assertEqual(self.share_name, share["name"])
+        self.assertEqual(self.share_desc, share["description"])
+        self.assertEqual(self.share_size, int(share["size"]))
+        self.assertEqual(self.share_group["id"], share["share_group_id"])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_list_share_groups_min(self):
+
+        # List share groups
+        share_groups = self.shares_v2_client.list_share_groups(
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        # Verify keys
+        self.assertGreater(len(share_groups), 0)
+        for sg in share_groups:
+            keys = set(sg.keys())
+            self.assertEqual(
+                constants.SHARE_GROUP_SIMPLE_KEYS,
+                keys,
+                'Incorrect keys returned for share group %s. '
+                'Expected: %s, found %s' % (
+                    sg['id'],
+                    constants.SHARE_GROUP_SIMPLE_KEYS,
+                    ','.join(keys)))
+
+        # Share group ids are in list exactly once
+        for sg_id in (self.share_group["id"], self.share_group2["id"]):
+            gen = [sg["id"] for sg in share_groups if sg["id"] == sg_id]
+            msg = ("Expected id %s exactly once in share group list" % sg_id)
+            self.assertEqual(1, len(gen), msg)
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_list_share_groups_with_detail_min(self):
+
+        # List share groups
+        share_groups = self.shares_v2_client.list_share_groups(
+            detailed=True, version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        # Verify keys
+        for sg in share_groups:
+            keys = set(sg.keys())
+            self.assertTrue(
+                constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(
+                    keys),
+                'Not all required keys returned for share group %s.  '
+                'Expected at least: %s, found %s' % (
+                    sg['id'],
+                    constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
+                    ','.join(keys),
+                )
+            )
+
+        # Share group ids are in list exactly once
+        for group_id in (self.share_group["id"], self.share_group2["id"]):
+            gen = [share_group["id"] for share_group in share_groups
+                   if share_group["id"] == group_id]
+            msg = ("Expected id %s exactly once in share group list" %
+                   group_id)
+            self.assertEqual(1, len(gen), msg)
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_filter_shares_by_share_group_id_min(self):
+        shares = self.shares_v2_client.list_shares(
+            detailed=True,
+            params={'share_group_id': self.share_group['id']},
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+            experimental=True,
+        )
+
+        share_ids = [share['id'] for share in shares]
+
+        self.assertEqual(
+            2, len(shares),
+            'Incorrect number of shares returned. '
+            'Expected 2, got %s' % len(shares))
+        self.assertIn(
+            self.shares[0]['id'], share_ids,
+            'Share %s expected in returned list, but got %s' % (
+                self.shares[0]['id'], share_ids))
+        self.assertIn(
+            self.shares[1]['id'], share_ids,
+            'Share %s expected in returned list, but got %s' % (
+                self.shares[0]['id'], share_ids))
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_share_group_snapshot_min(self):
+        # Get share group snapshot
+        sg_snapshot = self.shares_v2_client.get_share_group_snapshot(
+            self.sg_snapshot['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+
+        # Verify keys
+        actual_keys = set(sg_snapshot.keys())
+        self.assertTrue(
+            constants.SHARE_GROUP_SNAPSHOT_DETAIL_REQUIRED_KEYS.issubset(
+                actual_keys),
+            'Not all required keys returned for share group %s.  '
+            'Expected at least: %s, found %s' % (
+                sg_snapshot['id'],
+                constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
+                actual_keys,
+            )
+        )
+
+        # Verify values
+        self.assertEqual(self.sg_snap_name, sg_snapshot["name"])
+        self.assertEqual(self.sg_snap_desc, sg_snapshot["description"])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_share_group_snapshot_members_min(self):
+        sg_snapshot = self.shares_v2_client.get_share_group_snapshot(
+            self.sg_snapshot['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+        sg_snapshot_members = sg_snapshot['members']
+        member_share_ids = [m['share_id'] for m in sg_snapshot_members]
+        self.assertEqual(
+            2, len(sg_snapshot_members),
+            'Unexpected number of share group snapshot members. '
+            'Expected 2, got %s.' % len(sg_snapshot_members))
+        # Verify each share is represented in the share group snapshot
+        # appropriately
+        for share_id in (self.shares[0]['id'], self.shares[1]['id']):
+            self.assertIn(
+                share_id, member_share_ids,
+                'Share missing %s missing from share group '
+                'snapshot. Found %s.' % (share_id, member_share_ids))
+        for share in (self.shares[0], self.shares[1]):
+            for member in sg_snapshot_members:
+                if share['id'] == member['share_id']:
+                    self.assertEqual(share['size'], member['size'])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_share_group_from_populated_share_group_snapshot_min(self):
+
+        sg_snapshot = self.shares_v2_client.get_share_group_snapshot(
+            self.sg_snapshot['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+        snapshot_members = sg_snapshot['members']
+
+        new_share_group = self.create_share_group(
+            cleanup_in_class=False,
+            source_share_group_snapshot_id=self.sg_snapshot['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+
+        new_share_group = self.shares_v2_client.get_share_group(
+            new_share_group['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+
+        # Verify that share_network information matches source share group
+        self.assertEqual(
+            self.share_group['share_network_id'],
+            new_share_group['share_network_id'])
+
+        new_shares = self.shares_v2_client.list_shares(
+            params={'share_group_id': new_share_group['id']},
+            detailed=True,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+            experimental=True,
+        )
+
+        # Verify each new share is available
+        for share in new_shares:
+            self.assertEqual(
+                'available', share['status'],
+                'Share %s is not in available status.' % share['id'])
+
+        # Verify each sgsnapshot member is represented in the new sg
+        # appropriately
+        share_source_member_ids = [
+            share['source_share_group_snapshot_member_id']
+            for share in new_shares]
+        for member in snapshot_members:
+            self.assertIn(
+                member['id'], share_source_member_ids,
+                'Share group snapshot member %s not represented by '
+                'share group %s.' % (member['id'], new_share_group['id']))
+            for share in new_shares:
+                if (share['source_share_group_snapshot_member_id'] == (
+                        member['id'])):
+                    self.assertEqual(member['size'], share['size'])
+                    self.assertEqual(
+                        self.share_group['share_network_id'],
+                        share['share_network_id'])
+
+
+@testtools.skipUnless(
+    CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
+class ShareGroupRenameTest(base.BaseSharesTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareGroupRenameTest, cls).resource_setup()
+
+        # Create share group
+        cls.share_group_name = data_utils.rand_name("tempest-sg-name")
+        cls.share_group_desc = data_utils.rand_name("tempest-sg-description")
+        cls.share_group = cls.create_share_group(
+            name=cls.share_group_name,
+            description=cls.share_group_desc,
+        )
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_update_share_group_min(self):
+
+        # Get share_group
+        share_group = self.shares_v2_client.get_share_group(
+            self.share_group['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION
+        )
+        self.assertEqual(self.share_group_name, share_group["name"])
+        self.assertEqual(self.share_group_desc, share_group["description"])
+
+        # Update share_group
+        new_name = data_utils.rand_name("tempest-new-name")
+        new_desc = data_utils.rand_name("tempest-new-description")
+        updated = self.shares_v2_client.update_share_group(
+            share_group["id"],
+            name=new_name,
+            description=new_desc,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+        self.assertEqual(new_name, updated["name"])
+        self.assertEqual(new_desc, updated["description"])
+
+        # Get share_group
+        share_group = self.shares_v2_client.get_share_group(
+            self.share_group['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+        self.assertEqual(new_name, share_group["name"])
+        self.assertEqual(new_desc, share_group["description"])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_update_read_share_group_with_unicode_min(self):
+        value1 = u'ಠ_ಠ'
+        value2 = u'ಠ_ರೃ'
+
+        # Create share_group
+        share_group = self.create_share_group(
+            cleanup_in_class=False,
+            name=value1,
+            description=value1,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+        self.assertEqual(value1, share_group["name"])
+        self.assertEqual(value1, share_group["description"])
+
+        # Update share group
+        updated = self.shares_v2_client.update_share_group(
+            share_group["id"],
+            name=value2,
+            description=value2,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+        self.assertEqual(value2, updated["name"])
+        self.assertEqual(value2, updated["description"])
+
+        # Get share group
+        share_group = self.shares_v2_client.get_share_group(
+            share_group['id'], version=constants.MIN_SHARE_GROUP_MICROVERSION)
+        self.assertEqual(value2, share_group["name"])
+        self.assertEqual(value2, share_group["description"])
diff --git a/manila_tempest_tests/tests/api/test_share_groups.py b/manila_tempest_tests/tests/api/test_share_groups.py
new file mode 100644
index 0000000..98d29e4
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_share_groups.py
@@ -0,0 +1,165 @@
+# Copyright 2016 Andrew Kerr
+# 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 config
+from tempest.lib import exceptions as lib_exc
+import testtools
+from testtools import testcase as tc
+
+from manila_tempest_tests.common import constants
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+
+
+@testtools.skipUnless(
+    CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
+class ShareGroupsTest(base.BaseSharesTest):
+    """Covers share group functionality."""
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_populate_delete_share_group_min(self):
+        # Create a share group
+        share_group = self.create_share_group(
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+        keys = set(share_group.keys())
+        self.assertTrue(
+            constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS.issubset(keys),
+            'At least one expected element missing from share group '
+            'response. Expected %(expected)s, got %(actual)s.' % {
+                "expected": constants.SHARE_GROUP_DETAIL_REQUIRED_KEYS,
+                "actual": keys}
+        )
+        # Populate
+        share = self.create_share(
+            share_group_id=share_group['id'],
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+            experimental=True)
+
+        # Delete
+        params = {"share_group_id": share_group['id']}
+        self.shares_v2_client.delete_share(
+            share['id'],
+            params=params,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+        self.shares_client.wait_for_resource_deletion(share_id=share['id'])
+        self.shares_v2_client.delete_share_group(
+            share_group['id'], version=constants.MIN_SHARE_GROUP_MICROVERSION)
+        self.shares_v2_client.wait_for_resource_deletion(
+            share_group_id=share_group['id'])
+
+        # Verify
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.shares_v2_client.get_share_group, share_group['id'])
+        self.assertRaises(
+            lib_exc.NotFound, self.shares_client.get_share, share['id'])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_delete_empty_share_group_snapshot_min(self):
+        # Create base share group
+        share_group = self.create_share_group(
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        # Create share group snapshot
+        sg_snapshot = self.create_share_group_snapshot_wait_for_active(
+            share_group["id"],
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        keys = set(sg_snapshot.keys())
+        self.assertTrue(
+            constants.SHARE_GROUP_SNAPSHOT_DETAIL_REQUIRED_KEYS.issubset(keys),
+            'At least one expected element missing from share group snapshot '
+            'response. Expected %(e)s, got %(a)s.' % {
+                "e": constants.SHARE_GROUP_SNAPSHOT_DETAIL_REQUIRED_KEYS,
+                "a": keys})
+
+        sg_snapshot_members = sg_snapshot['members']
+        self.assertEmpty(
+            sg_snapshot_members,
+            'Expected 0 share_group_snapshot members, got %s' % len(
+                sg_snapshot_members))
+
+        # Delete snapshot
+        self.shares_v2_client.delete_share_group_snapshot(
+            sg_snapshot["id"], version=constants.MIN_SHARE_GROUP_MICROVERSION)
+        self.shares_v2_client.wait_for_resource_deletion(
+            share_group_snapshot_id=sg_snapshot["id"])
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.shares_v2_client.get_share_group_snapshot,
+            sg_snapshot['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_share_group_from_empty_share_group_snapshot_min(self):
+        # Create base share group
+        share_group = self.create_share_group(
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        # Create share group snapshot
+        sg_snapshot = self.create_share_group_snapshot_wait_for_active(
+            share_group["id"], cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        snapshot_members = sg_snapshot['members']
+
+        self.assertEmpty(
+            snapshot_members,
+            'Expected 0 share group snapshot members, got %s' %
+            len(snapshot_members))
+
+        new_share_group = self.create_share_group(
+            cleanup_in_class=False,
+            source_share_group_snapshot_id=sg_snapshot['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        new_shares = self.shares_v2_client.list_shares(
+            params={'share_group_id': new_share_group['id']},
+            version=constants.MIN_SHARE_GROUP_MICROVERSION, experimental=True)
+
+        self.assertEmpty(
+            new_shares, 'Expected 0 new shares, got %s' % len(new_shares))
+
+        msg = ('Expected source_ishare_group_snapshot_id %s '
+               'as source of share group %s' % (
+                   sg_snapshot['id'],
+                   new_share_group['source_share_group_snapshot_id']))
+        self.assertEqual(
+            new_share_group['source_share_group_snapshot_id'],
+            sg_snapshot['id'],
+            msg)
+
+        msg = ('Unexpected share_types on new share group. Expected '
+               '%s, got %s.' % (share_group['share_types'],
+                                new_share_group['share_types']))
+        self.assertEqual(
+            sorted(share_group['share_types']),
+            sorted(new_share_group['share_types']), msg)
+
+        # Assert the share_network information is the same
+        msg = 'Expected share_network %s as share_network of cg %s' % (
+            share_group['share_network_id'],
+            new_share_group['share_network_id'])
+        self.assertEqual(
+            share_group['share_network_id'],
+            new_share_group['share_network_id'],
+            msg)
diff --git a/manila_tempest_tests/tests/api/test_share_groups_negative.py b/manila_tempest_tests/tests/api/test_share_groups_negative.py
new file mode 100644
index 0000000..b33eca9
--- /dev/null
+++ b/manila_tempest_tests/tests/api/test_share_groups_negative.py
@@ -0,0 +1,239 @@
+# Copyright 2016 Andrew Kerr
+# 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 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.common import constants
+from manila_tempest_tests.tests.api import base
+
+CONF = config.CONF
+
+
+@testtools.skipUnless(
+    CONF.share.run_share_group_tests, 'Share Group tests disabled.')
+@base.skip_if_microversion_lt(constants.MIN_SHARE_GROUP_MICROVERSION)
+class ShareGroupsNegativeTest(base.BaseSharesTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ShareGroupsNegativeTest, cls).resource_setup()
+        # Create a share group
+        cls.share_group_name = data_utils.rand_name("tempest-sg-name")
+        cls.share_group_desc = data_utils.rand_name("tempest-sg-description")
+        cls.share_group = cls.create_share_group(
+            name=cls.share_group_name,
+            description=cls.share_group_desc
+        )
+        # Create a share in the share group
+        cls.share_name = data_utils.rand_name("tempest-share-name")
+        cls.share_desc = data_utils.rand_name("tempest-share-description")
+        cls.share_size = 1
+        cls.share = cls.create_share(
+            name=cls.share_name,
+            description=cls.share_desc,
+            size=cls.share_size,
+            share_group_id=cls.share_group['id'],
+            experimental=True,
+        )
+        # Create a share group snapshot of the share group
+        cls.sg_snap_name = data_utils.rand_name("tempest-sg-snap-name")
+        cls.sg_snap_desc = data_utils.rand_name(
+            "tempest-group-snap-description")
+        cls.sg_snapshot = cls.create_share_group_snapshot_wait_for_active(
+            cls.share_group["id"],
+            name=cls.sg_snap_name,
+            description=cls.sg_snap_desc
+        )
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_sg_with_invalid_source_sg_snapshot_id_value_min(self):
+        self.assertRaises(
+            lib_exc.BadRequest,
+            self.create_share_group,
+            source_share_group_snapshot_id='foobar',
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_sg_with_nonexistent_source_sg_snapshot_id_value_min(self):
+        self.assertRaises(
+            lib_exc.BadRequest,
+            self.create_share_group,
+            source_share_group_snapshot_id=self.share['id'],
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_sg_with_invalid_share_network_id_value_min(self):
+        self.assertRaises(
+            lib_exc.BadRequest,
+            self.create_share_group,
+            share_network_id='foobar',
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_group_with_nonexistent_share_network_id_value_min(self):
+        self.assertRaises(
+            lib_exc.BadRequest,
+            self.create_share_group,
+            share_network_id=self.share['id'],
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_sg_with_invalid_share_type_id_value_min(self):
+        self.assertRaises(
+            lib_exc.BadRequest,
+            self.create_share_group,
+            share_type_ids=['foobar'],
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_sg_with_nonexistent_share_type_id_value_min(self):
+        self.assertRaises(
+            lib_exc.BadRequest,
+            self.create_share_group,
+            share_type_ids=[self.share['id']],
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_sg_snapshot_with_invalid_sg_id_value_min(self):
+        self.assertRaises(
+            lib_exc.BadRequest,
+            self.create_share_group_snapshot_wait_for_active,
+            'foobar',
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_sg_snapshot_with_nonexistent_sg_id_value_min(self):
+        self.assertRaises(
+            lib_exc.BadRequest,
+            self.create_share_group_snapshot_wait_for_active,
+            self.share['id'],
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_sg_with_invalid_id_min(self):
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.shares_v2_client.get_share_group,
+            "invalid_share_group_id",
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_get_sg_without_passing_group_id_min(self):
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.shares_v2_client.get_share_group,
+            '', version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_update_sg_with_invalid_id_min(self):
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.shares_v2_client.update_share_group,
+            'invalid_share_group_id',
+            name='new_name',
+            description='new_description',
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_sg_with_invalid_id_min(self):
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.shares_v2_client.delete_share_group,
+            "invalid_share_group_id",
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_sg_without_passing_sg_id_min(self):
+        self.assertRaises(
+            lib_exc.NotFound,
+            self.shares_v2_client.delete_share_group,
+            '', version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_sg_in_use_by_sg_snapshot_min(self):
+        self.assertRaises(
+            lib_exc.Conflict,
+            self.shares_v2_client.delete_share_group,
+            self.share_group['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_share_in_use_by_sg_snapshot_min(self):
+        params = {'share_group_id': self.share['share_group_id']}
+        self.assertRaises(
+            lib_exc.Forbidden,
+            self.shares_v2_client.delete_share,
+            self.share['id'],
+            params=params,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_delete_sg_containing_a_share_min(self):
+        self.assertRaises(
+            lib_exc.Conflict,
+            self.shares_v2_client.delete_share_group,
+            self.share_group['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+
+        # Verify share group is not put into error state from conflict
+        sg = self.shares_v2_client.get_share_group(
+            self.share_group['id'],
+            version=constants.MIN_SHARE_GROUP_MICROVERSION)
+        self.assertEqual('available', sg['status'])
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_filter_shares_on_invalid_group_id_min(self):
+        shares = self.shares_v2_client.list_shares(
+            detailed=True,
+            params={'share_group_id': 'foobar'},
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+        self.assertEqual(0, len(shares), 'Incorrect number of shares returned')
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_filter_shares_on_nonexistent_group_id_min(self):
+        shares = self.shares_v2_client.list_shares(
+            detailed=True,
+            params={'share_group_id': self.share['id']},
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+        self.assertEqual(0, len(shares), 'Incorrect number of shares returned')
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_filter_shares_on_empty_share_group_id_min(self):
+        share_group = self.create_share_group(
+            name='tempest_sg',
+            description='tempest_sg_desc',
+            cleanup_in_class=False,
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+        shares = self.shares_v2_client.list_shares(
+            detailed=True,
+            params={'share_group_id': share_group['id']},
+            version=constants.MIN_SHARE_GROUP_MICROVERSION,
+        )
+        self.assertEqual(0, len(shares), 'Incorrect number of shares returned')