Merge "Check domain's enabled attribute strictly"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index b3aca42..56172f8 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -161,8 +161,9 @@
 # Timeout for Ironic power transitions. (integer value)
 #power_timeout = 60
 
-# Timeout for unprovisioning an Ironic node. (integer value)
-#unprovision_timeout = 60
+# Timeout for unprovisioning an Ironic node. Takes longer since Kilo
+# as Ironic performs an extra step in Node cleaning. (integer value)
+#unprovision_timeout = 300
 
 
 [boto]
diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py
index 2cf2e28..06e073d 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -89,15 +89,10 @@
     @test.idempotent_id('777b6f14-aca9-4758-9e84-38783cfa58bc')
     @test.services('network')
     def test_security_group_create_with_invalid_group_description(self):
-        # Negative test:Security Group should not be created with description
-        # as an empty string/with white spaces/chars more than 255
+        # Negative test: Security Group should not be created with description
+        # longer than 255 chars. Empty description is allowed by the API
+        # reference, however.
         s_name = data_utils.rand_name('securitygroup')
-        # Create Security Group with empty string as description
-        self.assertRaises(lib_exc.BadRequest,
-                          self.client.create_security_group, s_name, "")
-        # Create Security Group with white space in description
-        self.assertRaises(lib_exc.BadRequest,
-                          self.client.create_security_group, s_name, " ")
         # Create Security Group with group description longer than 255 chars
         s_description = 'description-'.ljust(260, '0')
         self.assertRaises(lib_exc.BadRequest,
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index d7607ab..7a91cab 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 from tempest_lib.common.utils import data_utils
-from tempest_lib import decorators
 from tempest_lib import exceptions as lib_exc
 
 from tempest.api.compute import base
@@ -290,8 +289,6 @@
         self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
         self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
 
-    @decorators.skip_because(bug="1182883",
-                             condition=CONF.service_available.neutron)
     @test.idempotent_id('a905e287-c35e-42f2-b132-d02b09f3654a')
     def test_list_servers_filtered_by_ip_regex(self):
         # Filter servers by regex ip
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 1cd1386..f864f95 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -123,10 +123,6 @@
             for floating_ip in cls.floating_ips:
                 cls._try_delete_resource(cls.client.delete_floatingip,
                                          floating_ip['id'])
-            # Clean up routers
-            for router in cls.routers:
-                cls._try_delete_resource(cls.delete_router,
-                                         router)
 
             # Clean up health monitors
             for health_monitor in cls.health_monitors:
@@ -158,6 +154,10 @@
             for port in cls.ports:
                 cls._try_delete_resource(cls.client.delete_port,
                                          port['id'])
+            # Clean up routers
+            for router in cls.routers:
+                cls._try_delete_resource(cls.delete_router,
+                                         router)
             # Clean up subnets
             for subnet in cls.subnets:
                 cls._try_delete_resource(cls.client.delete_subnet,
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index ca08fbd..5d798e3 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -193,13 +193,10 @@
                         self.network, **kwargs_dhcp)
                     subnet_slaac = self.create_subnet(self.network, **kwargs)
                 port_mac = data_utils.rand_mac_address()
-                dhcp_ip = subnet_dhcp["allocation_pools"][0]["start"]
                 eui_ip = data_utils.get_ipv6_addr_by_EUI64(
                     subnet_slaac['cidr'],
                     port_mac
                 ).format()
-                # TODO(sergsh): remove this when 1219795 is fixed
-                dhcp_ip = [dhcp_ip, (netaddr.IPAddress(dhcp_ip) + 1).format()]
                 port = self.create_port(self.network, mac_address=port_mac)
                 real_ips = dict([(k['subnet_id'], k['ip_address'])
                                  for k in port['fixed_ips']])
@@ -217,11 +214,10 @@
                                  'Real IP is {0}, but shall be {1}'.format(
                                      real_eui_ip,
                                      eui_ip))
