Merge "Merge the separated link lines on service client"
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index db6e682..23b16e7 100755
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -69,7 +69,7 @@
             self.tenant_id)['quota_set']
         ram = int(quota_set['ram'])
         if ram == -1:
-            raise self.skipException("default ram quota set is -1,"
+            raise self.skipException("ram quota set is -1,"
                                      " cannot test overlimit")
         ram += 1
         vcpus = 8
@@ -98,7 +98,7 @@
             self.tenant_id)['quota_set']
         vcpus = int(quota_set['cores'])
         if vcpus == -1:
-            raise self.skipException("default cores quota set is -1,"
+            raise self.skipException("cores quota set is -1,"
                                      " cannot test overlimit")
         vcpus += 1
         disk = 10
diff --git a/tempest/api/identity/admin/v2/test_users.py b/tempest/api/identity/admin/v2/test_users.py
index 8e63498..4a4b51a 100644
--- a/tempest/api/identity/admin/v2/test_users.py
+++ b/tempest/api/identity/admin/v2/test_users.py
@@ -234,4 +234,4 @@
         # Validate the updated password through getting a token.
         body = self.token_client.auth(user['name'], new_pass,
                                       tenant['name'])
-        self.assertTrue('id' in body['token'])
+        self.assertIn('id', body['token'])
diff --git a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
index 0400e76..8d12e75 100644
--- a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
+++ b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
@@ -72,10 +72,10 @@
         for outputs in stack['outputs']:
             output_map[outputs['output_key']] = outputs['output_value']
         # Test that first key generated public and private keys
-        self.assertTrue('KeyPair_PublicKey' in output_map)
-        self.assertTrue("Generated" in output_map['KeyPair_PublicKey'])
-        self.assertTrue('KeyPair_PrivateKey' in output_map)
-        self.assertTrue('-----BEGIN' in output_map['KeyPair_PrivateKey'])
+        self.assertIn('KeyPair_PublicKey', output_map)
+        self.assertIn("Generated", output_map['KeyPair_PublicKey'])
+        self.assertIn('KeyPair_PrivateKey', output_map)
+        self.assertIn('-----BEGIN', output_map['KeyPair_PrivateKey'])
         # Test that second key generated public key, and private key is not
         # in the output due to save_private_key = false
         self.assertTrue('KeyPairDontSavePrivate_PublicKey' in output_map)
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index d1549e2..ada55f7 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -175,7 +175,7 @@
             except Exception:
                 pass
 
-    def create_server(self, name, wait_for_deletion=False, **kwargs):
+    def create_server(self, name, **kwargs):
         tenant_network = self.get_tenant_network()
         body, _ = compute.create_test_server(
             self.os,
@@ -183,11 +183,9 @@
             name=name,
             **kwargs)
 
-        if wait_for_deletion:
-            self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                            waiters.wait_for_server_termination,
-                            self.servers_client, body['id'])
-
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        waiters.wait_for_server_termination,
+                        self.servers_client, body['id'])
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
                         self.servers_client.delete_server, body['id'])
         return body
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index 5bef7f3..e8ead5b 100755
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -179,7 +179,6 @@
         srv_name = data_utils.rand_name(self.__class__.__name__ + '-Instance')
         server = self.create_server(
             name=srv_name,
-            wait_for_deletion=True,
             wait_until='ACTIVE')
 
         self.assertRaises(lib_exc.NotFound,
diff --git a/tempest/config.py b/tempest/config.py
index 1d89eb0..f12e34e 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -304,6 +304,12 @@
                                       title="Enabled Compute Service Features")
 
 ComputeFeaturesGroup = [
+    # NOTE(mriedem): This is a feature toggle for bug 1175464 which is fixed in
+    # mitaka and newton. This option can be removed after liberty-eol.
+    cfg.BoolOpt('allow_port_security_disabled',
+                default=False,
+                help='Does the test environment support creating ports in a '
+                     'network where port security is disabled?'),
     cfg.BoolOpt('disk_config',
                 default=True,
                 help="If false, skip disk config tests"),
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index a88194c..2f31ea3 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -658,7 +658,8 @@
 
     def _create_network(self, networks_client=None,
                         routers_client=None, tenant_id=None,
-                        namestart='network-smoke-'):
+                        namestart='network-smoke-',
+                        port_security_enabled=True):
         if not networks_client:
             networks_client = self.networks_client
         if not routers_client:
@@ -666,7 +667,9 @@
         if not tenant_id:
             tenant_id = networks_client.tenant_id
         name = data_utils.rand_name(namestart)
-        result = networks_client.create_network(name=name, tenant_id=tenant_id)
+        network_kwargs = dict(name=name, tenant_id=tenant_id,
+                              port_security_enabled=port_security_enabled)
+        result = networks_client.create_network(**network_kwargs)
         network = result['network']
 
         self.assertEqual(network['name'], name)
