Merge "Make heat-slow job run in parallel"
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index abd36a6..ac43869 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -339,6 +339,7 @@
         cls.hosts_client = cls.os.hosts_v3_client
         cls.quotas_client = cls.os.quotas_v3_client
         cls.version_client = cls.os.version_v3_client
+        cls.migrations_client = cls.os.migrations_v3_client
 
     @classmethod
     def create_image_from_server(cls, server_id, **kwargs):
@@ -412,3 +413,4 @@
         cls.hosts_admin_client = cls.os_adm.hosts_v3_client
         cls.quotas_admin_client = cls.os_adm.quotas_v3_client
         cls.agents_admin_client = cls.os_adm.agents_v3_client
+        cls.migrations_admin_client = cls.os_adm.migrations_v3_client
diff --git a/tempest/api/compute/v3/admin/test_migrations.py b/tempest/api/compute/v3/admin/test_migrations.py
new file mode 100644
index 0000000..e8bd473
--- /dev/null
+++ b/tempest/api/compute/v3/admin/test_migrations.py
@@ -0,0 +1,50 @@
+# Copyright 2014 NEC Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import testtools
+
+from tempest.api.compute import base
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
+
+
+class MigrationsAdminV3Test(base.BaseV3ComputeAdminTest):
+
+    @test.attr(type='gate')
+    def test_list_migrations(self):
+        # Admin can get the migrations list
+        resp, _ = self.migrations_admin_client.list_migrations()
+        self.assertEqual(200, resp.status)
+
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
+    @test.attr(type='gate')
+    def test_list_migrations_in_flavor_resize_situation(self):
+        # Admin can get the migrations list which contains the resized server
+        resp, server = self.create_test_server(wait_until="ACTIVE")
+        server_id = server['id']
+
+        resp, _ = self.servers_client.resize(server_id, self.flavor_ref_alt)
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(server_id, 'VERIFY_RESIZE')
+        self.servers_client.confirm_resize(server_id)
+        self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+
+        resp, body = self.migrations_admin_client.list_migrations()
+        self.assertEqual(200, resp.status)
+
+        instance_uuids = [x['instance_uuid'] for x in body]
+        self.assertIn(server_id, instance_uuids)
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index f92ad68..0eb73c9 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -79,9 +79,17 @@
         cls.floating_ips = []
         cls.metering_labels = []
         cls.metering_label_rules = []
+        cls.fw_rules = []
+        cls.fw_policies = []
 
     @classmethod
     def tearDownClass(cls):
+        # Clean up firewall policies
+        for fw_policy in cls.fw_policies:
+            cls.client.delete_firewall_policy(fw_policy['id'])
+        # Clean up firewall rules
+        for fw_rule in cls.fw_rules:
+            cls.client.delete_firewall_rule(fw_rule['id'])
         # Clean up ike policies
         for ikepolicy in cls.ikepolicies:
             cls.client.delete_ikepolicy(ikepolicy['id'])
@@ -296,6 +304,26 @@
         cls.ikepolicies.append(ikepolicy)
         return ikepolicy
 
+    @classmethod
+    def create_firewall_rule(cls, action, protocol):
+        """Wrapper utility that returns a test firewall rule."""
+        resp, body = cls.client.create_firewall_rule(
+            name=data_utils.rand_name("fw-rule"),
+            action=action,
+            protocol=protocol)
+        fw_rule = body['firewall_rule']
+        cls.fw_rules.append(fw_rule)
+        return fw_rule
+
+    @classmethod
+    def create_firewall_policy(cls):
+        """Wrapper utility that returns a test firewall policy."""
+        resp, body = cls.client.create_firewall_policy(
+            name=data_utils.rand_name("fw-policy"))
+        fw_policy = body['firewall_policy']
+        cls.fw_policies.append(fw_policy)
+        return fw_policy
+
 
 class BaseAdminNetworkTest(BaseNetworkTest):
 
diff --git a/tempest/api/network/test_fwaas_extensions.py b/tempest/api/network/test_fwaas_extensions.py
new file mode 100644
index 0000000..0647069
--- /dev/null
+++ b/tempest/api/network/test_fwaas_extensions.py
@@ -0,0 +1,207 @@
+# Copyright 2014 NEC Corporation. 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.api.network import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class FWaaSExtensionTestJSON(base.BaseNetworkTest):
+    _interface = 'json'
+
+    """
+    Tests the following operations in the Neutron API using the REST client for
+    Neutron:
+
+        List firewall rules
+        Create firewall rule
+        Update firewall rule
+        Delete firewall rule
+        Show firewall rule
+        List firewall policies
+        Create firewall policy
+        Update firewall policy
+        Delete firewall policy
+        Show firewall policy
+        List firewall
+        Create firewall
+        Update firewall
+        Delete firewall
+        Show firewall
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        super(FWaaSExtensionTestJSON, cls).setUpClass()
+        if not test.is_extension_enabled('fwaas', 'network'):
+            msg = "FWaaS Extension not enabled."
+            raise cls.skipException(msg)
+        cls.fw_rule = cls.create_firewall_rule("allow", "tcp")
+        cls.fw_policy = cls.create_firewall_policy()
+
+    def _try_delete_policy(self, policy_id):
+        # delete policy, if it exists
+        try:
+            self.client.delete_firewall_policy(policy_id)
+        # if policy is not found, this means it was deleted in the test
+        except exceptions.NotFound:
+            pass
+
+    def _try_delete_firewall(self, fw_id):
+        # delete firewall, if it exists
+        try:
+            self.client.delete_firewall(fw_id)
+        # if firewall is not found, this means it was deleted in the test
+        except exceptions.NotFound:
+            pass
+
+    @test.attr(type='smoke')
+    def test_list_firewall_rules(self):
+        # List firewall rules
+        resp, fw_rules = self.client.list_firewall_rules()
+        self.assertEqual('200', resp['status'])
+        fw_rules = fw_rules['firewall_rules']
+        self.assertIn((self.fw_rule['id'],
+                       self.fw_rule['name'],
+                       self.fw_rule['action'],
+                       self.fw_rule['protocol'],
+                       self.fw_rule['ip_version'],
+                       self.fw_rule['enabled']),
+                      [(m['id'],
+                        m['name'],
+                        m['action'],
+                        m['protocol'],
+                        m['ip_version'],
+                        m['enabled']) for m in fw_rules])
+
+    @test.attr(type='smoke')
+    def test_create_update_delete_firewall_rule(self):
+        # Create firewall rule
+        resp, body = self.client.create_firewall_rule(
+            name=data_utils.rand_name("fw-rule"),
+            action="allow",
+            protocol="tcp")
+        self.assertEqual('201', resp['status'])
+        fw_rule_id = body['firewall_rule']['id']
+
+        # Update firewall rule
+        resp, body = self.client.update_firewall_rule(fw_rule_id,
+                                                      shared=True)
+        self.assertEqual('200', resp['status'])
+        self.assertTrue(body["firewall_rule"]['shared'])
+
+        # Delete firewall rule
+        resp, _ = self.client.delete_firewall_rule(fw_rule_id)
+        self.assertEqual('204', resp['status'])
+        # Confirm deletion
+        resp, fw_rules = self.client.list_firewall_rules()
+        self.assertNotIn(fw_rule_id,
+                         [m['id'] for m in fw_rules['firewall_rules']])
+
+    @test.attr(type='smoke')
+    def test_show_firewall_rule(self):
+        # show a created firewall rule
+        resp, fw_rule = self.client.show_firewall_rule(self.fw_rule['id'])
+        self.assertEqual('200', resp['status'])
+        for key, value in fw_rule['firewall_rule'].iteritems():
+            self.assertEqual(self.fw_rule[key], value)
+
+    @test.attr(type='smoke')
+    def test_list_firewall_policies(self):
+        resp, fw_policies = self.client.list_firewall_policies()
+        self.assertEqual('200', resp['status'])
+        fw_policies = fw_policies['firewall_policies']
+        self.assertIn((self.fw_policy['id'],
+                       self.fw_policy['name'],
+                       self.fw_policy['firewall_rules']),
+                      [(m['id'],
+                        m['name'],
+                        m['firewall_rules']) for m in fw_policies])
+
+    @test.attr(type='smoke')
+    def test_create_update_delete_firewall_policy(self):
+        # Create firewall policy
+        resp, body = self.client.create_firewall_policy(
+            name=data_utils.rand_name("fw-policy"))
+        self.assertEqual('201', resp['status'])
+        fw_policy_id = body['firewall_policy']['id']
+        self.addCleanup(self._try_delete_policy, fw_policy_id)
+
+        # Update firewall policy
+        resp, body = self.client.update_firewall_policy(fw_policy_id,
+                                                        shared=True,
+                                                        name="updated_policy")
+        self.assertEqual('200', resp['status'])
+        updated_fw_policy = body["firewall_policy"]
+        self.assertTrue(updated_fw_policy['shared'])
+        self.assertEqual("updated_policy", updated_fw_policy['name'])
+
+        # Delete firewall policy
+        resp, _ = self.client.delete_firewall_policy(fw_policy_id)
+        self.assertEqual('204', resp['status'])
+        # Confirm deletion
+        resp, fw_policies = self.client.list_firewall_policies()
+        fw_policies = fw_policies['firewall_policies']
+        self.assertNotIn(fw_policy_id, [m['id'] for m in fw_policies])
+
+    @test.attr(type='smoke')
+    def test_show_firewall_policy(self):
+        # show a created firewall policy
+        resp, fw_policy = self.client.show_firewall_policy(
+            self.fw_policy['id'])
+        self.assertEqual('200', resp['status'])
+        fw_policy = fw_policy['firewall_policy']
+        for key, value in fw_policy.iteritems():
+            self.assertEqual(self.fw_policy[key], value)
+
+    @test.attr(type='smoke')
+    def test_create_show_delete_firewall(self):
+        # Create firewall
+        resp, body = self.client.create_firewall(
+            name=data_utils.rand_name("firewall"),
+            firewall_policy_id=self.fw_policy['id'])
+        self.assertEqual('201', resp['status'])
+        created_firewall = body['firewall']
+        firewall_id = created_firewall['id']
+        self.addCleanup(self._try_delete_firewall, firewall_id)
+
+        # show a created firewall
+        resp, firewall = self.client.show_firewall(firewall_id)
+        self.assertEqual('200', resp['status'])
+        firewall = firewall['firewall']
+        for key, value in firewall.iteritems():
+            self.assertEqual(created_firewall[key], value)
+
+        # list firewall
+        resp, firewalls = self.client.list_firewalls()
+        self.assertEqual('200', resp['status'])
+        firewalls = firewalls['firewalls']
+        self.assertIn((created_firewall['id'],
+                       created_firewall['name'],
+                       created_firewall['firewall_policy_id']),
+                      [(m['id'],
+                        m['name'],
+                        m['firewall_policy_id']) for m in firewalls])
+
+        # Delete firewall
+        resp, _ = self.client.delete_firewall(firewall_id)
+        self.assertEqual('204', resp['status'])
+        # Confirm deletion
+        # TODO(raies): Confirm deletion can be done only when,
+        # deleted firewall status is not "PENDING_DELETE".
+
+
+class FWaaSExtensionTestXML(FWaaSExtensionTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api_schema/compute/v2/fixed_ips.py b/tempest/api_schema/compute/v2/fixed_ips.py
index a6add04..446633f 100644
--- a/tempest/api_schema/compute/v2/fixed_ips.py
+++ b/tempest/api_schema/compute/v2/fixed_ips.py
@@ -34,3 +34,8 @@
         'required': ['fixed_ip']
     }
 }
+
+fixed_ip_action = {
+    'status_code': [202],
+    'response_body': {'type': 'string'}
+}
diff --git a/tempest/api_schema/compute/v2/hosts.py b/tempest/api_schema/compute/v2/hosts.py
new file mode 100644
index 0000000..add5bb5
--- /dev/null
+++ b/tempest/api_schema/compute/v2/hosts.py
@@ -0,0 +1,27 @@
+# Copyright 2014 NEC Corporation.  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.
+
+body = {
+    'type': 'object',
+    'properties': {
+        'host': {'type': 'string'},
+        'power_action': {'enum': ['startup']}
+    },
+    'required': ['host', 'power_action']
+}
+
+startup_host = {
+    'status_code': [200],
+    'response_body': body
+}
diff --git a/tempest/api_schema/compute/v2/security_groups.py b/tempest/api_schema/compute/v2/security_groups.py
index 68b65b4..6dd44cd 100644
--- a/tempest/api_schema/compute/v2/security_groups.py
+++ b/tempest/api_schema/compute/v2/security_groups.py
@@ -36,3 +36,41 @@
         'required': ['security_groups']
     }
 }
+
+create_security_group_rule = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'security_group_rule': {
+                'type': 'object',
+                'properties': {
+                    'from_port': {'type': 'integer'},
+                    'to_port': {'type': 'integer'},
+                    'group': {'type': 'object'},
+                    'ip_protocol': {'type': 'string'},
+                    # 'parent_group_id' can be UUID so defining it
+                    # as 'string' also.
+                    'parent_group_id': {'type': ['integer', 'string']},
+                    'id': {'type': ['integer', 'string']},
+                    'ip_range': {
+                        'type': 'object',
+                        'properties': {
+                            'cidr': {'type': 'string'}
+                        }
+                        # When optional argument is provided in request body
+                        # like 'group_id' then, attribute 'cidr' does not
+                        # comes in response body. So it is not 'required'.
+                    }
+                },
+                'required': ['from_port', 'to_port', 'group', 'ip_protocol',
+                             'parent_group_id', 'id', 'ip_range']
+            }
+        },
+        'required': ['security_group_rule']
+    }
+}
+
+delete_security_group_rule = {
+    'status_code': [202]
+}
diff --git a/tempest/api_schema/compute/v3/hosts.py b/tempest/api_schema/compute/v3/hosts.py
new file mode 100644
index 0000000..9731d4b
--- /dev/null
+++ b/tempest/api_schema/compute/v3/hosts.py
@@ -0,0 +1,26 @@
+# Copyright 2014 NEC Corporation.  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.api_schema.compute.v2 import hosts
+
+startup_host = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'host': hosts.body
+        },
+        'required': ['host']
+    }
+}
diff --git a/tempest/api_schema/compute/v3/quotas.py b/tempest/api_schema/compute/v3/quotas.py
index 1b9989d..5378c0f 100644
--- a/tempest/api_schema/compute/v3/quotas.py
+++ b/tempest/api_schema/compute/v3/quotas.py
@@ -40,3 +40,42 @@
         'required': ['quota_set']
     }
 }
+
+quota_common_info = {
+    'type': 'object',
+    'properties': {
+        'reserved': {'type': 'integer'},
+        'limit': {'type': 'integer'},
+        'in_use': {'type': 'integer'}
+    },
+    'required': ['reserved', 'limit', 'in_use']
+}
+
+quota_set_detail = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'quota_set': {
+                'type': 'object',
+                'properties': {
+                    'id': {'type': 'string'},
+                    'instances': quota_common_info,
+                    'cores': quota_common_info,
+                    'ram': quota_common_info,
+                    'floating_ips': quota_common_info,
+                    'fixed_ips': quota_common_info,
+                    'metadata_items': quota_common_info,
+                    'key_pairs': quota_common_info,
+                    'security_groups': quota_common_info,
+                    'security_group_rules': quota_common_info
+                },
+                'required': ['id', 'instances', 'cores', 'ram',
+                             'floating_ips', 'fixed_ips',
+                             'metadata_items', 'key_pairs',
+                             'security_groups', 'security_group_rules']
+            }
+        },
+        'required': ['quota_set']
+    }
+}
diff --git a/tempest/cli/simple_read_only/test_sahara.py b/tempest/cli/simple_read_only/test_sahara.py
index cd819a4..5af8dae 100644
--- a/tempest/cli/simple_read_only/test_sahara.py
+++ b/tempest/cli/simple_read_only/test_sahara.py
@@ -48,23 +48,48 @@
 
     def test_sahara_plugins_list(self):
         plugins = self.parser.listing(self.sahara('plugin-list'))
-        self.assertTableStruct(plugins, ['name', 'versions', 'title'])
+        self.assertTableStruct(plugins, [
+            'name',
+            'versions',
+            'title'
+        ])
 
     def test_sahara_plugins_show(self):
-        plugin = self.parser.listing(self.sahara('plugin-show',
-                                                 params='--name vanilla'))
-        self.assertTableStruct(plugin, ['Property', 'Value'])
+        result = self.sahara('plugin-show', params='--name vanilla')
+        plugin = self.parser.listing(result)
+        self.assertTableStruct(plugin, [
+            'Property',
+            'Value'
+        ])
 
     def test_sahara_node_group_template_list(self):
-        plugins = self.parser.listing(self.sahara('node-group-template-list'))
-        self.assertTableStruct(plugins, ['name', 'id', 'plugin_name',
-                                         'node_processes', 'description'])
+        result = self.sahara('node-group-template-list')
+        node_group_templates = self.parser.listing(result)
+        self.assertTableStruct(node_group_templates, [
+            'name',
+            'id',
+            'plugin_name',
+            'node_processes',
+            'description'
+        ])
 
     def test_sahara_cluster_template_list(self):
-        plugins = self.parser.listing(self.sahara('cluster-template-list'))
-        self.assertTableStruct(plugins, ['name', 'id', 'plugin_name',
-                                         'node_groups', 'description'])
+        result = self.sahara('cluster-template-list')
+        cluster_templates = self.parser.listing(result)
+        self.assertTableStruct(cluster_templates, [
+            'name',
+            'id',
+            'plugin_name',
+            'node_groups',
+            'description'
+        ])
 
     def test_sahara_cluster_list(self):
-        plugins = self.parser.listing(self.sahara('cluster-list'))
-        self.assertTableStruct(plugins, ['name', 'id', 'status', 'node_count'])
+        result = self.sahara('cluster-list')
+        clusters = self.parser.listing(result)
+        self.assertTableStruct(clusters, [
+            'name',
+            'id',
+            'status',
+            'node_count'
+        ])
diff --git a/tempest/clients.py b/tempest/clients.py
index 7ebd983..6d27417 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -78,6 +78,8 @@
     InterfacesV3ClientJSON
 from tempest.services.compute.v3.json.keypairs_client import \
     KeyPairsV3ClientJSON
+from tempest.services.compute.v3.json.migration_client import \
+    MigrationsV3ClientJSON
 from tempest.services.compute.v3.json.quotas_client import \
     QuotasV3ClientJSON
 from tempest.services.compute.v3.json.servers_client import \
@@ -325,6 +327,8 @@
             self.tenant_usages_client = TenantUsagesClientJSON(
                 self.auth_provider)
             self.version_v3_client = VersionV3ClientJSON(self.auth_provider)
+            self.migrations_v3_client = MigrationsV3ClientJSON(
+                self.auth_provider)
             self.policy_client = PolicyClientJSON(self.auth_provider)
             self.hosts_client = HostsClientJSON(self.auth_provider)
             self.hypervisor_v3_client = HypervisorV3ClientJSON(
diff --git a/tempest/common/generator/base_generator.py b/tempest/common/generator/base_generator.py
index 95d50e2..87d65d0 100644
--- a/tempest/common/generator/base_generator.py
+++ b/tempest/common/generator/base_generator.py
@@ -87,12 +87,6 @@
         "additionalProperties": False,
     }
 
-    def __new__(cls, *args, **kwargs):
-        if not cls._instance:
-            cls._instance = super(BasicGeneratorSet, cls).__new__(cls, *args,
-                                                                  **kwargs)
-        return cls._instance
-
     def __init__(self):
         self.types_dict = {}
         for m in dir(self):
diff --git a/tempest/common/glance_http.py b/tempest/common/glance_http.py
index b4ba933..9358851 100644
--- a/tempest/common/glance_http.py
+++ b/tempest/common/glance_http.py
@@ -19,6 +19,7 @@
 import hashlib
 import httplib
 import json
+import OpenSSL
 import posixpath
 import re
 from six import moves
@@ -27,14 +28,6 @@
 import struct
 import urlparse
 
-
-# Python 2.5 compat fix
-if not hasattr(urlparse, 'parse_qsl'):
-    import cgi
-    urlparse.parse_qsl = cgi.parse_qsl
-
-import OpenSSL
-
 from tempest import exceptions as exc
 from tempest.openstack.common import log as logging
 
@@ -50,7 +43,7 @@
         self.auth_provider = auth_provider
         self.filters = filters
         self.endpoint = auth_provider.base_url(filters)
-        endpoint_parts = self.parse_endpoint(self.endpoint)
+        endpoint_parts = urlparse.urlparse(self.endpoint)
         self.endpoint_scheme = endpoint_parts.scheme
         self.endpoint_hostname = endpoint_parts.hostname
         self.endpoint_port = endpoint_parts.port
@@ -61,10 +54,6 @@
             self.endpoint_scheme, **kwargs)
 
     @staticmethod
-    def parse_endpoint(endpoint):
-        return urlparse.urlparse(endpoint)
-
-    @staticmethod
     def get_connection_class(scheme):
         if scheme == 'https':
             return VerifiedHTTPSConnection
@@ -107,7 +96,7 @@
         conn = self.get_connection()
 
         try:
-            url_parts = self.parse_endpoint(url)
+            url_parts = urlparse.urlparse(url)
             conn_url = posixpath.normpath(url_parts.path)
             LOG.debug('Actual Path: {path}'.format(path=conn_url))
             if kwargs['headers'].get('Transfer-Encoding') == 'chunked':
@@ -134,7 +123,6 @@
             raise exc.TimeoutException(message)
 
         body_iter = ResponseBodyIterator(resp)
-
         # Read body into string if it isn't obviously image data
         if resp.getheader('content-type', None) != 'application/octet-stream':
             body_str = ''.join([body_chunk for body_chunk in body_iter])
@@ -178,7 +166,7 @@
 
         resp, body_iter = self._http_request(url, method, **kwargs)
 
-        if 'application/json' in resp.getheader('content-type', None):
+        if 'application/json' in resp.getheader('content-type', ''):
             body = ''.join([chunk for chunk in body_iter])
             try:
                 body = json.loads(body)
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index f7a3d6f..1092b94 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -71,6 +71,21 @@
     def _create_security_groups(self):
         self.security_groups[self.tenant_id] =\
             self._create_security_group_neutron(tenant_id=self.tenant_id)
+        self._create_security_group_rules_for_port(self.port1)
+        self._create_security_group_rules_for_port(self.port2)
+
+    def _create_security_group_rules_for_port(self, port):
+        rule = {
+            'direction': 'ingress',
+            'protocol': 'tcp',
+            'port_range_min': port,
+            'port_range_max': port,
+        }
+        self._create_security_group_rule(
+            client=self.network_client,
+            secgroup=self.security_groups[self.tenant_id],
+            tenant_id=self.tenant_id,
+            **rule)
 
     def _create_server(self):
         tenant_id = self.tenant_id
@@ -215,7 +230,6 @@
         self.assertEqual(5, resp.count("server1\n"))
         self.assertEqual(5, resp.count("server2\n"))
 
-    @test.skip_because(bug='1295165')
     @test.attr(type='smoke')
     @test.services('compute', 'network')
     def test_load_balancer_basic(self):
diff --git a/tempest/services/compute/json/fixed_ips_client.py b/tempest/services/compute/json/fixed_ips_client.py
index 5fdd564..f2d5cbe 100644
--- a/tempest/services/compute/json/fixed_ips_client.py
+++ b/tempest/services/compute/json/fixed_ips_client.py
@@ -39,4 +39,5 @@
         """This reserves and unreserves fixed ips."""
         url = "os-fixed-ips/%s/action" % (ip)
         resp, body = self.post(url, json.dumps(body))
+        self.validate_response(schema.fixed_ip_action, resp, body)
         return resp, body
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index eeb417a..a000e56 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -16,6 +16,7 @@
 import urllib
 
 from tempest.api_schema.compute import hosts as schema
+from tempest.api_schema.compute.v2 import hosts as v2_schema
 from tempest.common import rest_client
 from tempest import config
 
@@ -67,6 +68,7 @@
 
         resp, body = self.get("os-hosts/%s/startup" % str(hostname))
         body = json.loads(body)
+        self.validate_response(v2_schema.startup_host, resp, body)
         return resp, body['host']
 
     def shutdown_host(self, hostname):
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index 9267be7..7411fb7 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -111,11 +111,15 @@
         url = 'os-security-group-rules'
         resp, body = self.post(url, post_body)
         body = json.loads(body)
+        self.validate_response(schema.create_security_group_rule, resp, body)
         return resp, body['security_group_rule']
 
     def delete_security_group_rule(self, group_rule_id):
         """Deletes the provided Security Group rule."""
-        return self.delete('os-security-group-rules/%s' % str(group_rule_id))
+        resp, body = self.delete('os-security-group-rules/%s' %
+                                 str(group_rule_id))
+        self.validate_response(schema.delete_security_group_rule, resp, body)
+        return resp, body
 
     def list_security_group_rules(self, security_group_id):
         """List all rules for a security group."""
diff --git a/tempest/services/compute/v3/json/hosts_client.py b/tempest/services/compute/v3/json/hosts_client.py
index db7134c..558d4f7 100644
--- a/tempest/services/compute/v3/json/hosts_client.py
+++ b/tempest/services/compute/v3/json/hosts_client.py
@@ -16,6 +16,7 @@
 import urllib
 
 from tempest.api_schema.compute import hosts as schema
+from tempest.api_schema.compute.v3 import hosts as v3_schema
 from tempest.common import rest_client
 from tempest import config
 
@@ -67,6 +68,7 @@
 
         resp, body = self.get("os-hosts/%s/startup" % str(hostname))
         body = json.loads(body)
+        self.validate_response(v3_schema.startup_host, resp, body)
         return resp, body['host']
 
     def shutdown_host(self, hostname):
diff --git a/tempest/services/compute/v3/json/migration_client.py b/tempest/services/compute/v3/json/migration_client.py
new file mode 100644
index 0000000..efd39b7
--- /dev/null
+++ b/tempest/services/compute/v3/json/migration_client.py
@@ -0,0 +1,37 @@
+# Copyright 2014 NEC Corporation.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import urllib
+
+from tempest.common import rest_client
+from tempest import config
+
+CONF = config.CONF
+
+
+class MigrationsV3ClientJSON(rest_client.RestClient):
+
+    def __init__(self, auth_provider):
+        super(MigrationsV3ClientJSON, self).__init__(auth_provider)
+        self.service = CONF.compute.catalog_v3_type
+
+    def list_migrations(self, params=None):
+        """Lists all migrations."""
+
+        url = 'os-migrations'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        return resp, self._parse_resp(body)
diff --git a/tempest/services/compute/v3/json/quotas_client.py b/tempest/services/compute/v3/json/quotas_client.py
index a8507c4..870c22e 100644
--- a/tempest/services/compute/v3/json/quotas_client.py
+++ b/tempest/services/compute/v3/json/quotas_client.py
@@ -45,6 +45,7 @@
         url = 'os-quota-sets/%s/detail' % str(tenant_id)
         resp, body = self.get(url)
         body = json.loads(body)
+        self.validate_response(schema.quota_set_detail, resp, body)
         return resp, body['quota_set']
 
     def get_default_quota_set(self, tenant_id):
diff --git a/tempest/services/network/network_client_base.py b/tempest/services/network/network_client_base.py
index e21abe1..34c61b0 100644
--- a/tempest/services/network/network_client_base.py
+++ b/tempest/services/network/network_client_base.py
@@ -31,12 +31,15 @@
     'vpnservices': 'vpn',
     'ikepolicies': 'vpn',
     'metering_labels': 'metering',
-    'metering_label_rules': 'metering'
+    'metering_label_rules': 'metering',
+    'firewall_rules': 'fw',
+    'firewall_policies': 'fw',
+    'firewalls': 'fw'
 }
 
 # The following list represents resource names that do not require
 # changing underscore to a hyphen
-hyphen_exceptions = ["health_monitors"]
+hyphen_exceptions = ["health_monitors", "firewall_rules", "firewall_policies"]
 
 # map from resource name to a plural name
 # needed only for those which can't be constructed as name + 's'
@@ -44,7 +47,8 @@
     'security_groups': 'security_groups',
     'security_group_rules': 'security_group_rules',
     'ikepolicy': 'ikepolicies',
-    'quotas': 'quotas'
+    'quotas': 'quotas',
+    'firewall_policy': 'firewall_policies'
 }
 
 
diff --git a/tempest/tests/test_decorators.py b/tempest/tests/test_decorators.py
index ebf0ca0..804204a 100644
--- a/tempest/tests/test_decorators.py
+++ b/tempest/tests/test_decorators.py
@@ -13,6 +13,7 @@
 #    under the License.
 
 
+import mock
 import testtools
 
 from oslo.config import cfg
@@ -232,3 +233,19 @@
                           self._test_requires_ext_helper,
                           extension='enabled_ext',
                           service='bad_service')
+
+
+class TestSimpleNegativeDecorator(BaseDecoratorsTest):
+    @test.SimpleNegativeAutoTest
+    class FakeNegativeJSONTest(test.NegativeAutoTest):
+        _schema_file = 'fake/schemas/file.json'
+
+    def test_testfunc_exist(self):
+        self.assertIn("test_fake_negative", dir(self.FakeNegativeJSONTest))
+
+    @mock.patch('tempest.test.NegativeAutoTest.execute')
+    def test_testfunc_calls_execute(self, mock):
+        obj = self.FakeNegativeJSONTest("test_fake_negative")
+        self.assertIn("test_fake_negative", dir(obj))
+        obj.test_fake_negative()
+        mock.assert_called_once_with(self.FakeNegativeJSONTest._schema_file)