-                self.assertIn(
-                    real_dhcp_ip, dhcp_ip,
-                    'Real IP is {0}, but shall be one from {1}'.format(
-                        real_dhcp_ip,
-                        str(dhcp_ip)))
+                msg = ('Real IP address is {0} and it is NOT on '
+                       'subnet {1}'.format(real_dhcp_ip, subnet_dhcp['cidr']))
+                self.assertIn(netaddr.IPAddress(real_dhcp_ip),
+                              netaddr.IPNetwork(subnet_dhcp['cidr']), msg)
 
     @test.idempotent_id('4256c61d-c538-41ea-9147-3c450c36669e')
     def test_dhcpv6_64_subnets(self):
@@ -246,13 +242,10 @@
                         self.network, ip_version=4)
                     subnet_slaac = self.create_subnet(self.network, **kwargs)
                 port_mac = data_utils.rand_mac_address()
-                dhcp_ip = subnet_dhcp["allocation_pools"][0]["start"]
                 eui_ip = data_utils.get_ipv6_addr_by_EUI64(
                     subnet_slaac['cidr'],
                     port_mac
                 ).format()
-                # TODO(sergsh): remove this when 1219795 is fixed
-                dhcp_ip = [dhcp_ip, (netaddr.IPAddress(dhcp_ip) + 1).format()]
                 port = self.create_port(self.network, mac_address=port_mac)
                 real_ips = dict([(k['subnet_id'], k['ip_address'])
                                  for k in port['fixed_ips']])
@@ -260,23 +253,20 @@
                                              for sub in [subnet_dhcp,
                                              subnet_slaac]]
                 self._clean_network()
-                self.assertTrue({real_eui_ip,
-                                 real_dhcp_ip}.issubset([eui_ip] + dhcp_ip))
                 self.assertEqual(real_eui_ip,
                                  eui_ip,
                                  'Real IP is {0}, but shall be {1}'.format(
                                      real_eui_ip,
                                      eui_ip))
-                self.assertIn(
-                    real_dhcp_ip, dhcp_ip,
-                    'Real IP is {0}, but shall be one from {1}'.format(
-                        real_dhcp_ip,
-                        str(dhcp_ip)))
+                msg = ('Real IP address is {0} and it is NOT on '
+                       'subnet {1}'.format(real_dhcp_ip, subnet_dhcp['cidr']))
+                self.assertIn(netaddr.IPAddress(real_dhcp_ip),
+                              netaddr.IPNetwork(subnet_dhcp['cidr']), msg)
 
     @test.idempotent_id('4ab211a0-276f-4552-9070-51e27f58fecf')
     def test_dhcp_stateful(self):