@@ -1141,7 +1144,8 @@
 
     def create_networks(self, networks_client=None,
                         routers_client=None, subnets_client=None,
-                        tenant_id=None, dns_nameservers=None):
+                        tenant_id=None, dns_nameservers=None,
+                        port_security_enabled=True):
         """Create a network with a subnet connected to a router.
 
         The baremetal driver is a special case since all nodes are
@@ -1167,7 +1171,8 @@
         else:
             network = self._create_network(
                 networks_client=networks_client,
-                tenant_id=tenant_id)
+                tenant_id=tenant_id,
+                port_security_enabled=port_security_enabled)
             router = self._get_router(client=routers_client,
                                       tenant_id=tenant_id)
             subnet_kwargs = dict(network=network,
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 86185c8..b893aad 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 from oslo_log import log
+import testtools
 
 from tempest import clients
 from tempest.common.utils import data_utils
@@ -256,7 +257,7 @@
         # and distributed routers; 'device_owner' is "" by default.
         return port['device_owner'].startswith('network:router_interface')
 
-    def _create_server(self, name, tenant, security_groups=None, **kwargs):
+    def _create_server(self, name, tenant, security_groups, **kwargs):
         """Creates a server and assigns it to security group.
 
         If multi-host is enabled, Ensures servers are created on different
@@ -264,8 +265,6 @@
         as scheduler_hints on creation.
         Validates servers are created as requested, using admin client.
         """
-        if security_groups is None:
-            security_groups = [tenant.security_groups['default']]
         security_groups_names = [{'name': s['name']} for s in security_groups]
         if self.multi_node:
             kwargs["scheduler_hints"] = {'different_host': self.servers}
@@ -277,9 +276,10 @@
             wait_until='ACTIVE',
             clients=tenant.manager,
             **kwargs)
-        self.assertEqual(
-            sorted([s['name'] for s in security_groups]),
-            sorted([s['name'] for s in server['security_groups']]))
+        if 'security_groups' in server:
+            self.assertEqual(
+                sorted([s['name'] for s in security_groups]),
+                sorted([s['name'] for s in server['security_groups']]))
 
         # Verify servers are on different compute nodes
         if self.multi_node:
@@ -303,7 +303,8 @@
                    num=i
             )
             name = data_utils.rand_name(name)
-            server = self._create_server(name, tenant)
+            server = self._create_server(name, tenant,
+                                         [tenant.security_groups['default']])
             tenant.servers.append(server)
 
     def _set_access_point(self, tenant):
@@ -326,11 +327,12 @@
             client=tenant.manager.floating_ips_client)
         self.floating_ips.setdefault(server['id'], floating_ip)
 
-    def _create_tenant_network(self, tenant):
+    def _create_tenant_network(self, tenant, port_security_enabled=True):
         network, subnet, router = self.create_networks(
             networks_client=tenant.manager.networks_client,
             routers_client=tenant.manager.routers_client,
-            subnets_client=tenant.manager.subnets_client)
+            subnets_client=tenant.manager.subnets_client,
+            port_security_enabled=port_security_enabled)
         tenant.set_network(network, subnet, router)
 
     def _deploy_tenant(self, tenant_or_id):
@@ -533,7 +535,8 @@
                tenant=new_tenant.creds.tenant_name
         )
         name = data_utils.rand_name(name)
-        server = self._create_server(name, new_tenant)
+        server = self._create_server(name, new_tenant,
+                                     [new_tenant.security_groups['default']])
 
         # Check connectivity failure with default security group
         try:
@@ -599,7 +602,8 @@
                tenant=new_tenant.creds.tenant_name
         )
         name = data_utils.rand_name(name)
-        server = self._create_server(name, new_tenant)
+        server = self._create_server(name, new_tenant,
+                                     [new_tenant.security_groups['default']])
 
         access_point_ssh = self._connect_to_access_point(new_tenant)
         server_id = server['id']
@@ -624,3 +628,24 @@
             for tenant in self.tenants.values():
                 self._log_console_output(servers=tenant.servers)
             raise
+
+    @test.requires_ext(service='network', extension='port-security')
+    @test.idempotent_id('13ccf253-e5ad-424b-9c4a-97b88a026699')
+    @testtools.skipUnless(
+        CONF.compute_feature_enabled.allow_port_security_disabled,
+        'Port security must be enabled.')
+    @test.services('compute', 'network')
+    def test_boot_into_disabled_port_security_network_without_secgroup(self):
+        tenant = self.primary_tenant
+        self._create_tenant_network(tenant, port_security_enabled=False)
+        self.assertFalse(tenant.network['port_security_enabled'])
+        name = data_utils.rand_name('server-smoke')
+        sec_groups = []
+        server = self._create_server(name, tenant, sec_groups)
+        server_id = server['id']
+        ports = self._list_ports(device_id=server_id)
+        self.assertEqual(1, len(ports))
+        for port in ports:
+            self.assertEmpty(port['security_groups'],
+                             "Neutron shouldn't even use it's default sec "
+                             "group.")
diff --git a/tempest/tests/negative/test_negative_generators.py b/tempest/tests/negative/test_negative_generators.py
index 2e45ef7..7e1ee2c 100644
--- a/tempest/tests/negative/test_negative_generators.py
+++ b/tempest/tests/negative/test_negative_generators.py
@@ -107,7 +107,7 @@
 
     def _validate_result(self, valid_schema, invalid_schema):
         for k, v in six.iteritems(valid_schema):
-            self.assertTrue(k in invalid_schema)
+            self.assertIn(k, invalid_schema)
 
     def test_generator_mandatory_functions(self):
         for data_type in self.types: