Merge "[Share groups] Add scheduler filter ConsistentSnapshotFilter"
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index 7c5eeb2..3be873f 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -112,6 +112,11 @@
                      "capability called 'revert_to_snapshot_support' "
                      "and will be used for setting up custom share type. "
                      "Defaults to the value of run_revert_to_snapshot_tests."),
+    cfg.StrOpt("capability_sg_consistent_snapshot_support",
+               choices=["host", "pool", None],
+               help="Backend capability to create consistent snapshots of "
+                    "share group members. Will be used with creation "
+                    "of new share group types as group spec."),
     cfg.StrOpt("share_network_id",
                default="",
                help="Some backend drivers requires share network "
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
index 532e773..189ab34 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_group_types.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_group_types.py
@@ -136,13 +136,16 @@
 
         self.assertDictMatch(group_specs, sg_type['group_specs'])
 
-        group_specs = {'key1': 'value3', 'key2': 'value2'}
+        group_specs = {'key1': 'value1', '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'])
+        self.assertIn('key1', sg_type['group_specs'])
+        self.assertIn('key2', sg_type['group_specs'])
+        self.assertEqual('value3', sg_type['group_specs']['key1'])
+        self.assertEqual(group_specs['key2'], sg_type['group_specs']['key2'])
 
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
     def test_update_all_share_group_type_specs_min(self):
@@ -164,7 +167,9 @@
             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'])
+        for k, v in group_specs.items():
+            self.assertIn(k, sg_type['group_specs'])
+            self.assertEqual(v, sg_type['group_specs'][k])
 
     @tc.attr(base.TAG_POSITIVE, base.TAG_API)
     def test_delete_single_share_group_type_spec_min(self):
diff --git a/manila_tempest_tests/tests/api/admin/test_share_groups.py b/manila_tempest_tests/tests/api/admin/test_share_groups.py
index e289005..dc1f2ae 100644
--- a/manila_tempest_tests/tests/api/admin/test_share_groups.py
+++ b/manila_tempest_tests/tests/api/admin/test_share_groups.py
@@ -48,7 +48,7 @@
             cleanup_in_class=True,
             version=constants.MIN_SHARE_GROUP_MICROVERSION)
 
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     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'],
@@ -81,7 +81,7 @@
             'Expected %s, got %s' % (
                 share_group['id'], expected_share_types, actual_share_types))
 
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     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'],
@@ -114,7 +114,7 @@
             'Expected %s, got %s' % (
                 share_group['id'], expected_share_types, actual_share_types))
 
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     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']
@@ -142,7 +142,7 @@
 
     @testtools.skipUnless(
         CONF.share.multitenancy_enabled, "Only for multitenancy.")
-    @tc.attr(base.TAG_POSITIVE, base.TAG_API)
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
     def test_create_sg_from_snapshot_verify_share_server_information_min(self):
         # Create a share group
         orig_sg = self.create_share_group(
@@ -173,3 +173,19 @@
             orig_sg['share_network_id'], new_sg['share_network_id'])
         self.assertEqual(
             orig_sg['share_server_id'], new_sg['share_server_id'])
+
+    @tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_sg_with_sg_type_but_without_any_group_specs(self):
+        # Create share group type not specifying any group specs
+        sg_type = self.create_share_group_type(
+            name=data_utils.rand_name("tempest-manila"),
+            share_types=[self.share_type['id']],
+            group_specs={},
+            cleanup_in_class=False)
+
+        # Create share group, it should be created always, because we do not
+        # restrict choice anyhow.
+        self.create_share_group(
+            share_type_ids=[self.share_type['id']],
+            share_group_type_id=sg_type['id'],
+            cleanup_in_class=False)
diff --git a/manila_tempest_tests/tests/api/admin/test_share_groups_negative.py b/manila_tempest_tests/tests/api/admin/test_share_groups_negative.py
new file mode 100644
index 0000000..979e6a4
--- /dev/null
+++ b/manila_tempest_tests/tests/api/admin/test_share_groups_negative.py
@@ -0,0 +1,56 @@
+# Copyright 2017 Mirantis Inc.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest import 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 import share_exceptions
+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.BaseSharesAdminTest):
+
+    @tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
+    def test_create_share_group_with_wrong_consistent_snapshot_spec(self):
+        # Create valid share type for share group type
+        name = data_utils.rand_name("tempest-manila")
+        extra_specs = self.add_extra_specs_to_dict()
+        st = self.create_share_type(name, extra_specs=extra_specs)
+        share_type = st['share_type'] if 'share_type' in st else st
+
+        # Create share group type with wrong value for
+        # 'consistent_snapshot_support' capability, we always expect
+        # NoValidHostFound using this SG type.
+        sg_type = self.create_share_group_type(
+            name=name,
+            share_types=[share_type['id']],
+            group_specs={"consistent_snapshot_support": "fake"},
+            cleanup_in_class=False)
+
+        # Try create share group
+        self.assertRaises(
+            share_exceptions.ShareGroupBuildErrorException,
+            self.create_share_group,
+            share_type_ids=[share_type['id']],
+            share_group_type_id=sg_type['id'],
+            cleanup_in_class=False)
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index de298da..236351d 100644
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -595,6 +595,11 @@
                                 group_specs=None, client=None,
                                 cleanup_in_class=True, **kwargs):
         client = client or cls.shares_v2_client
+        if group_specs is None:
+            group_specs = {
+                'consistent_snapshot_support': (
+                    CONF.share.capability_sg_consistent_snapshot_support),
+            }
         share_group_type = client.create_share_group_type(
             name=name,
             share_types=share_types,