Merge "Make the wait_for_server_status timeout message a bit more clear"
diff --git a/tempest/api/compute/__init__.py b/tempest/api/compute/__init__.py
index dd92ee9..d20068e 100644
--- a/tempest/api/compute/__init__.py
+++ b/tempest/api/compute/__init__.py
@@ -16,7 +16,6 @@
# under the License.
from tempest import config
-from tempest.exceptions import InvalidConfiguration
from tempest.openstack.common import log as logging
LOG = logging.getLogger(__name__)
@@ -26,29 +25,3 @@
RESIZE_AVAILABLE = CONFIG.compute_feature_enabled.resize
CHANGE_PASSWORD_AVAILABLE = CONFIG.compute_feature_enabled.change_password
DISK_CONFIG_ENABLED = CONFIG.compute_feature_enabled.disk_config
-MULTI_USER = True
-
-
-# All compute tests -- single setup function
-def generic_setup_package():
- LOG.debug("Entering tempest.api.compute.setup_package")
-
- global MULTI_USER
-
- # Determine if there are two regular users that can be
- # used in testing. If the test cases are allowed to create
- # users (config.compute.allow_tenant_isolation is true,
- # then we allow multi-user.
- if not CONFIG.compute.allow_tenant_isolation:
- user1 = CONFIG.identity.username
- user2 = CONFIG.identity.alt_username
- if not user2 or user1 == user2:
- MULTI_USER = False
- else:
- user2_password = CONFIG.identity.alt_password
- user2_tenant_name = CONFIG.identity.alt_tenant_name
- if not user2_password or not user2_tenant_name:
- msg = ("Alternate user specified but not alternate "
- "tenant or password: alt_tenant_name=%s alt_password=%s"
- % (user2_tenant_name, user2_password))
- raise InvalidConfiguration(msg)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 3c00851..d18b749 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -17,7 +17,6 @@
import time
-from tempest.api import compute
from tempest import clients
from tempest.common.utils import data_utils
from tempest import exceptions
@@ -31,7 +30,6 @@
class BaseComputeTest(tempest.test.BaseTestCase):
"""Base test case class for all Compute API tests."""
- conclusion = compute.generic_setup_package()
force_tenant_isolation = False
@classmethod
@@ -55,6 +53,30 @@
cls.image_ssh_password = cls.config.compute.image_ssh_password
cls.servers = []
cls.images = []
+ cls.multi_user = cls.get_multi_user()
+
+ @classmethod
+ def get_multi_user(cls):
+ multi_user = True
+ # Determine if there are two regular users that can be
+ # used in testing. If the test cases are allowed to create
+ # users (config.compute.allow_tenant_isolation is true,
+ # then we allow multi-user.
+ if not cls.config.compute.allow_tenant_isolation:
+ user1 = cls.config.identity.username
+ user2 = cls.config.identity.alt_username
+ if not user2 or user1 == user2:
+ multi_user = False
+ else:
+ user2_password = cls.config.identity.alt_password
+ user2_tenant_name = cls.config.identity.alt_tenant_name
+ if not user2_password or not user2_tenant_name:
+ msg = ("Alternate user specified but not alternate "
+ "tenant or password: alt_tenant_name=%s "
+ "alt_password=%s"
+ % (user2_tenant_name, user2_password))
+ raise exceptions.InvalidConfiguration(msg)
+ return multi_user
@classmethod
def clear_servers(cls):
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index fa99422..092fd65 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -16,7 +16,6 @@
# under the License.
from tempest.api.compute import base
-from tempest import exceptions
from tempest.test import attr
@@ -50,12 +49,6 @@
resp, flavor = self.client.get_flavor_details(self.flavor_ref)
self.assertEqual(self.flavor_ref, flavor['id'])
- @attr(type=['negative', 'gate'])
- def test_get_non_existant_flavor(self):
- # flavor details are not returned for non-existent flavors
- self.assertRaises(exceptions.NotFound, self.client.get_flavor_details,
- 999)
-
@attr(type='gate')
def test_list_flavors_limit_results(self):
# Only the expected number of flavors should be returned
@@ -136,24 +129,6 @@
resp, flavors = self.client.list_flavors(params)
self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
- @attr(type=['negative', 'gate'])
- def test_invalid_minRam_filter(self):
- self.assertRaises(exceptions.BadRequest,
- self.client.list_flavors_with_detail,
- {'minRam': 'invalid'})
-
- @attr(type=['negative', 'gate'])
- def test_invalid_minDisk_filter(self):
- self.assertRaises(exceptions.BadRequest,
- self.client.list_flavors_with_detail,
- {'minDisk': 'invalid'})
-
- @attr(type=['negative', 'gate'])
- def test_get_flavor_details_for_invalid_flavor_id(self):
- # Ensure 404 returned for non-existent flavor ID
- self.assertRaises(exceptions.NotFound, self.client.get_flavor_details,
- 9999)
-
class FlavorsTestXML(FlavorsTestJSON):
_interface = 'xml'
diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py
new file mode 100644
index 0000000..81e4f87
--- /dev/null
+++ b/tempest/api/compute/flavors/test_flavors_negative.py
@@ -0,0 +1,69 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 OpenStack Foundation
+# 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 uuid
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class FlavorsNegativeTestJSON(base.BaseV2ComputeTest):
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(FlavorsNegativeTestJSON, cls).setUpClass()
+ cls.client = cls.flavors_client
+
+ # Generating a nonexistent flavor id
+ resp, flavors = cls.client.list_flavors()
+ flavor_ids = [flavor['id'] for flavor in flavors]
+ while True:
+ cls.nonexistent_flavor_id = data_utils.rand_int_id(start=999)
+ if cls.nonexistent_flavor_id not in flavor_ids:
+ break
+
+ @attr(type=['negative', 'gate'])
+ def test_invalid_minRam_filter(self):
+ self.assertRaises(exceptions.BadRequest,
+ self.client.list_flavors_with_detail,
+ {'minRam': 'invalid'})
+
+ @attr(type=['negative', 'gate'])
+ def test_invalid_minDisk_filter(self):
+ self.assertRaises(exceptions.BadRequest,
+ self.client.list_flavors_with_detail,
+ {'minDisk': 'invalid'})
+
+ @attr(type=['negative', 'gate'])
+ def test_get_flavor_details_for_invalid_flavor_id(self):
+ # Ensure 404 returned for invalid flavor ID
+ invalid_flavor_id = str(uuid.uuid4())
+ self.assertRaises(exceptions.NotFound, self.client.get_flavor_details,
+ invalid_flavor_id)
+
+ @attr(type=['negative', 'gate'])
+ def test_non_existent_flavor_id(self):
+ # flavor details are not returned for non-existent flavors
+ self.assertRaises(exceptions.NotFound, self.client.get_flavor_details,
+ self.nonexistent_flavor_id)
+
+
+class FlavorsNegativeTestXML(FlavorsNegativeTestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index 55260bf..f7db89b 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -14,7 +14,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api import compute
from tempest.api.compute import base
from tempest import clients
from tempest.common.utils import data_utils
@@ -36,7 +35,7 @@
cls.image_ids = []
- if compute.MULTI_USER:
+ if cls.multi_user:
if cls.config.compute.allow_tenant_isolation:
creds = cls.isolated_creds.get_alt_creds()
username, tenant_name, password = creds
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 19a308a..b0ff7ab 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -68,7 +68,7 @@
cls.image_ids = []
- if compute.MULTI_USER:
+ if cls.multi_user:
if cls.config.compute.allow_tenant_isolation:
creds = cls.isolated_creds.get_alt_creds()
username, tenant_name, password = creds
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index 6757e8a..ea6608c 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -16,7 +16,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api import compute
from tempest.api.compute import base
from tempest import clients
from tempest.common.utils import data_utils
@@ -69,7 +68,7 @@
cls.image_ids = []
- if compute.MULTI_USER:
+ if cls.multi_user:
if cls.config.compute.allow_tenant_isolation:
creds = cls.isolated_creds.get_alt_creds()
username, tenant_name, password = creds
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index f244155..3c40e80 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -296,6 +296,14 @@
self.assertEqual((backup2, backup3),
(image_list[0]['name'], image_list[1]['name']))
+ def _get_output(self):
+ resp, output = self.servers_client.get_console_output(
+ self.server_id, 10)
+ self.assertEqual(200, resp.status)
+ self.assertTrue(output, "Console output was empty.")
+ lines = len(output.split('\n'))
+ self.assertEqual(lines, 10)
+
@attr(type='gate')
def test_get_console_output(self):
# Positive test:Should be able to GET the console output
@@ -310,29 +318,24 @@
self.assertEqual(202, resp.status)
self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
- def get_output():
- resp, output = self.servers_client.get_console_output(
- self.server_id, 10)
- self.assertEqual(200, resp.status)
- self.assertTrue(output, "Console output was empty.")
- lines = len(output.split('\n'))
- self.assertEqual(lines, 10)
- self.wait_for(get_output)
+ self.wait_for(self._get_output)
- @skip_because(bug="1014683")
@attr(type='gate')
- def test_get_console_output_server_id_in_reboot_status(self):
+ def test_get_console_output_server_id_in_shutoff_status(self):
# Positive test:Should be able to GET the console output
- # for a given server_id in reboot status
- resp, output = self.servers_client.reboot(self.server_id, 'SOFT')
- self.servers_client.wait_for_server_status(self.server_id,
- 'REBOOT')
- resp, output = self.servers_client.get_console_output(self.server_id,
- 10)
- self.assertEqual(200, resp.status)
- self.assertIsNotNone(output)
- lines = len(output.split('\n'))
- self.assertEqual(lines, 10)
+ # for a given server_id in SHUTOFF status
+
+ # NOTE: SHUTOFF is irregular status. To avoid test instability,
+ # one server is created only for this test without using
+ # the server that was created in setupClass.
+ resp, server = self.create_test_server(wait_until='ACTIVE')
+ temp_server_id = server['id']
+
+ resp, server = self.servers_client.stop(temp_server_id)
+ self.assertEqual(202, resp.status)
+ self.servers_client.wait_for_server_status(temp_server_id, 'SHUTOFF')
+
+ self.wait_for(self._get_output)
@attr(type='gate')
def test_pause_unpause_server(self):
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index 49c4f32..327c7d1 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -15,7 +15,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api import compute
from tempest.api.compute import base
from tempest import clients
from tempest.common.utils import data_utils
@@ -31,12 +30,10 @@
@classmethod
def setUpClass(cls):
- if not compute.MULTI_USER:
+ super(AuthorizationTestJSON, cls).setUpClass()
+ if not cls.multi_user:
msg = "Need >1 user"
raise cls.skipException(msg)
-
- super(AuthorizationTestJSON, cls).setUpClass()
-
cls.client = cls.os.servers_client
cls.images_client = cls.os.images_client
cls.keypairs_client = cls.os.keypairs_client
@@ -85,7 +82,7 @@
@classmethod
def tearDownClass(cls):
- if compute.MULTI_USER:
+ if cls.multi_user:
cls.images_client.delete_image(cls.image['id'])
cls.keypairs_client.delete_keypair(cls.keypairname)
cls.security_client.delete_security_group(cls.security_group['id'])
diff --git a/tempest/api/compute/v3/images/test_images.py b/tempest/api/compute/v3/images/test_images.py
index 3aacafb..a179d65 100644
--- a/tempest/api/compute/v3/images/test_images.py
+++ b/tempest/api/compute/v3/images/test_images.py
@@ -14,7 +14,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.api import compute
from tempest.api.compute import base
from tempest import clients
from tempest.common.utils import data_utils
@@ -34,7 +33,7 @@
cls.client = cls.images_client
cls.servers_client = cls.servers_client
- if compute.MULTI_USER:
+ if cls.multi_user:
if cls.config.compute.allow_tenant_isolation:
creds = cls.isolated_creds.get_alt_creds()
username, tenant_name, password = creds
diff --git a/tempest/api/compute/v3/servers/test_list_servers_negative.py b/tempest/api/compute/v3/servers/test_list_servers_negative.py
index 6225345..3f7f885 100644
--- a/tempest/api/compute/v3/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/v3/servers/test_list_servers_negative.py
@@ -17,7 +17,6 @@
import datetime
-from tempest.api import compute
from tempest.api.compute import base
from tempest import clients
from tempest import exceptions
@@ -53,7 +52,7 @@
cls.client = cls.servers_client
cls.servers = []
- if compute.MULTI_USER:
+ if cls.multi_user:
if cls.config.compute.allow_tenant_isolation:
creds = cls.isolated_creds.get_alt_creds()
username, tenant_name, password = creds
diff --git a/tempest/api/network/test_vpnaas_extensions.py b/tempest/api/network/test_vpnaas_extensions.py
index 7905b97..63a8e24 100644
--- a/tempest/api/network/test_vpnaas_extensions.py
+++ b/tempest/api/network/test_vpnaas_extensions.py
@@ -40,7 +40,9 @@
super(VPNaaSJSON, cls).setUpClass()
cls.network = cls.create_network()
cls.subnet = cls.create_subnet(cls.network)
- cls.router = cls.create_router(data_utils.rand_name("router-"))
+ cls.router = cls.create_router(
+ data_utils.rand_name("router-"),
+ external_network_id=cls.network_cfg.public_network_id)
cls.create_router_interface(cls.router['id'], cls.subnet['id'])
cls.vpnservice = cls.create_vpnservice(cls.subnet['id'],
cls.router['id'])
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 06841e1..0066a73 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -537,6 +537,27 @@
routers = self.network_client.list_routers()
return routers['routers']
+ def _list_ports(self):
+ ports = self.network_client.list_ports()
+ return ports['ports']
+
+ def _get_tenant_own_network_num(self, tenant_id):
+ nets = self._list_networks()
+ ownnets = [value for value in nets if tenant_id == value['tenant_id']]
+ return len(ownnets)
+
+ def _get_tenant_own_subnet_num(self, tenant_id):
+ subnets = self._list_subnets()
+ ownsubnets = ([value for value in subnets
+ if tenant_id == value['tenant_id']])
+ return len(ownsubnets)
+
+ def _get_tenant_own_port_num(self, tenant_id):
+ ports = self._list_ports()
+ ownports = ([value for value in ports
+ if tenant_id == value['tenant_id']])
+ return len(ownports)
+
def _create_subnet(self, network, namestart='subnet-smoke-'):
"""
Create a subnet for the given network within the cidr block
@@ -801,6 +822,18 @@
return rules
+ def _show_quota_network(self, tenant_id):
+ quota = self.network_client.show_quota(tenant_id)
+ return quota['quota']['network']
+
+ def _show_quota_subnet(self, tenant_id):
+ quota = self.network_client.show_quota(tenant_id)
+ return quota['quota']['subnet']
+
+ def _show_quota_port(self, tenant_id):
+ quota = self.network_client.show_quota(tenant_id)
+ return quota['quota']['port']
+
class OrchestrationScenarioTest(OfficialClientTest):
"""
diff --git a/tempest/scenario/test_network_quotas.py b/tempest/scenario/test_network_quotas.py
index 3268066..cb7aa0b 100644
--- a/tempest/scenario/test_network_quotas.py
+++ b/tempest/scenario/test_network_quotas.py
@@ -20,8 +20,6 @@
from tempest.scenario.manager import NetworkScenarioTest
from tempest.test import services
-MAX_REASONABLE_ITERATIONS = 51 # more than enough. Default for port is 50.
-
class TestNetworkQuotaBasic(NetworkScenarioTest):
"""
@@ -46,7 +44,9 @@
@services('network')
def test_create_network_until_quota_hit(self):
hit_limit = False
- for n in xrange(MAX_REASONABLE_ITERATIONS):
+ networknum = self._get_tenant_own_network_num(self.tenant_id)
+ max = self._show_quota_network(self.tenant_id) - networknum
+ for n in xrange(max):
try:
self.networks.append(
self._create_network(self.tenant_id,
@@ -56,6 +56,16 @@
raise
hit_limit = True
break
+ self.assertFalse(hit_limit, "Failed: Hit quota limit !")
+
+ try:
+ self.networks.append(
+ self._create_network(self.tenant_id,
+ namestart='network-quotatest-'))
+ except exc.NeutronClientException as e:
+ if (e.status_code != 409):
+ raise
+ hit_limit = True
self.assertTrue(hit_limit, "Failed: Did not hit quota limit !")
@services('network')
@@ -65,7 +75,9 @@
self._create_network(self.tenant_id,
namestart='network-quotatest-'))
hit_limit = False
- for n in xrange(MAX_REASONABLE_ITERATIONS):
+ subnetnum = self._get_tenant_own_subnet_num(self.tenant_id)
+ max = self._show_quota_subnet(self.tenant_id) - subnetnum
+ for n in xrange(max):
try:
self.subnets.append(
self._create_subnet(self.networks[0],
@@ -75,6 +87,16 @@
raise
hit_limit = True
break
+ self.assertFalse(hit_limit, "Failed: Hit quota limit !")
+
+ try:
+ self.subnets.append(
+ self._create_subnet(self.networks[0],
+ namestart='subnet-quotatest-'))
+ except exc.NeutronClientException as e:
+ if (e.status_code != 409):
+ raise
+ hit_limit = True
self.assertTrue(hit_limit, "Failed: Did not hit quota limit !")
@services('network')
@@ -84,7 +106,9 @@
self._create_network(self.tenant_id,
namestart='network-quotatest-'))
hit_limit = False
- for n in xrange(MAX_REASONABLE_ITERATIONS):
+ portnum = self._get_tenant_own_port_num(self.tenant_id)
+ max = self._show_quota_port(self.tenant_id) - portnum
+ for n in xrange(max):
try:
self.ports.append(
self._create_port(self.networks[0],
@@ -94,4 +118,14 @@
raise
hit_limit = True
break
+ self.assertFalse(hit_limit, "Failed: Hit quota limit !")
+
+ try:
+ self.ports.append(
+ self._create_port(self.networks[0],
+ namestart='port-quotatest-'))
+ except exc.NeutronClientException as e:
+ if (e.status_code != 409):
+ raise
+ hit_limit = True
self.assertTrue(hit_limit, "Failed: Did not hit quota limit !")
diff --git a/tools/check_logs.py b/tools/check_logs.py
index 6d4436e..0c8fd21 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -27,6 +27,8 @@
is_neutron = os.environ.get('DEVSTACK_GATE_NEUTRON', "0") == "1"
+is_grenade = (os.environ.get('DEVSTACK_GATE_GRENADE', "0") == "1" or
+ os.environ.get('DEVSTACK_GATE_GRENADE_FORWARD', "0") == "1")
dump_all_errors = is_neutron
@@ -125,6 +127,9 @@
if is_neutron:
print("Currently not failing neutron builds with errors")
return 0
+ if is_grenade:
+ print("Currently not failing grenade runs with errors")
+ return 0
print("FAILED")
return 1
else:
diff --git a/tox.ini b/tox.ini
index e5698d2..9389cf4 100644
--- a/tox.ini
+++ b/tox.ini
@@ -9,6 +9,7 @@
LANGUAGE=en_US:en
LC_ALL=C
usedevelop = True
+install_command = pip install -U {opts} {packages}
[testenv:py26]
commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'