-        """With all options below, DHCPv6 shall allocate first
-        address from subnet pool to port.
+        """With all options below, DHCPv6 shall allocate address
+        from subnet pool to port.
         """
         for ra_mode, add_mode in (
                 ('dhcpv6-stateful', 'dhcpv6-stateful'),
@@ -289,15 +279,11 @@
             subnet = self.create_subnet(self.network, **kwargs)
             port = self.create_port(self.network)
             port_ip = next(iter(port['fixed_ips']), None)['ip_address']
-            dhcp_ip = subnet["allocation_pools"][0]["start"]
-            # TODO(sergsh): remove this when 1219795 is fixed
-            dhcp_ip = [dhcp_ip, (netaddr.IPAddress(dhcp_ip) + 1).format()]
             self._clean_network()
-            self.assertIn(
-                port_ip, dhcp_ip,
-                'Real IP is {0}, but shall be one from {1}'.format(
-                    port_ip,
-                    str(dhcp_ip)))
+            msg = ('Real IP address is {0} and it is NOT on '
+                   'subnet {1}'.format(port_ip, subnet['cidr']))
+            self.assertIn(netaddr.IPAddress(port_ip),
+                          netaddr.IPNetwork(subnet['cidr']), msg)
 
     @test.idempotent_id('51a5e97f-f02e-4e4e-9a17-a69811d300e3')
     def test_dhcp_stateful_fixedips(self):
diff --git a/tempest/api/network/test_fwaas_extensions.py b/tempest/api/network/test_fwaas_extensions.py
index 0622e87..651b4ab 100644
--- a/tempest/api/network/test_fwaas_extensions.py
+++ b/tempest/api/network/test_fwaas_extensions.py
@@ -99,8 +99,13 @@
 
         if not test.call_until_true(_wait, CONF.network.build_timeout,
                                     CONF.network.build_interval):
-            m = ("Timed out waiting for firewall %s to reach %s state(s)" %
-                 (fw_id, target_states))
+            status = self.client.show_firewall(fw_id)['firewall']['status']
+            m = ("Timed out waiting for firewall %s to reach %s state(s) "
+                 "after %ss, currently in %s state." %
+                 (fw_id,
+                  target_states,
+                  CONF.network.build_interval,
+                  status))
             raise exceptions.TimeoutException(m)
 
     @test.idempotent_id('1b84cf01-9c09-4ce7-bc72-b15e39076468')
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 7b6b25b..29600c5 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -150,6 +150,34 @@
                  if port['id'] == self.port['id']]
         self.assertNotEmpty(ports, "Created port not found in the list")
 
+    @test.idempotent_id('e7fe260b-1e79-4dd3-86d9-bec6a7959fc5')
+    def test_port_list_filter_by_ip(self):
+        # Create network and subnet
+        network = self.create_network()
+        subnet = self.create_subnet(network)
+        self.addCleanup(self.client.delete_subnet, subnet['id'])
+        # Create two ports specifying a fixed_ips
+        address = self._get_ipaddress_from_tempest_conf()
+        _fixed_ip_1 = str(address + 3)
+        _fixed_ip_2 = str(address + 4)
+        fixed_ips_1 = [{'ip_address': _fixed_ip_1}]
+        port_1 = self.client.create_port(network_id=network['id'],
+                                         fixed_ips=fixed_ips_1)
+        self.addCleanup(self.client.delete_port, port_1['port']['id'])
+        fixed_ips_2 = [{'ip_address': _fixed_ip_2}]
+        port_2 = self.client.create_port(network_id=network['id'],
+                                         fixed_ips=fixed_ips_2)
+        self.addCleanup(self.client.delete_port, port_2['port']['id'])
+        # List ports filtered by fixed_ips
+        fixed_ips = 'ip_address=' + _fixed_ip_1
+        port_list = self.client.list_ports(fixed_ips=fixed_ips)
+        ports = port_list['ports']
+        self.assertEqual(len(ports), 1)
+        self.assertEqual(ports[0]['id'], port_1['port']['id'])
+        self.assertEqual(ports[0]['fixed_ips'][0]['ip_address'],
+                         _fixed_ip_1)
+        self.assertEqual(ports[0]['network_id'], network['id'])
+
     @test.idempotent_id('5ad01ed0-0e6e-4c5d-8194-232801b15c72')
     def test_port_list_filter_by_router_id(self):
         # Create a router
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
index 7df0dde..6fc7821 100644
--- a/tempest/api/object_storage/test_object_slo.py
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -110,6 +110,7 @@
         self.assertHeaders(resp, 'Object', method)
 
     @test.idempotent_id('2c3f24a6-36e8-4711-9aa2-800ee1fc7b5b')
+    @test.requires_ext(extension='slo', service='object')
     def test_upload_manifest(self):
         # create static large object from multipart manifest
         manifest = self._create_manifest()
@@ -124,6 +125,7 @@
         self._assertHeadersSLO(resp, 'PUT')
 
     @test.idempotent_id('e69ad766-e1aa-44a2-bdd2-bf62c09c1456')
+    @test.requires_ext(extension='slo', service='object')
     def test_list_large_object_metadata(self):
         # list static large object metadata using multipart manifest
         object_name = self._create_large_object()
@@ -135,6 +137,7 @@
         self._assertHeadersSLO(resp, 'HEAD')
 
     @test.idempotent_id('49bc49bc-dd1b-4c0f-904e-d9f10b830ee8')
+    @test.requires_ext(extension='slo', service='object')
     def test_retrieve_large_object(self):
         # list static large object using multipart manifest
         object_name = self._create_large_object()
@@ -149,6 +152,7 @@
         self.assertEqual(body, sum_data)
 
     @test.idempotent_id('87b6dfa1-abe9-404d-8bf0-6c3751e6aa77')
+    @test.requires_ext(extension='slo', service='object')
     def test_delete_large_object(self):
         # delete static large object using multipart manifest
         object_name = self._create_large_object()
diff --git a/tempest/config.py b/tempest/config.py
index 603ccd2..bbd6772 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -1114,8 +1114,10 @@
                default=60,
                help="Timeout for Ironic power transitions."),
     cfg.IntOpt('unprovision_timeout',
-               default=60,
-               help="Timeout for unprovisioning an Ironic node.")
+               default=300,
+               help="Timeout for unprovisioning an Ironic node. "
+                    "Takes longer since Kilo as Ironic performs an extra "
+                    "step in Node cleaning.")
 ]
 
 negative_group = cfg.OptGroup(name='negative', title="Negative Test Options")
diff --git a/tempest/scenario/test_large_ops.py b/tempest/scenario/test_large_ops.py
index 0789c21..56d4c7d 100644
--- a/tempest/scenario/test_large_ops.py
+++ b/tempest/scenario/test_large_ops.py
@@ -17,6 +17,7 @@
 from tempest_lib.common.utils import data_utils
 from tempest_lib import exceptions as lib_exc
 
+from tempest.common import fixed_network
 from tempest import config
 from tempest.scenario import manager
 from tempest import test
@@ -87,13 +88,18 @@
             'secgroup-%s' % name, 'secgroup-desc-%s' % name)
         self.addCleanupClass(self.security_groups_client.delete_security_group,
                              secgroup['id'])
-
+        create_kwargs = {
+            'min_count': CONF.scenario.large_ops_number,
+            'security_groups': [{'name': secgroup['name']}]
+            }
+        network = self.get_tenant_network()
+        create_kwargs = fixed_network.set_networks_kwarg(network,
+                                                         create_kwargs)
         self.servers_client.create_server(
             name,
             self.image,
             flavor_id,
-            min_count=CONF.scenario.large_ops_number,
-            security_groups=[{'name': secgroup['name']}])
+            **create_kwargs)
         # needed because of bug 1199788
         params = {'name': name}
         server_list = self.servers_client.list_servers(params)
diff --git a/tempest/tests/cmd/test_javelin.py b/tempest/tests/cmd/test_javelin.py
index 860599b..f98f8ba 100644
--- a/tempest/tests/cmd/test_javelin.py
+++ b/tempest/tests/cmd/test_javelin.py
@@ -28,6 +28,39 @@
         self.fake_client = mock.MagicMock()
         self.fake_object = mock.MagicMock()
 
+    def test_load_resources(self):
+        with mock.patch('six.moves.builtins.open', mock.mock_open(),
+                        create=True) as open_mock:
+            with mock.patch('yaml.load', mock.MagicMock(),
+                            create=True) as load_mock:
+                javelin.load_resources(self.fake_object)
+                load_mock.assert_called_once_with(open_mock(self.fake_object))
+
+    def test_keystone_admin(self):
+        self.useFixture(mockpatch.PatchObject(javelin, "OSClient"))
+        javelin.OPTS = self.fake_object
+        javelin.keystone_admin()
+        javelin.OSClient.assert_called_once_with(
+            self.fake_object.os_username,
+            self.fake_object.os_password,
+            self.fake_object.os_tenant_name)
+
+    def test_client_for_user(self):
+        fake_user = mock.MagicMock()
+        javelin.USERS = {fake_user['name']: fake_user}
+        self.useFixture(mockpatch.PatchObject(javelin, "OSClient"))
+        javelin.client_for_user(fake_user['name'])
+        javelin.OSClient.assert_called_once_with(
+            fake_user['name'], fake_user['pass'], fake_user['tenant'])
+
+    def test_client_for_non_existing_user(self):
+        fake_non_existing_user = self.fake_object
+        fake_user = mock.MagicMock()
+        javelin.USERS = {fake_user['name']: fake_user}
+        self.useFixture(mockpatch.PatchObject(javelin, "OSClient"))
+        javelin.client_for_user(fake_non_existing_user['name'])
+        self.assertFalse(javelin.OSClient.called)
+
 
 class TestCreateResources(JavelinUnitTest):
     def test_create_tenants(self):