Merge "White space after # in the tempest/services"
diff --git a/doc/source/index.rst b/doc/source/index.rst
index f012097..00c4e9a 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -33,6 +33,13 @@
field_guide/thirdparty
field_guide/whitebox
+------------------
+API and test cases
+------------------
+.. toctree::
+ :maxdepth: 1
+
+ api/modules
==================
Indices and tables
diff --git a/etc/logging.conf.sample b/etc/logging.conf.sample
index 685dd36..3b468f1 100644
--- a/etc/logging.conf.sample
+++ b/etc/logging.conf.sample
@@ -1,5 +1,5 @@
[loggers]
-keys=root,tempest
+keys=root,tempest,tempest_stress
[handlers]
keys=file,syslog,devel
@@ -16,6 +16,11 @@
handlers=file
qualname=tempest
+[logger_tempest_stress]
+level=INFO
+handlers=file,devel
+qualname=tempest.stress
+
[handler_file]
class=FileHandler
level=DEBUG
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 825965f..f1aaa07 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -1,7 +1,17 @@
[DEFAULT]
# log_config = /opt/stack/tempest/etc/logging.conf.sample
+
+# disable logging to the stderr
+use_stderr = False
+
+# log file
+log_file = tempest.log
+
+# lock/semaphore base directory
lock_path=/tmp
+default_log_levels=tempest.stress=INFO,amqplib=WARN,sqlalchemy=WARN,boto=WARN,suds=INFO,keystone=INFO,eventlet.wsgi.server=WARN
+
[identity]
# This section contains configuration options that a variety of Tempest
# test clients use when authenticating with different user/tenant
@@ -90,7 +100,7 @@
fixed_network_name = private
# Network id used for SSH (public, private, etc)
-network_for_ssh = private
+network_for_ssh = public
# IP version of the address used for SSH
ip_version_for_ssh = 4
@@ -259,6 +269,8 @@
# Number of seconds to wait while looping to check the status of a
# container to container synchronization
container_sync_interval = 5
+# Set to True if the Account Quota middleware is enabled
+accounts_quotas_available = True
[boto]
# This section contains configuration options used when executing tests
@@ -357,6 +369,8 @@
enabled = True
# directory where python client binaries are located
cli_dir = /usr/local/bin
+# Number of seconds to wait on a CLI timeout
+timeout = 15
[service_available]
# Whether or not cinder is expected to be available
diff --git a/run_tests.sh b/run_tests.sh
index a645b22..f8636c1 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -11,23 +11,22 @@
echo " -u, --update Update the virtual environment with any newer package versions"
echo " -s, --smoke Only run smoke tests"
echo " -w, --whitebox Only run whitebox tests"
- echo " -t, --with-testr Run using testr instead of nose"
+ echo " -t, --parallel Run testr parallel"
echo " -c, --nova-coverage Enable Nova coverage collection"
echo " -C, --config Config file location"
echo " -p, --pep8 Just run pep8"
echo " -h, --help Print this usage message"
echo " -d, --debug Debug this script -- set -o xtrace"
- echo " -S, --stdout Don't capture stdout"
echo " -l, --logging Enable logging"
echo " -L, --logging-config Logging config file location. Default is etc/logging.conf"
- echo " -- [NOSEOPTIONS] After the first '--' you can pass arbitrary arguments to nosetests "
+ echo " -- [TESTROPTIONS] After the first '--' you can pass arbitrary arguments to testr "
}
-noseargs=""
+testrargs=""
just_pep8=0
venv=.venv
with_venv=tools/with_venv.sh
-with_testr=0
+parallel=0
always_venv=0
never_venv=0
no_site_packages=0
@@ -39,7 +38,7 @@
logging=0
logging_config=etc/logging.conf
-if ! options=$(getopt -o VNnfuswtcphdSC:lL: -l virtual-env,no-virtual-env,no-site-packages,force,update,smoke,whitebox,with-testr,nova-coverage,pep8,help,debug,stdout,config:,logging,logging-config: -- "$@")
+if ! options=$(getopt -o VNnfuswtcphdC:lL: -l virtual-env,no-virtual-env,no-site-packages,force,update,smoke,whitebox,parallel,nova-coverage,pep8,help,debug,config:,logging,logging-config: -- "$@")
then
# parse error
usage
@@ -60,14 +59,13 @@
-c|--nova-coverage) let nova_coverage=1;;
-C|--config) config_file=$2; shift;;
-p|--pep8) let just_pep8=1;;
- -s|--smoke) noseargs="$noseargs --attr=type=smoke";;
- -w|--whitebox) noseargs="$noseargs --attr=type=whitebox";;
- -t|--with-testr) with_testr=1;;
- -S|--stdout) noseargs="$noseargs -s";;
+ -s|--smoke) testrargs="$testrargs smoke";;
+ -w|--whitebox) testrargs="$testrargs whitebox";;
+ -t|--parallel) parallel=1;;
-l|--logging) logging=1;;
-L|--logging-config) logging_config=$2; shift;;
- --) [ "yes" == "$first_uu" ] || noseargs="$noseargs $1"; first_uu=no ;;
- *) noseargs="$noseargs $1"
+ --) [ "yes" == "$first_uu" ] || testrargs="$testrargs $1"; first_uu=no ;;
+ *) testrargs="$testrargs $1"
esac
shift
done
@@ -90,24 +88,10 @@
cd `dirname "$0"`
-export NOSE_WITH_OPENSTACK=1
-export NOSE_OPENSTACK_COLOR=1
-export NOSE_OPENSTACK_RED=15.00
-export NOSE_OPENSTACK_YELLOW=3.00
-export NOSE_OPENSTACK_SHOW_ELAPSED=1
-export NOSE_OPENSTACK_STDOUT=1
-
if [ $no_site_packages -eq 1 ]; then
installvenvopts="--no-site-packages"
fi
-# only add tempest default if we don't specify a test
-if [[ "x$noseargs" =~ "tempest" ]]; then
- noseargs="$noseargs"
-else
- noseargs="$noseargs tempest"
-fi
-
function testr_init {
if [ ! -d .testrepository ]; then
${wrapper} testr init
@@ -115,12 +99,12 @@
}
function run_tests {
- if [ $with_testr -eq 1 ]; then
- testr_init
- ${wrapper} find . -type f -name "*.pyc" -delete
- ${wrapper} testr run --parallel --subunit $noseargs | ${wrapper} subunit-2to1 | ${wrapper} tools/colorizer.py
+ testr_init
+ ${wrapper} find . -type f -name "*.pyc" -delete
+ if [ $parallel -eq 1 ]; then
+ ${wrapper} testr run --parallel --subunit $testrargs | ${wrapper} subunit-2to1 | ${wrapper} tools/colorizer.py
else
- ${wrapper} $NOSETESTS
+ ${wrapper} testr run --subunit $testrargs | ${wrapper} subunit-2to1 | ${wrapper} tools/colorizer.py
fi
}
@@ -139,8 +123,6 @@
${wrapper} python tools/tempest_coverage.py -c report
}
-NOSETESTS="nosetests $noseargs"
-
if [ $never_venv -eq 0 ]
then
# Remove the virtual environment if --force used
@@ -187,7 +169,7 @@
run_coverage_report
fi
-if [ -z "$noseargs" ]; then
+if [ -z "$testrargs" ]; then
run_pep8
fi
diff --git a/setup.cfg b/setup.cfg
index 3b13b60..7cfc4ce 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -35,3 +35,6 @@
# coverage http://pypi.python.org/pypi/coverage
# openstack-nose https://github.com/openstack-dev/openstack-nose
verbosity=2
+
+[pbr]
+autodoc_tree_index_modules=true
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 107d635..303bc0c 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -146,6 +146,7 @@
self.client.get_aggregate, -1)
@attr(type='gate')
+ @lockutils.synchronized('availability_zone', 'tempest-', True)
def test_aggregate_add_remove_host(self):
# Add an host to the given aggregate and remove.
aggregate_name = rand_name(self.aggregate_name_prefix)
@@ -167,6 +168,7 @@
self.assertNotIn(self.host, body['hosts'])
@attr(type='gate')
+ @lockutils.synchronized('availability_zone', 'tempest-', True)
def test_aggregate_add_host_list(self):
# Add an host to the given aggregate and list.
aggregate_name = rand_name(self.aggregate_name_prefix)
@@ -184,6 +186,7 @@
self.assertIn(self.host, agg['hosts'])
@attr(type='gate')
+ @lockutils.synchronized('availability_zone', 'tempest-', True)
def test_aggregate_add_host_get_details(self):
# Add an host to the given aggregate and get details.
aggregate_name = rand_name(self.aggregate_name_prefix)
@@ -245,6 +248,7 @@
aggregate['id'], self.host)
@attr(type=['negative', 'gate'])
+ @lockutils.synchronized('availability_zone', 'tempest-', True)
def test_aggregate_remove_host_as_user(self):
# Regular user is not allowed to remove a host from an aggregate.
aggregate_name = rand_name(self.aggregate_name_prefix)
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 6db20f9..6d0a5b5 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -60,7 +60,7 @@
flavor_name = rand_name(self.flavor_name_prefix)
new_flavor_id = rand_int_id(start=1000)
- #Create the flavor
+ # Create the flavor
resp, flavor = self.client.create_flavor(flavor_name,
self.ram, self.vcpus,
self.disk,
@@ -87,7 +87,7 @@
if self._interface == "json":
self.assertEqual(flavor['os-flavor-access:is_public'], True)
- #Verify flavor is retrieved
+ # Verify flavor is retrieved
resp, flavor = self.client.get_flavor_details(new_flavor_id)
self.assertEqual(resp.status, 200)
self.assertEqual(flavor['name'], flavor_name)
@@ -99,7 +99,7 @@
flavor_name = rand_name(self.flavor_name_prefix)
new_flavor_id = rand_int_id(start=1000)
- #Create the flavor
+ # Create the flavor
resp, flavor = self.client.create_flavor(flavor_name,
self.ram, self.vcpus,
self.disk,
@@ -109,7 +109,7 @@
rxtx=self.rxtx)
self.addCleanup(self.flavor_clean_up, flavor['id'])
flag = False
- #Verify flavor is retrieved
+ # Verify flavor is retrieved
resp, flavors = self.client.list_flavors_with_detail()
self.assertEqual(resp.status, 200)
for flavor in flavors:
@@ -153,12 +153,12 @@
@attr(type='gate')
def test_create_list_flavor_without_extra_data(self):
- #Create a flavor and ensure it is listed
- #This operation requires the user to have 'admin' role
+ # Create a flavor and ensure it is listed
+ # This operation requires the user to have 'admin' role
flavor_name = rand_name(self.flavor_name_prefix)
new_flavor_id = rand_int_id(start=1000)
- #Create the flavor
+ # Create the flavor
resp, flavor = self.client.create_flavor(flavor_name,
self.ram, self.vcpus,
self.disk,
@@ -181,11 +181,11 @@
if self._interface == "json":
self.assertEqual(flavor['os-flavor-access:is_public'], True)
- #Verify flavor is retrieved
+ # Verify flavor is retrieved
resp, flavor = self.client.get_flavor_details(new_flavor_id)
self.assertEqual(resp.status, 200)
self.assertEqual(flavor['name'], flavor_name)
- #Check if flavor is present in list
+ # Check if flavor is present in list
resp, flavors = self.client.list_flavors_with_detail()
self.assertEqual(resp.status, 200)
for flavor in flavors:
@@ -195,13 +195,13 @@
@attr(type='gate')
def test_flavor_not_public_verify_entry_not_in_list_details(self):
- #Create a flavor with os-flavor-access:is_public false should not
- #be present in list_details.
- #This operation requires the user to have 'admin' role
+ # Create a flavor with os-flavor-access:is_public false should not
+ # be present in list_details.
+ # This operation requires the user to have 'admin' role
flavor_name = rand_name(self.flavor_name_prefix)
new_flavor_id = rand_int_id(start=1000)
- #Create the flavor
+ # Create the flavor
resp, flavor = self.client.create_flavor(flavor_name,
self.ram, self.vcpus,
self.disk,
@@ -209,7 +209,7 @@
is_public="False")
self.addCleanup(self.flavor_clean_up, flavor['id'])
flag = False
- #Verify flavor is retrieved
+ # Verify flavor is retrieved
resp, flavors = self.client.list_flavors_with_detail()
self.assertEqual(resp.status, 200)
for flavor in flavors:
@@ -219,12 +219,12 @@
@attr(type='gate')
def test_list_public_flavor_with_other_user(self):
- #Create a Flavor with public access.
- #Try to List/Get flavor with another user
+ # Create a Flavor with public access.
+ # Try to List/Get flavor with another user
flavor_name = rand_name(self.flavor_name_prefix)
new_flavor_id = rand_int_id(start=1000)
- #Create the flavor
+ # Create the flavor
resp, flavor = self.client.create_flavor(flavor_name,
self.ram, self.vcpus,
self.disk,
@@ -233,7 +233,7 @@
self.addCleanup(self.flavor_clean_up, flavor['id'])
flag = False
self.new_client = self.flavors_client
- #Verify flavor is retrieved with new user
+ # Verify flavor is retrieved with new user
resp, flavors = self.new_client.list_flavors_with_detail()
self.assertEqual(resp.status, 200)
for flavor in flavors:
diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index 63d5025..107b23d 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -52,7 +52,7 @@
@attr(type='gate')
def test_flavor_access_add_remove(self):
- #Test to add and remove flavor access to a given tenant.
+ # Test to add and remove flavor access to a given tenant.
flavor_name = rand_name(self.flavor_name_prefix)
new_flavor_id = rand_int_id(start=1000)
resp, new_flavor = self.client.create_flavor(flavor_name,
@@ -61,7 +61,7 @@
new_flavor_id,
is_public='False')
self.addCleanup(self.client.delete_flavor, new_flavor['id'])
- #Add flavor access to a tenant.
+ # Add flavor access to a tenant.
resp_body = {
"tenant_id": str(self.tenant_id),
"flavor_id": str(new_flavor['id']),
@@ -71,25 +71,25 @@
self.assertEqual(add_resp.status, 200)
self.assertIn(resp_body, add_body)
- #The flavor is present in list.
+ # The flavor is present in list.
resp, flavors = self.flavors_client.list_flavors_with_detail()
self.assertEqual(resp.status, 200)
self.assertIn(new_flavor['id'], map(lambda x: x['id'], flavors))
- #Remove flavor access from a tenant.
+ # Remove flavor access from a tenant.
remove_resp, remove_body = \
self.client.remove_flavor_access(new_flavor['id'], self.tenant_id)
self.assertEqual(remove_resp.status, 200)
self.assertNotIn(resp_body, remove_body)
- #The flavor is not present in list.
+ # The flavor is not present in list.
resp, flavors = self.flavors_client.list_flavors_with_detail()
self.assertEqual(resp.status, 200)
self.assertNotIn(new_flavor['id'], map(lambda x: x['id'], flavors))
@attr(type=['negative', 'gate'])
def test_flavor_non_admin_add(self):
- #Test to add flavor access as a user without admin privileges.
+ # Test to add flavor access as a user without admin privileges.
flavor_name = rand_name(self.flavor_name_prefix)
new_flavor_id = rand_int_id(start=1000)
resp, new_flavor = self.client.create_flavor(flavor_name,
@@ -105,7 +105,7 @@
@attr(type=['negative', 'gate'])
def test_flavor_non_admin_remove(self):
- #Test to remove flavor access as a user without admin privileges.
+ # Test to remove flavor access as a user without admin privileges.
flavor_name = rand_name(self.flavor_name_prefix)
new_flavor_id = rand_int_id(start=1000)
resp, new_flavor = self.client.create_flavor(flavor_name,
@@ -114,7 +114,7 @@
new_flavor_id,
is_public='False')
self.addCleanup(self.client.delete_flavor, new_flavor['id'])
- #Add flavor access to a tenant.
+ # Add flavor access to a tenant.
self.client.add_flavor_access(new_flavor['id'], self.tenant_id)
self.addCleanup(self.client.remove_flavor_access,
new_flavor['id'], self.tenant_id)
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index db376b5..7b79a12 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -47,7 +47,7 @@
cls.new_flavor_id = 12345
swap = 1024
rxtx = 1
- #Create a flavor so as to set/get/unset extra specs
+ # Create a flavor so as to set/get/unset extra specs
resp, cls.flavor = cls.client.create_flavor(flavor_name,
ram, vcpus,
disk,
@@ -62,28 +62,28 @@
@attr(type='gate')
def test_flavor_set_get_unset_keys(self):
- #Test to SET, GET UNSET flavor extra spec as a user
- #with admin privileges.
- #Assigning extra specs values that are to be set
+ # Test to SET, GET UNSET flavor extra spec as a user
+ # with admin privileges.
+ # Assigning extra specs values that are to be set
specs = {"key1": "value1", "key2": "value2"}
- #SET extra specs to the flavor created in setUp
+ # SET extra specs to the flavor created in setUp
set_resp, set_body = \
self.client.set_flavor_extra_spec(self.flavor['id'], specs)
self.assertEqual(set_resp.status, 200)
self.assertEqual(set_body, specs)
- #GET extra specs and verify
+ # GET extra specs and verify
get_resp, get_body = \
self.client.get_flavor_extra_spec(self.flavor['id'])
self.assertEqual(get_resp.status, 200)
self.assertEqual(get_body, specs)
- #UNSET extra specs that were set in this test
+ # UNSET extra specs that were set in this test
unset_resp, _ = \
self.client.unset_flavor_extra_spec(self.flavor['id'], "key1")
self.assertEqual(unset_resp.status, 200)
@attr(type=['negative', 'gate'])
def test_flavor_non_admin_set_keys(self):
- #Test to SET flavor extra spec as a user without admin privileges.
+ # Test to SET flavor extra spec as a user without admin privileges.
specs = {"key1": "value1", "key2": "value2"}
self.assertRaises(exceptions.Unauthorized,
self.flavors_client.set_flavor_extra_spec,
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 3e98029..4e42dd0 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -36,10 +36,11 @@
resp, tenants = cls.identity_admin_client.list_tenants()
- #NOTE(afazekas): these test cases should always create and use a new
+ # NOTE(afazekas): these test cases should always create and use a new
# tenant most of them should be skipped if we can't do that
if cls.config.compute.allow_tenant_isolation:
- cls.demo_tenant_id = cls.isolated_creds[0][0]['tenantId']
+ cls.demo_tenant_id = cls.isolated_creds.get_primary_user().get(
+ 'tenantId')
else:
cls.demo_tenant_id = [tnt['id'] for tnt in tenants if tnt['name']
== cls.config.identity.tenant_name][0]
@@ -102,7 +103,7 @@
self.assertEqual(200, resp.status, "Failed to reset quota "
"defaults")
- #TODO(afazekas): merge these test cases
+ # TODO(afazekas): merge these test cases
@attr(type='gate')
def test_get_updated_quotas(self):
# Verify that GET shows the updated quota set
@@ -121,7 +122,7 @@
self.assertEqual(200, resp.status)
self.assertEqual(quota_set['ram'], 5120)
- #TODO(afazekas): Add dedicated tenant to the skiped quota tests
+ # TODO(afazekas): Add dedicated tenant to the skiped quota tests
# it can be moved into the setUpClass as well
@testtools.skip("Skipped until the Bug #1160749 is resolved")
@attr(type='gate')
@@ -155,12 +156,12 @@
ram=default_mem_quota)
self.assertRaises(exceptions.OverLimit, self.create_server)
-#TODO(afazekas): Add test that tried to update the quota_set as a regular user
+# TODO(afazekas): Add test that tried to update the quota_set as a regular user
@testtools.skip("Skipped until the Bug #1160749 is resolved")
@attr(type=['negative', 'gate'])
def test_create_server_when_instances_quota_is_full(self):
- #Once instances quota limit is reached, disallow server creation
+ # Once instances quota limit is reached, disallow server creation
resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
default_instances_quota = quota_set['instances']
instances_quota = 0 # Set quota to zero to disallow server creation
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index dc960db..434ea2f 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -70,13 +70,13 @@
s1 = map(lambda x: x['binary'], services)
s2 = map(lambda x: x['binary'], services_on_host)
- #sort the lists before comparing, to take out dependency
- #on order.
+ # sort the lists before comparing, to take out dependency
+ # on order.
self.assertEqual(sorted(s1), sorted(s2))
@attr(type=['negative', 'gate'])
def test_get_service_by_invalid_params(self):
- #return all services if send the request with invalid parameter
+ # return all services if send the request with invalid parameter
resp, services = self.client.list_services()
params = {'xxx': 'nova-compute'}
resp, services_xxx = self.client.list_services(params)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index d40b0e0..15e28fd 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -19,6 +19,7 @@
from tempest.api import compute
from tempest import clients
+from tempest.common import isolated_creds
from tempest.common.utils.data_utils import parse_image_id
from tempest.common.utils.data_utils import rand_name
from tempest.openstack.common import log as logging
@@ -38,10 +39,10 @@
if not cls.config.service_available.nova:
skip_msg = ("%s skipped as nova is not available" % cls.__name__)
raise cls.skipException(skip_msg)
- cls.isolated_creds = []
+ cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
if cls.config.compute.allow_tenant_isolation:
- creds = cls._get_isolated_creds()
+ creds = cls.isolated_creds.get_primary_creds()
username, tenant_name, password = creds
os = clients.Manager(username=username,
password=password,
@@ -108,7 +109,8 @@
def tearDownClass(cls):
cls.clear_images()
cls.clear_servers()
- cls._clear_isolated_creds()
+ cls.isolated_creds.clear_isolated_creds()
+ super(BaseComputeTest, cls).tearDownClass()
@classmethod
def create_server(cls, **kwargs):
@@ -187,7 +189,7 @@
"in configuration.")
raise cls.skipException(msg)
if cls.config.compute.allow_tenant_isolation:
- creds = cls._get_isolated_creds(admin=True)
+ creds = cls.isolated_creds.get_admin_creds()
admin_username, admin_tenant_name, admin_password = creds
cls.os_adm = clients.Manager(username=admin_username,
password=admin_password,
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index a8ac7de..930ebcb 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -32,15 +32,15 @@
cls.client = cls.floating_ips_client
cls.servers_client = cls.servers_client
- #Server creation
+ # Server creation
resp, server = cls.create_server(wait_until='ACTIVE')
cls.server_id = server['id']
resp, body = cls.servers_client.get_server(server['id'])
- #Floating IP creation
+ # Floating IP creation
resp, body = cls.client.create_floating_ip()
cls.floating_ip_id = body['id']
cls.floating_ip = body['ip']
- #Generating a nonexistent floatingIP id
+ # Generating a nonexistent floatingIP id
cls.floating_ip_ids = []
resp, body = cls.client.list_floating_ips()
for i in range(len(body)):
@@ -52,7 +52,7 @@
@classmethod
def tearDownClass(cls):
- #Deleting the floating IP which is created in this method
+ # Deleting the floating IP which is created in this method
resp, body = cls.client.delete_floating_ip(cls.floating_ip_id)
super(FloatingIPsTestJSON, cls).tearDownClass()
@@ -66,17 +66,17 @@
floating_ip_id_allocated = body['id']
resp, floating_ip_details = \
self.client.get_floating_ip_details(floating_ip_id_allocated)
- #Checking if the details of allocated IP is in list of floating IP
+ # Checking if the details of allocated IP is in list of floating IP
resp, body = self.client.list_floating_ips()
self.assertIn(floating_ip_details, body)
finally:
- #Deleting the floating IP which is created in this method
+ # Deleting the floating IP which is created in this method
self.client.delete_floating_ip(floating_ip_id_allocated)
@attr(type=['negative', 'gate'])
def test_allocate_floating_ip_from_nonexistent_pool(self):
# Positive test:Allocation of a new floating IP from a nonexistent_pool
- #to a project should fail
+ # to a project should fail
self.assertRaises(exceptions.NotFound,
self.client.create_floating_ip,
"non_exist_pool")
@@ -85,12 +85,12 @@
def test_delete_floating_ip(self):
# Positive test:Deletion of valid floating IP from project
# should be successful
- #Creating the floating IP that is to be deleted in this method
+ # Creating the floating IP that is to be deleted in this method
resp, floating_ip_body = self.client.create_floating_ip()
- #Storing the details of floating IP before deleting it
+ # Storing the details of floating IP before deleting it
cli_resp = self.client.get_floating_ip_details(floating_ip_body['id'])
resp, floating_ip_details = cli_resp
- #Deleting the floating IP from the project
+ # Deleting the floating IP from the project
resp, body = self.client.delete_floating_ip(floating_ip_body['id'])
self.assertEqual(202, resp.status)
# Check it was really deleted.
@@ -101,12 +101,12 @@
# Positive test:Associate and disassociate the provided floating IP
# to a specific server should be successful
- #Association of floating IP to fixed IP address
+ # Association of floating IP to fixed IP address
resp, body = self.client.associate_floating_ip_to_server(
self.floating_ip,
self.server_id)
self.assertEqual(202, resp.status)
- #Disassociation of floating IP that was associated in this method
+ # Disassociation of floating IP that was associated in this method
resp, body = self.client.disassociate_floating_ip_from_server(
self.floating_ip,
self.server_id)
@@ -142,18 +142,18 @@
def test_associate_already_associated_floating_ip(self):
# positive test:Association of an already associated floating IP
# to specific server should change the association of the Floating IP
- #Create server so as to use for Multiple association
+ # Create server so as to use for Multiple association
resp, body = self.servers_client.create_server('floating-server2',
self.image_ref,
self.flavor_ref)
self.servers_client.wait_for_server_status(body['id'], 'ACTIVE')
self.new_server_id = body['id']
- #Associating floating IP for the first time
+ # Associating floating IP for the first time
resp, _ = self.client.associate_floating_ip_to_server(
self.floating_ip,
self.server_id)
- #Associating floating IP for the second time
+ # Associating floating IP for the second time
resp, body = self.client.associate_floating_ip_to_server(
self.floating_ip,
self.new_server_id)
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index 7e4e833..e380334 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -56,7 +56,7 @@
@attr(type='gate')
def test_get_floating_ip_details(self):
# Positive test:Should be able to GET the details of floatingIP
- #Creating a floating IP for which details are to be checked
+ # Creating a floating IP for which details are to be checked
try:
resp, body = self.client.create_floating_ip()
floating_ip_instance_id = body['instance_id']
@@ -66,14 +66,14 @@
resp, body = \
self.client.get_floating_ip_details(floating_ip_id)
self.assertEqual(200, resp.status)
- #Comparing the details of floating IP
+ # Comparing the details of floating IP
self.assertEqual(floating_ip_instance_id,
body['instance_id'])
self.assertEqual(floating_ip_ip, body['ip'])
self.assertEqual(floating_ip_fixed_ip,
body['fixed_ip'])
self.assertEqual(floating_ip_id, body['id'])
- #Deleting the floating IP created in this method
+ # Deleting the floating IP created in this method
finally:
self.client.delete_floating_ip(floating_ip_id)
@@ -85,7 +85,7 @@
resp, body = self.client.list_floating_ips()
for i in range(len(body)):
floating_ip_id.append(body[i]['id'])
- #Creating a nonexistant floatingIP id
+ # Creating a nonexistant floatingIP id
while True:
non_exist_id = rand_name('999')
if non_exist_id not in floating_ip_id:
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index 4f9364b..2f0ed6b 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -39,7 +39,7 @@
if compute.MULTI_USER:
if cls.config.compute.allow_tenant_isolation:
- creds = cls._get_isolated_creds()
+ creds = cls.isolated_creds.get_alt_creds()
username, tenant_name, password = creds
cls.alt_manager = clients.Manager(username=username,
password=password,
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 64f1854..0052a30 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -54,7 +54,7 @@
if compute.MULTI_USER:
if cls.config.compute.allow_tenant_isolation:
- creds = cls._get_isolated_creds()
+ creds = cls.isolated_creds.get_alt_creds()
username, tenant_name, password = creds
cls.alt_manager = clients.Manager(username=username,
password=password,
@@ -89,23 +89,6 @@
self.assertRaises(exceptions.BadRequest, self.client.create_image,
self.server['id'], snapshot_name, meta)
- @testtools.skipUnless(compute.MULTI_USER,
- 'Need multiple users for this test.')
- @attr(type=['negative', 'gate'])
- def test_delete_image_of_another_tenant(self):
- # Return an error while trying to delete another tenant's image
- self.servers_client.wait_for_server_status(self.server['id'], 'ACTIVE')
- snapshot_name = rand_name('test-snap-')
- resp, body = self.client.create_image(self.server['id'], snapshot_name)
- image_id = parse_image_id(resp['location'])
- self.image_ids.append(image_id)
- self.client.wait_for_image_resp_code(image_id, 200)
- self.client.wait_for_image_status(image_id, 'ACTIVE')
-
- # Delete image
- self.assertRaises(exceptions.NotFound,
- self.alt_client.delete_image, image_id)
-
def _get_default_flavor_disk_size(self, flavor_id):
resp, flavor = self.flavors_client.get_flavor_details(flavor_id)
return flavor['disk']
@@ -144,16 +127,6 @@
self.assertEqual('204', resp['status'])
self.client.wait_for_resource_deletion(image_id)
- @testtools.skipUnless(compute.MULTI_USER,
- 'Need multiple users for this test.')
- @attr(type=['negative', 'gate'])
- def test_create_image_for_server_in_another_tenant(self):
- # Creating image of another tenant's server should be return error
-
- snapshot_name = rand_name('test-snap-')
- self.assertRaises(exceptions.NotFound, self.alt_client.create_image,
- self.server['id'], snapshot_name)
-
@attr(type=['negative', 'gate'])
def test_create_second_image_when_first_image_is_being_saved(self):
# Disallow creating another image when first image is being saved
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index fb2906a..a80f456 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -144,16 +144,16 @@
# Verify only the expected number of results are returned
params = {'limit': '1'}
resp, images = self.client.list_images(params)
- #when _interface='xml', one element for images_links in images
- #ref: Question #224349
+ # when _interface='xml', one element for images_links in images
+ # ref: Question #224349
self.assertEqual(1, len([x for x in images if 'id' in x]))
@attr(type='gate')
def test_list_images_filter_by_changes_since(self):
# Verify only updated images are returned in the detailed list
- #Becoming ACTIVE will modify the updated time
- #Filter by the image's created time
+ # Becoming ACTIVE will modify the updated time
+ # Filter by the image's created time
params = {'changes-since': self.image3['created']}
resp, images = self.client.list_images(params)
found = any([i for i in images if i['id'] == self.image3_id])
@@ -222,8 +222,8 @@
def test_list_images_with_detail_filter_by_changes_since(self):
# Verify an update image is returned
- #Becoming ACTIVE will modify the updated time
- #Filter by the image's created time
+ # Becoming ACTIVE will modify the updated time
+ # Filter by the image's created time
params = {'changes-since': self.image1['created']}
resp, images = self.client.list_images_with_detail(params)
self.assertTrue(any([i for i in images if i['id'] == self.image1_id]))
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index 3bcf7b4..e4e87c0 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -32,33 +32,33 @@
@attr(type='gate')
def test_keypairs_create_list_delete(self):
# Keypairs created should be available in the response list
- #Create 3 keypairs
+ # Create 3 keypairs
key_list = list()
for i in range(3):
k_name = rand_name('keypair-')
resp, keypair = self.client.create_keypair(k_name)
- #Need to pop these keys so that our compare doesn't fail later,
- #as the keypair dicts from list API doesn't have them.
+ # Need to pop these keys so that our compare doesn't fail later,
+ # as the keypair dicts from list API doesn't have them.
keypair.pop('private_key')
keypair.pop('user_id')
self.assertEqual(200, resp.status)
key_list.append(keypair)
- #Fetch all keypairs and verify the list
- #has all created keypairs
+ # Fetch all keypairs and verify the list
+ # has all created keypairs
resp, fetched_list = self.client.list_keypairs()
self.assertEqual(200, resp.status)
- #We need to remove the extra 'keypair' element in the
- #returned dict. See comment in keypairs_client.list_keypairs()
+ # We need to remove the extra 'keypair' element in the
+ # returned dict. See comment in keypairs_client.list_keypairs()
new_list = list()
for keypair in fetched_list:
new_list.append(keypair['keypair'])
fetched_list = new_list
- #Now check if all the created keypairs are in the fetched list
+ # Now check if all the created keypairs are in the fetched list
missing_kps = [kp for kp in key_list if kp not in fetched_list]
self.assertFalse(missing_kps,
"Failed to find keypairs %s in fetched list"
% ', '.join(m_key['name'] for m_key in missing_kps))
- #Delete all the keypairs created
+ # Delete all the keypairs created
for keypair in key_list:
resp, _ = self.client.delete_keypair(keypair['name'])
self.assertEqual(202, resp.status)
@@ -163,7 +163,7 @@
k_name = rand_name('keypair-')
resp, _ = self.client.create_keypair(k_name)
self.assertEqual(200, resp.status)
- #Now try the same keyname to ceate another key
+ # Now try the same keyname to ceate another key
self.assertRaises(exceptions.Duplicate, self.client.create_keypair,
k_name)
resp, _ = self.client.delete_keypair(k_name)
diff --git a/tempest/api/compute/limits/test_absolute_limits.py b/tempest/api/compute/limits/test_absolute_limits.py
index beae122..972e4a8 100644
--- a/tempest/api/compute/limits/test_absolute_limits.py
+++ b/tempest/api/compute/limits/test_absolute_limits.py
@@ -51,11 +51,11 @@
@attr(type=['negative', 'gate'])
def test_max_image_meta_exceed_limit(self):
- #We should not create vm with image meta over maxImageMeta limit
+ # We should not create vm with image meta over maxImageMeta limit
# Get max limit value
max_meta = self.client.get_specific_absolute_limit('maxImageMeta')
- #Create server should fail, since we are passing > metadata Limit!
+ # Create server should fail, since we are passing > metadata Limit!
max_meta_data = int(max_meta) + 1
meta_data = {}
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 6a32b64..472b8b4 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -15,8 +15,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.api.compute import base
from tempest.common.utils.data_utils import rand_name
+from tempest import config
from tempest import exceptions
from tempest.test import attr
@@ -33,14 +36,14 @@
def test_security_group_rules_create(self):
# Positive test: Creation of Security Group rule
# should be successfull
- #Creating a Security Group to add rules to it
+ # Creating a Security Group to add rules to it
s_name = rand_name('securitygroup-')
s_description = rand_name('description-')
resp, securitygroup = \
self.client.create_security_group(s_name, s_description)
securitygroup_id = securitygroup['id']
self.addCleanup(self.client.delete_security_group, securitygroup_id)
- #Adding rules to the created Security Group
+ # Adding rules to the created Security Group
ip_protocol = 'tcp'
from_port = 22
to_port = 22
@@ -60,21 +63,21 @@
secgroup1 = None
secgroup2 = None
- #Creating a Security Group to add rules to it
+ # Creating a Security Group to add rules to it
s_name = rand_name('securitygroup-')
s_description = rand_name('description-')
resp, securitygroup = \
self.client.create_security_group(s_name, s_description)
secgroup1 = securitygroup['id']
self.addCleanup(self.client.delete_security_group, secgroup1)
- #Creating a Security Group so as to assign group_id to the rule
+ # Creating a Security Group so as to assign group_id to the rule
s_name2 = rand_name('securitygroup-')
s_description2 = rand_name('description-')
resp, securitygroup = \
self.client.create_security_group(s_name2, s_description2)
secgroup2 = securitygroup['id']
self.addCleanup(self.client.delete_security_group, secgroup2)
- #Adding rules to the created Security Group with optional arguments
+ # Adding rules to the created Security Group with optional arguments
parent_group_id = secgroup1
ip_protocol = 'tcp'
from_port = 22
@@ -91,6 +94,8 @@
self.addCleanup(self.client.delete_security_group_rule, rule['id'])
self.assertEqual(200, resp.status)
+ @testtools.skipIf(config.TempestConfig().service_available.neutron,
+ "Skipped until the Bug #1182384 is resolved")
@attr(type=['negative', 'gate'])
def test_security_group_rules_create_with_invalid_id(self):
# Negative test: Creation of Security Group rule should FAIL
@@ -108,12 +113,12 @@
def test_security_group_rules_create_with_invalid_ip_protocol(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid ip_protocol
- #Creating a Security Group to add rule to it
+ # Creating a Security Group to add rule to it
s_name = rand_name('securitygroup-')
s_description = rand_name('description-')
resp, securitygroup = self.client.create_security_group(s_name,
s_description)
- #Adding rules to the created Security Group
+ # Adding rules to the created Security Group
parent_group_id = securitygroup['id']
ip_protocol = rand_name('999')
from_port = 22
@@ -128,12 +133,12 @@
def test_security_group_rules_create_with_invalid_from_port(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid from_port
- #Creating a Security Group to add rule to it
+ # Creating a Security Group to add rule to it
s_name = rand_name('securitygroup-')
s_description = rand_name('description-')
resp, securitygroup = self.client.create_security_group(s_name,
s_description)
- #Adding rules to the created Security Group
+ # Adding rules to the created Security Group
parent_group_id = securitygroup['id']
ip_protocol = 'tcp'
from_port = rand_name('999')
@@ -147,12 +152,12 @@
def test_security_group_rules_create_with_invalid_to_port(self):
# Negative test: Creation of Security Group rule should FAIL
# with invalid from_port
- #Creating a Security Group to add rule to it
+ # Creating a Security Group to add rule to it
s_name = rand_name('securitygroup-')
s_description = rand_name('description-')
resp, securitygroup = self.client.create_security_group(s_name,
s_description)
- #Adding rules to the created Security Group
+ # Adding rules to the created Security Group
parent_group_id = securitygroup['id']
ip_protocol = 'tcp'
from_port = 22
@@ -181,6 +186,8 @@
self.client.create_security_group_rule,
secgroup_id, ip_protocol, from_port, to_port)
+ @testtools.skipIf(config.TempestConfig().service_available.neutron,
+ "Skipped until the Bug #1182384 is resolved")
@attr(type=['negative', 'gate'])
def test_security_group_rules_delete_with_invalid_id(self):
# Negative test: Deletion of Security Group rule should be FAIL
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index 68be206..30db206 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -39,7 +39,7 @@
@attr(type='gate')
def test_security_groups_create_list_delete(self):
# Positive test:Should return the list of Security Groups
- #Create 3 Security Groups
+ # Create 3 Security Groups
security_group_list = list()
for i in range(3):
s_name = rand_name('securitygroup-')
@@ -50,11 +50,11 @@
self.addCleanup(self._delete_security_group,
securitygroup['id'])
security_group_list.append(securitygroup)
- #Fetch all Security Groups and verify the list
- #has all created Security Groups
+ # Fetch all Security Groups and verify the list
+ # has all created Security Groups
resp, fetched_list = self.client.list_security_groups()
self.assertEqual(200, resp.status)
- #Now check if all the created Security Groups are in fetched list
+ # Now check if all the created Security Groups are in fetched list
missing_sgs = \
[sg for sg in security_group_list if sg not in fetched_list]
self.assertFalse(missing_sgs,
@@ -62,8 +62,8 @@
"list" % ', '.join(m_group['name']
for m_group in missing_sgs))
- #TODO(afazekas): scheduled for delete,
- #test_security_group_create_get_delete covers it
+ # TODO(afazekas): scheduled for delete,
+ # test_security_group_create_get_delete covers it
@attr(type='gate')
def test_security_group_create_delete(self):
# Security Group should be created, verified and deleted
@@ -99,7 +99,7 @@
self.assertEqual(securitygroup_name, s_name,
"The created Security Group name is "
"not equal to the requested name")
- #Now fetch the created Security Group by its 'id'
+ # Now fetch the created Security Group by its 'id'
resp, fetched_group = \
self.client.get_security_group(securitygroup['id'])
self.assertEqual(200, resp.status)
@@ -107,6 +107,8 @@
"The fetched Security Group is different "
"from the created Group")
+ @testtools.skipIf(config.TempestConfig().service_available.neutron,
+ "Skipped until the Bug #1182384 is resolved")
@attr(type=['negative', 'gate'])
def test_security_group_get_nonexistant_group(self):
# Negative test:Should not be able to GET the details
@@ -115,7 +117,7 @@
resp, body = self.client.list_security_groups()
for i in range(len(body)):
security_group_id.append(body[i]['id'])
- #Creating a nonexistant Security Group id
+ # Creating a nonexistant Security Group id
while True:
non_exist_id = rand_name('999')
if non_exist_id not in security_group_id:
@@ -123,6 +125,8 @@
self.assertRaises(exceptions.NotFound, self.client.get_security_group,
non_exist_id)
+ @testtools.skipIf(config.TempestConfig().service_available.neutron,
+ "Skipped until the Bug #1161411 is resolved")
@attr(type=['negative', 'gate'])
def test_security_group_create_with_invalid_group_name(self):
# Negative test: Security Group should not be created with group name
@@ -141,6 +145,8 @@
self.client.create_security_group, s_name,
s_description)
+ @testtools.skipIf(config.TempestConfig().service_available.neutron,
+ "Skipped until the Bug #1161411 is resolved")
@attr(type=['negative', 'gate'])
def test_security_group_create_with_invalid_group_description(self):
# Negative test:Security Group should not be created with description
@@ -186,11 +192,13 @@
if body[i]['name'] == 'default':
default_security_group_id = body[i]['id']
break
- #Deleting the "default" Security Group
+ # Deleting the "default" Security Group
self.assertRaises(exceptions.BadRequest,
self.client.delete_security_group,
default_security_group_id)
+ @testtools.skipIf(config.TempestConfig().service_available.neutron,
+ "Skipped until the Bug #1182384 is resolved")
@attr(type=['negative', 'gate'])
def test_delete_nonexistant_security_group(self):
# Negative test:Deletion of a nonexistant Security Group should Fail
@@ -198,7 +206,7 @@
resp, body = self.client.list_security_groups()
for i in range(len(body)):
security_group_id.append(body[i]['id'])
- #Creating Non Existant Security Group
+ # Creating Non Existant Security Group
while True:
non_exist_id = rand_name('999')
if non_exist_id not in security_group_id:
diff --git a/tempest/api/compute/servers/test_disk_config.py b/tempest/api/compute/servers/test_disk_config.py
index e9385b5..efb01af 100644
--- a/tempest/api/compute/servers/test_disk_config.py
+++ b/tempest/api/compute/servers/test_disk_config.py
@@ -39,7 +39,7 @@
resp, server = self.create_server(disk_config='AUTO',
wait_until='ACTIVE')
- #Verify the specified attributes are set correctly
+ # Verify the specified attributes are set correctly
resp, server = self.client.get_server(server['id'])
self.assertEqual('AUTO', server['OS-DCF:diskConfig'])
@@ -47,14 +47,14 @@
self.image_ref_alt,
disk_config='MANUAL')
- #Wait for the server to become active
+ # Wait for the server to become active
self.client.wait_for_server_status(server['id'], 'ACTIVE')
- #Verify the specified attributes are set correctly
+ # Verify the specified attributes are set correctly
resp, server = self.client.get_server(server['id'])
self.assertEqual('MANUAL', server['OS-DCF:diskConfig'])
- #Delete the server
+ # Delete the server
resp, body = self.client.delete_server(server['id'])
@attr(type='gate')
@@ -63,7 +63,7 @@
resp, server = self.create_server(disk_config='MANUAL',
wait_until='ACTIVE')
- #Verify the specified attributes are set correctly
+ # Verify the specified attributes are set correctly
resp, server = self.client.get_server(server['id'])
self.assertEqual('MANUAL', server['OS-DCF:diskConfig'])
@@ -71,14 +71,14 @@
self.image_ref_alt,
disk_config='AUTO')
- #Wait for the server to become active
+ # Wait for the server to become active
self.client.wait_for_server_status(server['id'], 'ACTIVE')
- #Verify the specified attributes are set correctly
+ # Verify the specified attributes are set correctly
resp, server = self.client.get_server(server['id'])
self.assertEqual('AUTO', server['OS-DCF:diskConfig'])
- #Delete the server
+ # Delete the server
resp, body = self.client.delete_server(server['id'])
@testtools.skipUnless(compute.RESIZE_AVAILABLE, 'Resize not available.')
@@ -88,7 +88,7 @@
resp, server = self.create_server(disk_config='MANUAL',
wait_until='ACTIVE')
- #Resize with auto option
+ # Resize with auto option
self.client.resize(server['id'], self.flavor_ref_alt,
disk_config='AUTO')
self.client.wait_for_server_status(server['id'], 'VERIFY_RESIZE')
@@ -98,7 +98,7 @@
resp, server = self.client.get_server(server['id'])
self.assertEqual('AUTO', server['OS-DCF:diskConfig'])
- #Delete the server
+ # Delete the server
resp, body = self.client.delete_server(server['id'])
@testtools.skipUnless(compute.RESIZE_AVAILABLE, 'Resize not available.')
@@ -108,7 +108,7 @@
resp, server = self.create_server(disk_config='AUTO',
wait_until='ACTIVE')
- #Resize with manual option
+ # Resize with manual option
self.client.resize(server['id'], self.flavor_ref_alt,
disk_config='MANUAL')
self.client.wait_for_server_status(server['id'], 'VERIFY_RESIZE')
@@ -118,7 +118,7 @@
resp, server = self.client.get_server(server['id'])
self.assertEqual('MANUAL', server['OS-DCF:diskConfig'])
- #Delete the server
+ # Delete the server
resp, body = self.client.delete_server(server['id'])
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 31b44f7..b8f965c 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -133,7 +133,7 @@
# Verify only the expected number of servers are returned
params = {'limit': 1}
resp, servers = self.client.list_servers(params)
- #when _interface='xml', one element for servers_links in servers
+ # when _interface='xml', one element for servers_links in servers
self.assertEqual(1, len([x for x in servers['servers'] if 'id' in x]))
@utils.skip_unless_attr('multiple_images', 'Only one image found')
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index c03c43e..14ea174 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -35,7 +35,7 @@
if compute.MULTI_USER:
if cls.config.compute.allow_tenant_isolation:
- creds = cls._get_isolated_creds()
+ creds = cls.isolated_creds.get_alt_creds()
username, tenant_name, password = creds
cls.alt_manager = clients.Manager(username=username,
password=password,
@@ -95,7 +95,7 @@
ignore_error=True)
cls.deleted_fixtures.append(srv)
- @attr(type='gate')
+ @attr(type=['negative', 'gate'])
def test_list_servers_with_a_deleted_server(self):
# Verify deleted servers do not show by default in list servers
# List servers and verify server not returned
@@ -107,7 +107,7 @@
self.assertEqual('200', resp['status'])
self.assertEqual([], actual)
- @attr(type='gate')
+ @attr(type=['negative', 'gate'])
def test_list_servers_by_non_existing_image(self):
# Listing servers for a non existing image returns empty list
non_existing_image = '1234abcd-zzz0-aaa9-ppp3-0987654abcde'
@@ -116,7 +116,7 @@
self.assertEqual('200', resp['status'])
self.assertEqual([], servers)
- @attr(type='gate')
+ @attr(type=['negative', 'gate'])
def test_list_servers_by_non_existing_flavor(self):
# Listing servers by non existing flavor returns empty list
non_existing_flavor = 1234
@@ -125,7 +125,7 @@
self.assertEqual('200', resp['status'])
self.assertEqual([], servers)
- @attr(type='gate')
+ @attr(type=['negative', 'gate'])
def test_list_servers_by_non_existing_server_name(self):
# Listing servers for a non existent server name returns empty list
non_existing_name = 'junk_server_1234'
@@ -134,7 +134,7 @@
self.assertEqual('200', resp['status'])
self.assertEqual([], servers)
- @attr(type='gate')
+ @attr(type=['negative', 'gate'])
def test_list_servers_status_non_existing(self):
# Return an empty list when invalid status is specified
non_existing_status = 'BALONEY'
@@ -148,23 +148,23 @@
# List servers by specifying limits
resp, body = self.client.list_servers({'limit': 1})
self.assertEqual('200', resp['status'])
- #when _interface='xml', one element for servers_links in servers
+ # when _interface='xml', one element for servers_links in servers
self.assertEqual(1, len([x for x in body['servers'] if 'id' in x]))
- @attr(type='gate')
+ @attr(type=['negative', 'gate'])
def test_list_servers_by_limits_greater_than_actual_count(self):
# List servers by specifying a greater value for limit
resp, body = self.client.list_servers({'limit': 100})
self.assertEqual('200', resp['status'])
self.assertEqual(len(self.existing_fixtures), len(body['servers']))
- @attr(type='gate')
+ @attr(type=['negative', 'gate'])
def test_list_servers_by_limits_pass_string(self):
# Return an error if a string value is passed for limit
self.assertRaises(exceptions.BadRequest, self.client.list_servers,
{'limit': 'testing'})
- @attr(type='gate')
+ @attr(type=['negative', 'gate'])
def test_list_servers_by_limits_pass_negative_value(self):
# Return an error if a negative value for limit is passed
self.assertRaises(exceptions.BadRequest, self.client.list_servers,
@@ -182,13 +182,13 @@
len(self.deleted_fixtures))
self.assertEqual(num_expected, len(body['servers']))
- @attr(type='gate')
+ @attr(type=['negative', 'gate'])
def test_list_servers_by_changes_since_invalid_date(self):
# Return an error when invalid date format is passed
self.assertRaises(exceptions.BadRequest, self.client.list_servers,
{'changes-since': '2011/01/01'})
- @attr(type='gate')
+ @attr(type=['negative', 'gate'])
def test_list_servers_by_changes_since_future_date(self):
# Return an empty list when a date in the future is passed
changes_since = {'changes-since': '2051-01-01T12:34:00Z'}
@@ -196,7 +196,7 @@
self.assertEqual('200', resp['status'])
self.assertEqual(0, len(body['servers']))
- @attr(type='gate')
+ @attr(type=['negative', 'gate'])
def test_list_servers_detail_server_is_deleted(self):
# Server details are not listed for a deleted server
deleted_ids = [s['id'] for s in self.deleted_fixtures]
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 8b76f7f..893d9e0 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -35,7 +35,7 @@
run_ssh = tempest.config.TempestConfig().compute.run_ssh
def setUp(self):
- #NOTE(afazekas): Normally we use the same server with all test cases,
+ # NOTE(afazekas): Normally we use the same server with all test cases,
# but if it has an issue, we build a new one
super(ServerActionsTestJSON, self).setUp()
# Check if the server is in a clean state after test
@@ -121,13 +121,13 @@
personality=personality,
adminPass=password)
- #Verify the properties in the initial response are correct
+ # Verify the properties in the initial response are correct
self.assertEqual(self.server_id, rebuilt_server['id'])
rebuilt_image_id = rebuilt_server['image']['id']
self.assertTrue(self.image_ref_alt.endswith(rebuilt_image_id))
self.assertEqual(self.flavor_ref, int(rebuilt_server['flavor']['id']))
- #Verify the server properties after the rebuild completes
+ # Verify the server properties after the rebuild completes
self.client.wait_for_server_status(rebuilt_server['id'], 'ACTIVE')
resp, server = self.client.get_server(rebuilt_server['id'])
rebuilt_image_id = rebuilt_server['image']['id']
@@ -279,6 +279,15 @@
cls.server_id = server['id']
cls.password = server['adminPass']
+ @attr(type='gate')
+ def test_stop_start_server(self):
+ resp, server = self.servers_client.stop(self.server_id)
+ self.assertEqual(202, resp.status)
+ self.servers_client.wait_for_server_status(self.server_id, 'SHUTOFF')
+ resp, server = self.servers_client.start(self.server_id)
+ self.assertEqual(202, resp.status)
+ self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
+
class ServerActionsTestXML(ServerActionsTestJSON):
_interface = 'xml'
diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py
index 442d30c..45de0d6 100644
--- a/tempest/api/compute/servers/test_server_metadata.py
+++ b/tempest/api/compute/servers/test_server_metadata.py
@@ -47,7 +47,7 @@
# All metadata key/value pairs for a server should be returned
resp, resp_metadata = self.client.list_server_metadata(self.server_id)
- #Verify the expected metadata items are in the list
+ # Verify the expected metadata items are in the list
self.assertEqual(200, resp.status)
expected = {'key1': 'value1', 'key2': 'value2'}
self.assertEqual(expected, resp_metadata)
@@ -55,14 +55,14 @@
@attr(type='gate')
def test_set_server_metadata(self):
# The server's metadata should be replaced with the provided values
- #Create a new set of metadata for the server
+ # Create a new set of metadata for the server
req_metadata = {'meta2': 'data2', 'meta3': 'data3'}
resp, metadata = self.client.set_server_metadata(self.server_id,
req_metadata)
self.assertEqual(200, resp.status)
- #Verify the expected values are correct, and that the
- #previous values have been removed
+ # Verify the expected values are correct, and that the
+ # previous values have been removed
resp, resp_metadata = self.client.list_server_metadata(self.server_id)
self.assertEqual(resp_metadata, req_metadata)
@@ -98,7 +98,7 @@
meta)
self.assertEqual(200, resp.status)
- #Verify the values have been updated to the proper values
+ # Verify the values have been updated to the proper values
resp, resp_metadata = self.client.list_server_metadata(self.server_id)
expected = {'key1': 'alt1', 'key2': 'value2', 'key3': 'value3'}
self.assertEqual(expected, resp_metadata)
@@ -123,13 +123,13 @@
@attr(type='gate')
def test_set_server_metadata_item(self):
# The item's value should be updated to the provided value
- #Update the metadata value
+ # Update the metadata value
meta = {'nova': 'alt'}
resp, body = self.client.set_server_metadata_item(self.server_id,
'nova', meta)
self.assertEqual(200, resp.status)
- #Verify the meta item's value has been updated
+ # Verify the meta item's value has been updated
resp, resp_metadata = self.client.list_server_metadata(self.server_id)
expected = {'key1': 'value1', 'key2': 'value2', 'nova': 'alt'}
self.assertEqual(expected, resp_metadata)
@@ -141,7 +141,7 @@
'key1')
self.assertEqual(204, resp.status)
- #Verify the metadata item has been removed
+ # Verify the metadata item has been removed
resp, resp_metadata = self.client.list_server_metadata(self.server_id)
expected = {'key2': 'value2'}
self.assertEqual(expected, resp_metadata)
@@ -197,7 +197,7 @@
# Negative test: Should not be able to delete metadata item from a
# nonexistant server
- #Delete the metadata item
+ # Delete the metadata item
self.assertRaises(exceptions.NotFound,
self.client.delete_server_metadata_item, 999, 'd')
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index b35b1b2..82559d5 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -32,12 +32,12 @@
super(ServerRescueTestJSON, cls).setUpClass()
cls.device = 'vdf'
- #Floating IP creation
+ # Floating IP creation
resp, body = cls.floating_ips_client.create_floating_ip()
cls.floating_ip_id = str(body['id']).strip()
cls.floating_ip = str(body['ip']).strip()
- #Security group creation
+ # Security group creation
cls.sg_name = rand_name('sg')
cls.sg_desc = rand_name('sg-desc')
resp, cls.sg = \
@@ -85,7 +85,7 @@
@classmethod
def tearDownClass(cls):
- #Deleting the floating IP which is created in this method
+ # Deleting the floating IP which is created in this method
cls.floating_ips_client.delete_floating_ip(cls.floating_ip_id)
client = cls.volumes_extensions_client
client.delete_volume(str(cls.volume_to_attach['id']).strip())
@@ -127,7 +127,7 @@
@attr(type=['negative', 'gate'])
def test_rescue_paused_instance(self):
- #Rescue a paused server
+ # Rescue a paused server
resp, body = self.servers_client.pause_server(
self.server_id)
self.addCleanup(self._unpause, self.server_id)
@@ -182,7 +182,7 @@
# Rescue the server
self.servers_client.rescue_server(self.server_id, self.password)
self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
- #addCleanup is a LIFO queue
+ # addCleanup is a LIFO queue
self.addCleanup(self._detach, self.server_id,
self.volume_to_detach['id'])
self.addCleanup(self._unrescue, self.server_id)
@@ -201,13 +201,13 @@
self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
self.addCleanup(self._unrescue, self.server_id)
- #Association of floating IP to a rescued vm
+ # Association of floating IP to a rescued vm
client = self.floating_ips_client
resp, body = client.associate_floating_ip_to_server(self.floating_ip,
self.server_id)
self.assertEqual(202, resp.status)
- #Disassociation of floating IP that was associated in this method
+ # Disassociation of floating IP that was associated in this method
resp, body = \
client.disassociate_floating_ip_from_server(self.floating_ip,
self.server_id)
@@ -220,12 +220,12 @@
self.server_id, self.password)
self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
- #Add Security group
+ # Add Security group
resp, body = self.servers_client.add_security_group(self.server_id,
self.sg_name)
self.assertEqual(202, resp.status)
- #Delete Security group
+ # Delete Security group
resp, body = self.servers_client.remove_security_group(self.server_id,
self.sg_name)
self.assertEqual(202, resp.status)
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 703f143..e09a23f 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -255,6 +255,20 @@
self.assertRaises(exceptions.NotFound, self.client.get_server,
'999erra43')
+ @attr(type=['negative', 'gate'])
+ def test_stop_non_existent_server(self):
+ # Stop a non existent server
+ non_exist_id = rand_name('non-existent-server')
+ self.assertRaises(exceptions.NotFound, self.servers_client.stop,
+ non_exist_id)
+
+ @attr(type=['negative', 'gate'])
+ def test_pause_non_existent_server(self):
+ # pause a non existent server
+ non_exist_id = rand_name('non-existent-server')
+ self.assertRaises(exceptions.NotFound, self.client.pause_server,
+ non_exist_id)
+
class ServersNegativeTestXML(ServersNegativeTestJSON):
_interface = 'xml'
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index 1a65a20..60297a9 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -41,7 +41,7 @@
cls.security_client = cls.os.security_groups_client
if cls.config.compute.allow_tenant_isolation:
- creds = cls._get_isolated_creds()
+ creds = cls.isolated_creds.get_alt_creds()
username, tenant_name, password = creds
cls.alt_manager = clients.Manager(username=username,
password=password,
@@ -126,7 +126,7 @@
def test_list_servers_with_alternate_tenant(self):
# A list on servers from one tenant should not
# show on alternate tenant
- #Listing servers from alternate tenant
+ # Listing servers from alternate tenant
alt_server_ids = []
resp, body = self.alt_client.list_servers()
alt_server_ids = [s['id'] for s in body['servers']]
@@ -188,7 +188,7 @@
def test_create_keypair_in_analt_user_tenant(self):
# A create keypair request should fail if the tenant id does not match
# the current user
- #POST keypair with other user tenant
+ # POST keypair with other user tenant
k_name = rand_name('keypair-')
self.alt_keypairs_client._set_auth()
self.saved_base_url = self.alt_keypairs_client.base_url
@@ -238,7 +238,7 @@
def test_create_security_group_in_analt_user_tenant(self):
# A create security group request should fail if the tenant id does not
# match the current user
- #POST security group with other user tenant
+ # POST security group with other user tenant
s_name = rand_name('security-')
s_description = rand_name('security')
self.saved_base_url = self.alt_security_client.base_url
@@ -276,7 +276,7 @@
def test_create_security_group_rule_in_analt_user_tenant(self):
# A create security group rule request should fail if the tenant id
# does not match the current user
- #POST security group rule with other user tenant
+ # POST security group rule with other user tenant
parent_group_id = self.security_group['id']
ip_protocol = 'icmp'
from_port = -1
diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py
index f2dd93c..4f0f17e 100644
--- a/tempest/api/compute/volumes/test_volumes_get.py
+++ b/tempest/api/compute/volumes/test_volumes_get.py
@@ -38,7 +38,7 @@
volume = None
v_name = rand_name('Volume-%s-') % self._interface
metadata = {'Type': 'work'}
- #Create volume
+ # Create volume
resp, volume = self.client.create_volume(size=1,
display_name=v_name,
metadata=metadata)
@@ -51,12 +51,12 @@
"to the requested name")
self.assertTrue(volume['id'] is not None,
"Field volume id is empty or not found.")
- #Wait for Volume status to become ACTIVE
+ # Wait for Volume status to become ACTIVE
self.client.wait_for_volume_status(volume['id'], 'available')
- #GET Volume
+ # GET Volume
resp, fetched_volume = self.client.get_volume(volume['id'])
self.assertEqual(200, resp.status)
- #Verfication of details of fetched Volume
+ # Verfication of details of fetched Volume
self.assertEqual(v_name,
fetched_volume['displayName'],
'The fetched Volume is different '
@@ -74,7 +74,7 @@
def test_volume_get_metadata_none(self):
# CREATE, GET empty metadata dict
v_name = rand_name('Volume-')
- #Create volume
+ # Create volume
resp, volume = self.client.create_volume(size=1,
display_name=v_name,
metadata={})
@@ -82,19 +82,19 @@
self.assertEqual(200, resp.status)
self.assertIn('id', volume)
self.assertIn('displayName', volume)
- #Wait for Volume status to become ACTIVE
+ # Wait for Volume status to become ACTIVE
self.client.wait_for_volume_status(volume['id'], 'available')
- #GET Volume
+ # GET Volume
resp, fetched_volume = self.client.get_volume(volume['id'])
self.assertEqual(200, resp.status)
self.assertEqual(fetched_volume['metadata'], {})
def _delete_volume(self, volume):
- #Delete the Volume created in this method
+ # Delete the Volume created in this method
try:
resp, _ = self.client.delete_volume(volume['id'])
self.assertEqual(202, resp.status)
- #Checking if the deleted Volume still exists
+ # Checking if the deleted Volume still exists
self.client.wait_for_resource_deletion(volume['id'])
except KeyError:
return
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index 02cc4e1..0e475cf 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -97,10 +97,10 @@
@attr(type='gate')
def test_volume_list_with_details(self):
# Should return the list of Volumes with details
- #Fetch all Volumes
+ # Fetch all Volumes
resp, fetched_list = self.client.list_volumes_with_detail()
self.assertEqual(200, resp.status)
- #Now check if all the Volumes created in setup are in fetched list
+ # Now check if all the Volumes created in setup are in fetched list
missing_volumes = [
v for v in self.volume_list if v not in fetched_list
]
diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py
index 2ecf3e8..c91e95b 100644
--- a/tempest/api/compute/volumes/test_volumes_negative.py
+++ b/tempest/api/compute/volumes/test_volumes_negative.py
@@ -35,7 +35,7 @@
@attr(type=['negative', 'gate'])
def test_volume_get_nonexistant_volume_id(self):
# Negative: Should not be able to get details of nonexistant volume
- #Creating a nonexistant volume id
+ # Creating a nonexistant volume id
volume_id_list = list()
resp, body = self.client.list_volumes()
for i in range(len(body)):
diff --git a/tempest/api/identity/admin/test_services.py b/tempest/api/identity/admin/test_services.py
index a590735..2be0c29 100644
--- a/tempest/api/identity/admin/test_services.py
+++ b/tempest/api/identity/admin/test_services.py
@@ -29,14 +29,14 @@
def test_create_get_delete_service(self):
# GET Service
try:
- #Creating a Service
+ # Creating a Service
name = rand_name('service-')
type = rand_name('type--')
description = rand_name('description-')
resp, service_data = self.client.create_service(
name, type, description=description)
self.assertTrue(resp['status'].startswith('2'))
- #Verifying response body of create service
+ # Verifying response body of create service
self.assertIn('id', service_data)
self.assertFalse(service_data['id'] is None)
self.assertIn('name', service_data)
@@ -45,10 +45,10 @@
self.assertEqual(type, service_data['type'])
self.assertIn('description', service_data)
self.assertEqual(description, service_data['description'])
- #Get service
+ # Get service
resp, fetched_service = self.client.get_service(service_data['id'])
self.assertTrue(resp['status'].startswith('2'))
- #verifying the existence of service created
+ # verifying the existence of service created
self.assertIn('id', fetched_service)
self.assertEquals(fetched_service['id'], service_data['id'])
self.assertIn('name', fetched_service)
diff --git a/tempest/api/identity/admin/test_users.py b/tempest/api/identity/admin/test_users.py
index 3a20081..6f90b04 100644
--- a/tempest/api/identity/admin/test_users.py
+++ b/tempest/api/identity/admin/test_users.py
@@ -240,12 +240,12 @@
self.assertEquals('200', resp['status'])
user_ids.append(user2['id'])
self.data.users.append(user2)
- #List of users for the respective tenant ID
+ # List of users for the respective tenant ID
resp, body = self.client.list_users_for_tenant(self.data.tenant['id'])
self.assertIn(resp['status'], ('200', '203'))
for i in body:
fetched_user_ids.append(i['id'])
- #verifying the user Id in the list
+ # verifying the user Id in the list
missing_users =\
[user for user in user_ids if user not in fetched_user_ids]
self.assertEqual(0, len(missing_users),
@@ -260,7 +260,7 @@
user = self.get_user_by_name(self.data.test_user)
tenant = self.get_tenant_by_name(self.data.test_tenant)
role = self.get_role_by_name(self.data.test_role)
- #Assigning roles to two users
+ # Assigning roles to two users
user_ids = list()
fetched_user_ids = list()
user_ids.append(user['id'])
@@ -277,12 +277,12 @@
second_user['id'],
role['id'])
self.assertEquals('200', resp['status'])
- #List of users with roles for the respective tenant ID
+ # List of users with roles for the respective tenant ID
resp, body = self.client.list_users_for_tenant(self.data.tenant['id'])
self.assertEquals('200', resp['status'])
for i in body:
fetched_user_ids.append(i['id'])
- #verifying the user Id in the list
+ # verifying the user Id in the list
missing_users = [missing_user for missing_user in user_ids
if missing_user not in fetched_user_ids]
self.assertEqual(0, len(missing_users),
@@ -293,13 +293,13 @@
def test_list_users_with_invalid_tenant(self):
# Should not be able to return a list of all
# users for a nonexistant tenant
- #Assign invalid tenant ids
+ # Assign invalid tenant ids
invalid_id = list()
invalid_id.append(rand_name('999'))
invalid_id.append('alpha')
invalid_id.append(rand_name("dddd@#%%^$"))
invalid_id.append('!@#()$%^&*?<>{}[]')
- #List the users with invalid tenant id
+ # List the users with invalid tenant id
for invalid in invalid_id:
self.assertRaises(exceptions.NotFound,
self.client.list_users_for_tenant, invalid)
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index 3d40eb3..9136934 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -33,7 +33,7 @@
@attr(type='smoke')
def test_list_domains(self):
- #Test to list domains
+ # Test to list domains
domain_ids = list()
fetched_ids = list()
for _ in range(3):
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index f01cc64..9f7b24b 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -37,7 +37,7 @@
description=s_description)
cls.service_id = cls.service_data['id']
cls.service_ids.append(cls.service_id)
- #Create endpoints so as to use for LIST and GET test cases
+ # Create endpoints so as to use for LIST and GET test cases
cls.setup_endpoints = list()
for i in range(2):
region = rand_name('region')
@@ -58,7 +58,7 @@
def test_list_endpoints(self):
# Get a list of endpoints
resp, fetched_endpoints = self.client.list_endpoints()
- #Asserting LIST Endpoint
+ # Asserting LIST Endpoint
self.assertEqual(resp['status'], '200')
missing_endpoints =\
[e for e in self.setup_endpoints if e not in fetched_endpoints]
@@ -78,11 +78,11 @@
self.client.create_endpoint(self.service_id, interface, url,
region=region, enabled=True)
create_flag = True
- #Asserting Create Endpoint response body
+ # Asserting Create Endpoint response body
self.assertEqual(resp['status'], '201')
self.assertEqual(region, endpoint['region'])
self.assertEqual(url, endpoint['url'])
- #Checking if created endpoint is present in the list of endpoints
+ # Checking if created endpoint is present in the list of endpoints
resp, fetched_endpoints = self.client.list_endpoints()
for e in fetched_endpoints:
if endpoint['id'] == e['id']:
@@ -93,12 +93,12 @@
finally:
if create_flag:
matched = False
- #Deleting the endpoint created in this method
+ # Deleting the endpoint created in this method
resp_header, resp_body =\
self.client.delete_endpoint(endpoint['id'])
self.assertEqual(resp_header['status'], '204')
self.assertEqual(resp_body, '')
- #Checking whether endpoint is deleted successfully
+ # Checking whether endpoint is deleted successfully
resp, fetched_endpoints = self.client.list_endpoints()
for e in fetched_endpoints:
if endpoint['id'] == e['id']:
@@ -108,8 +108,8 @@
@attr(type='smoke')
def test_update_endpoint(self):
- #Creating an endpoint so as to check update endpoint
- #with new values
+ # Creating an endpoint so as to check update endpoint
+ # with new values
region1 = rand_name('region')
url1 = rand_name('url')
interface1 = 'public'
@@ -117,7 +117,7 @@
self.client.create_endpoint(self.service_id, interface1,
url1, region=region1,
enabled=True)
- #Creating service so as update endpoint with new service ID
+ # Creating service so as update endpoint with new service ID
s_name = rand_name('service-')
s_type = rand_name('type--')
s_description = rand_name('description-')
@@ -125,7 +125,7 @@
self.identity_client.create_service(s_name, s_type,
description=s_description)
self.service_ids.append(self.service2['id'])
- #Updating endpoint with new values
+ # Updating endpoint with new values
region2 = rand_name('region')
url2 = rand_name('url')
interface2 = 'internal'
@@ -135,7 +135,7 @@
interface=interface2, url=url2,
region=region2, enabled=False)
self.assertEqual(resp['status'], '200')
- #Asserting if the attributes of endpoint are updated
+ # Asserting if the attributes of endpoint are updated
self.assertEqual(self.service2['id'], endpoint['service_id'])
self.assertEqual(interface2, endpoint['interface'])
self.assertEqual(url2, endpoint['url'])
diff --git a/tempest/api/identity/admin/v3/test_policies.py b/tempest/api/identity/admin/v3/test_policies.py
index 681db07..737a0e0 100644
--- a/tempest/api/identity/admin/v3/test_policies.py
+++ b/tempest/api/identity/admin/v3/test_policies.py
@@ -29,7 +29,7 @@
@attr(type='smoke')
def test_list_policies(self):
- #Test to list policies
+ # Test to list policies
policy_ids = list()
fetched_ids = list()
for _ in range(3):
@@ -50,7 +50,7 @@
@attr(type='smoke')
def test_create_update_delete_policy(self):
- #Test to update policy
+ # Test to update policy
blob = rand_name('BlobName-')
policy_type = rand_name('PolicyType-')
resp, policy = self.policy_client.create_policy(blob, policy_type)
@@ -63,12 +63,12 @@
self.assertEqual(policy_type, policy['type'])
resp, fetched_policy = self.policy_client.get_policy(policy['id'])
self.assertEqual(resp['status'], '200')
- #Update policy
+ # Update policy
update_type = rand_name('UpdatedPolicyType-')
resp, data = self.policy_client.update_policy(
policy['id'], type=update_type)
self.assertIn('type', data)
- #Assertion for updated value with fetched value
+ # Assertion for updated value with fetched value
resp, fetched_policy = self.policy_client.get_policy(policy['id'])
self.assertIn('id', fetched_policy)
self.assertIn('blob', fetched_policy)
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
new file mode 100644
index 0000000..cab84c0
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -0,0 +1,170 @@
+# 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.
+
+from tempest.api.identity import base
+from tempest.common.utils.data_utils import rand_name
+from tempest.test import attr
+
+
+class RolesV3TestJSON(base.BaseIdentityAdminTest):
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(RolesV3TestJSON, cls).setUpClass()
+ cls.fetched_role_ids = list()
+ u_name = rand_name('user-')
+ u_desc = '%s description' % u_name
+ u_email = '%s@testmail.tm' % u_name
+ u_password = rand_name('pass-')
+ resp = [None] * 5
+ resp[0], cls.project = cls.v3_client.create_project(
+ rand_name('project-'), description=rand_name('project-desc-'))
+ resp[1], cls.domain = cls.v3_client.create_domain(
+ rand_name('domain-'), description=rand_name('domain-desc-'))
+ resp[2], cls.group_body = cls.v3_client.create_group(
+ rand_name('Group-'), project_id=cls.project['id'],
+ domain_id=cls.domain['id'])
+ resp[3], cls.user_body = cls.v3_client.create_user(
+ u_name, description=u_desc, password=u_password,
+ email=u_email, project_id=cls.project['id'],
+ domain_id=cls.domain['id'])
+ resp[4], cls.role = cls.v3_client.create_role(rand_name('Role-'))
+ for r in resp:
+ assert r['status'] == '201', "Expected: %s" % r['status']
+
+ @classmethod
+ def tearDownClass(cls):
+ resp = [None] * 5
+ resp[0], _ = cls.v3_client.delete_role(cls.role['id'])
+ resp[1], _ = cls.v3_client.delete_group(cls.group_body['id'])
+ resp[2], _ = cls.v3_client.delete_user(cls.user_body['id'])
+ resp[3], _ = cls.v3_client.delete_project(cls.project['id'])
+ #NOTE(harika-vakadi): It is necessary to disable the domian
+ # before deleting,or else it would result in unauthorized error
+ cls.v3_client.update_domain(cls.domain['id'], enabled=False)
+ resp[4], _ = cls.v3_client.delete_domain(cls.domain['id'])
+ for r in resp:
+ assert r['status'] == '204', "Expected: %s" % r['status']
+ super(RolesV3TestJSON, cls).tearDownClass()
+
+ def _list_assertions(self, resp, body, fetched_role_ids, role_id):
+ self.assertEqual(resp['status'], '200')
+ self.assertEqual(len(body), 1)
+ self.assertIn(role_id, fetched_role_ids)
+
+ @attr(type='smoke')
+ def test_role_create_update_get(self):
+ r_name = rand_name('Role-')
+ resp, role = self.v3_client.create_role(r_name)
+ self.addCleanup(self.v3_client.delete_role, role['id'])
+ self.assertEqual(resp['status'], '201')
+ self.assertIn('name', role)
+ self.assertEqual(role['name'], r_name)
+
+ new_name = rand_name('NewRole-')
+ resp, updated_role = self.v3_client.update_role(new_name, role['id'])
+ self.assertEqual(resp['status'], '200')
+ self.assertIn('name', updated_role)
+ self.assertIn('id', updated_role)
+ self.assertIn('links', updated_role)
+ self.assertNotEqual(r_name, updated_role['name'])
+
+ resp, new_role = self.v3_client.get_role(role['id'])
+ self.assertEqual(resp['status'], '200')
+ self.assertEqual(new_name, new_role['name'])
+ self.assertEqual(updated_role['id'], new_role['id'])
+
+ @attr(type='smoke')
+ def test_grant_list_revoke_role_to_user_on_project(self):
+ resp, _ = self.v3_client.assign_user_role_on_project(
+ self.project['id'], self.user_body['id'], self.role['id'])
+ self.assertEqual(resp['status'], '204')
+
+ resp, roles = self.v3_client.list_user_roles_on_project(
+ self.project['id'], self.user_body['id'])
+
+ for i in roles:
+ self.fetched_role_ids.append(i['id'])
+
+ self._list_assertions(resp, roles, self.fetched_role_ids,
+ self.role['id'])
+
+ resp, _ = self.v3_client.revoke_role_from_user_on_project(
+ self.project['id'], self.user_body['id'], self.role['id'])
+ self.assertEqual(resp['status'], '204')
+
+ @attr(type='smoke')
+ def test_grant_list_revoke_role_to_user_on_domain(self):
+ resp, _ = self.v3_client.assign_user_role_on_domain(
+ self.domain['id'], self.user_body['id'], self.role['id'])
+ self.assertEqual(resp['status'], '204')
+
+ resp, roles = self.v3_client.list_user_roles_on_domain(
+ self.domain['id'], self.user_body['id'])
+
+ for i in roles:
+ self.fetched_role_ids.append(i['id'])
+
+ self._list_assertions(resp, roles, self.fetched_role_ids,
+ self.role['id'])
+
+ resp, _ = self.v3_client.revoke_role_from_user_on_domain(
+ self.domain['id'], self.user_body['id'], self.role['id'])
+ self.assertEqual(resp['status'], '204')
+
+ @attr(type='smoke')
+ def test_grant_list_revoke_role_to_group_on_project(self):
+ resp, _ = self.v3_client.assign_group_role_on_project(
+ self.project['id'], self.group_body['id'], self.role['id'])
+ self.assertEqual(resp['status'], '204')
+
+ resp, roles = self.v3_client.list_group_roles_on_project(
+ self.project['id'], self.group_body['id'])
+
+ for i in roles:
+ self.fetched_role_ids.append(i['id'])
+
+ self._list_assertions(resp, roles, self.fetched_role_ids,
+ self.role['id'])
+
+ resp, _ = self.v3_client.revoke_role_from_group_on_project(
+ self.project['id'], self.group_body['id'], self.role['id'])
+ self.assertEqual(resp['status'], '204')
+
+ @attr(type='smoke')
+ def test_grant_list_revoke_role_to_group_on_domain(self):
+ resp, _ = self.v3_client.assign_group_role_on_domain(
+ self.domain['id'], self.group_body['id'], self.role['id'])
+ self.assertEqual(resp['status'], '204')
+
+ resp, roles = self.v3_client.list_group_roles_on_domain(
+ self.domain['id'], self.group_body['id'])
+
+ for i in roles:
+ self.fetched_role_ids.append(i['id'])
+
+ self._list_assertions(resp, roles, self.fetched_role_ids,
+ self.role['id'])
+
+ resp, _ = self.v3_client.revoke_role_from_group_on_domain(
+ self.domain['id'], self.group_body['id'], self.role['id'])
+ self.assertEqual(resp['status'], '204')
+
+
+class RolesV3TestXML(RolesV3TestJSON):
+ _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_services.py b/tempest/api/identity/admin/v3/test_services.py
index b35b93a..bfa0d84 100644
--- a/tempest/api/identity/admin/v3/test_services.py
+++ b/tempest/api/identity/admin/v3/test_services.py
@@ -1,4 +1,4 @@
-#vim: tabstop=4 shiftwidth=4 softtabstop=4
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 OpenStack Foundation
# All Rights Reserved.
@@ -33,7 +33,7 @@
resp, body = self.client.create_service(
name, type, description=description)
self.assertEqual('200', resp['status'])
- #Deleting the service created in this method
+ # Deleting the service created in this method
self.addCleanup(self.client.delete_service, body['id'])
s_id = body['id']
@@ -46,7 +46,7 @@
self.assertEqual('200', resp['status'])
self.assertNotEqual(resp1_desc, resp2_desc)
- #Get service
+ # Get service
resp, body = self.client.get_service(s_id)
resp3_desc = body['description']
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index 04e993d..bf7a554 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -26,7 +26,7 @@
@attr(type='gate')
def test_user_update(self):
# Test case to check if updating of user attributes is successful.
- #Creating first user
+ # Creating first user
u_name = rand_name('user-')
u_desc = u_name + 'description'
u_email = u_name + '@testmail.tm'
@@ -36,12 +36,12 @@
email=u_email, enabled=False)
# Delete the User at the end of this method
self.addCleanup(self.v3_client.delete_user, user['id'])
- #Creating second project for updation
+ # Creating second project for updation
resp, project = self.v3_client.create_project(
rand_name('project-'), description=rand_name('project-desc-'))
# Delete the Project at the end of this method
self.addCleanup(self.v3_client.delete_project, project['id'])
- #Updating user details with new values
+ # Updating user details with new values
u_name2 = rand_name('user2-')
u_email2 = u_name2 + '@testmail.tm'
u_description2 = u_name2 + ' description'
@@ -49,7 +49,7 @@
user['id'], name=u_name2, description=u_description2,
project_id=project['id'],
email=u_email2, enabled=False)
- #Assert response body of update user.
+ # Assert response body of update user.
self.assertEqual(200, resp.status)
self.assertEqual(u_name2, update_user['name'])
self.assertEqual(u_description2, update_user['description'])
@@ -57,9 +57,9 @@
update_user['project_id'])
self.assertEqual(u_email2, update_user['email'])
self.assertEqual('false', str(update_user['enabled']).lower())
- #GET by id after updation
+ # GET by id after updation
resp, new_user_get = self.v3_client.get_user(user['id'])
- #Assert response body of GET after updation
+ # Assert response body of GET after updation
self.assertEqual(u_name2, new_user_get['name'])
self.assertEqual(u_description2, new_user_get['description'])
self.assertEqual(project['id'],
@@ -69,14 +69,14 @@
@attr(type='gate')
def test_list_user_projects(self):
- #List the projects that a user has access upon
+ # List the projects that a user has access upon
assigned_project_ids = list()
fetched_project_ids = list()
_, u_project = self.v3_client.create_project(
rand_name('project-'), description=rand_name('project-desc-'))
# Delete the Project at the end of this method
self.addCleanup(self.v3_client.delete_project, u_project['id'])
- #Create a user.
+ # Create a user.
u_name = rand_name('user-')
u_desc = u_name + 'description'
u_email = u_name + '@testmail.tm'
@@ -100,7 +100,7 @@
_, project = self.v3_client.get_project(project_body['id'])
# Delete the Project at the end of this method
self.addCleanup(self.v3_client.delete_project, project_body['id'])
- #Assigning roles to user on project
+ # Assigning roles to user on project
self.v3_client.assign_user_role(project['id'],
user['id'],
role['id'])
@@ -109,7 +109,7 @@
self.assertEqual(200, resp.status)
for i in body:
fetched_project_ids.append(i['id'])
- #verifying the project ids in list
+ # verifying the project ids in list
missing_projects =\
[p for p in assigned_project_ids
if p not in fetched_project_ids]
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 086c50e..4e61495 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -15,6 +15,7 @@
# under the License.
from tempest import clients
+from tempest.common import isolated_creds
from tempest.common.utils.data_utils import rand_name
from tempest import exceptions
from tempest.openstack.common import log as logging
@@ -28,14 +29,14 @@
@classmethod
def setUpClass(cls):
- cls.isolated_creds = []
cls.created_images = []
cls._interface = 'json'
+ cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
if not cls.config.service_available.glance:
skip_msg = ("%s skipped as glance is not available" % cls.__name__)
raise cls.skipException(skip_msg)
if cls.config.compute.allow_tenant_isolation:
- creds = cls._get_isolated_creds()
+ creds = cls.isolated_creds.get_primary_creds()
username, tenant_name, password = creds
cls.os = clients.Manager(username=username,
password=password,
@@ -53,7 +54,8 @@
for image_id in cls.created_images:
cls.client.wait_for_resource_deletion(image_id)
- cls._clear_isolated_creds()
+ cls.isolated_creds.clear_isolated_creds()
+ super(BaseImageTest, cls).tearDownClass()
@classmethod
def create_image(cls, **kwargs):
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 7de7821..ad7be39 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -105,3 +105,8 @@
image_list = map(lambda x: x['id'], images_list)
for image in self.created_images:
self.assertIn(image, image_list)
+
+ @attr(type=['negative', 'gate'])
+ def test_get_image_meta_by_null_id(self):
+ self.assertRaises(exceptions.NotFound,
+ self.client.get_image_metadata, '')
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 142ad7d..d3fa763 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -38,6 +38,11 @@
tenant_network_mask_bits with the mask bits to be used to partition the
block defined by tenant-network_cidr
+
+ Finally, it is assumed that the following option is defined in the
+ [service_available] section of etc/tempest.conf
+
+ neutron as True
"""
@classmethod
@@ -49,9 +54,12 @@
cls.client = os.network_client
cls.networks = []
cls.subnets = []
+ cls.ports = []
@classmethod
def tearDownClass(cls):
+ for port in cls.ports:
+ cls.client.delete_port(port['id'])
for subnet in cls.subnets:
cls.client.delete_subnet(subnet['id'])
for network in cls.networks:
@@ -93,3 +101,11 @@
subnet = body['subnet']
cls.subnets.append(subnet)
return subnet
+
+ @classmethod
+ def create_port(cls, network):
+ """Wrapper utility that returns a test port."""
+ resp, body = cls.client.create_port(network['id'])
+ port = body['port']
+ cls.ports.append(port)
+ return port
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 4481853..00a8ef7 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -35,6 +35,13 @@
create a subnet for a tenant
list tenant's subnets
show a tenant subnet details
+ port create
+ port delete
+ port list
+ port show
+ port update
+ network update
+ subnet update
v2.0 of the Neutron API is assumed. It is also assumed that the following
options are defined in the [network] section of etc/tempest.conf:
@@ -53,21 +60,28 @@
cls.name = cls.network['name']
cls.subnet = cls.create_subnet(cls.network)
cls.cidr = cls.subnet['cidr']
+ cls.port = cls.create_port(cls.network)
@attr(type='gate')
- def test_create_delete_network_subnet(self):
+ def test_create_update_delete_network_subnet(self):
# Creates a network
name = rand_name('network-')
resp, body = self.client.create_network(name)
self.assertEqual('201', resp['status'])
network = body['network']
- self.assertTrue(network['id'] is not None)
+ net_id = network['id']
+ # Verification of network update
+ new_name = "New_network"
+ resp, body = self.client.update_network(net_id, new_name)
+ self.assertEqual('200', resp['status'])
+ updated_net = body['network']
+ self.assertEqual(updated_net['name'], new_name)
# Find a cidr that is not in use yet and create a subnet with it
cidr = netaddr.IPNetwork(self.network_cfg.tenant_network_cidr)
mask_bits = self.network_cfg.tenant_network_mask_bits
for subnet_cidr in cidr.subnet(mask_bits):
try:
- resp, body = self.client.create_subnet(network['id'],
+ resp, body = self.client.create_subnet(net_id,
str(subnet_cidr))
break
except exceptions.BadRequest as e:
@@ -76,11 +90,17 @@
raise
self.assertEqual('201', resp['status'])
subnet = body['subnet']
- self.assertTrue(subnet['id'] is not None)
- #Deletes subnet and network
- resp, body = self.client.delete_subnet(subnet['id'])
+ subnet_id = subnet['id']
+ # Verification of subnet update
+ new_subnet = "New_subnet"
+ resp, body = self.client.update_subnet(subnet_id, new_subnet)
+ self.assertEqual('200', resp['status'])
+ updated_subnet = body['subnet']
+ self.assertEqual(updated_subnet['name'], new_subnet)
+ # Deletes subnet and network
+ resp, body = self.client.delete_subnet(subnet_id)
self.assertEqual('204', resp['status'])
- resp, body = self.client.delete_network(network['id'])
+ resp, body = self.client.delete_network(net_id)
self.assertEqual('204', resp['status'])
@attr(type='gate')
@@ -97,8 +117,12 @@
# Verify the network exists in the list of all networks
resp, body = self.client.list_networks()
networks = body['networks']
- found = any(n for n in networks if n['id'] == self.network['id'])
- self.assertTrue(found)
+ found = None
+ for n in networks:
+ if (n['id'] == self.network['id']):
+ found = n['id']
+ msg = "Network list doesn't contain created network"
+ self.assertIsNotNone(found, msg)
@attr(type='gate')
def test_show_subnet(self):
@@ -114,5 +138,57 @@
# Verify the subnet exists in the list of all subnets
resp, body = self.client.list_subnets()
subnets = body['subnets']
- found = any(n for n in subnets if n['id'] == self.subnet['id'])
- self.assertTrue(found)
+ found = None
+ for n in subnets:
+ if (n['id'] == self.subnet['id']):
+ found = n['id']
+ msg = "Subnet list doesn't contain created subnet"
+ self.assertIsNotNone(found, msg)
+
+ @attr(type='gate')
+ def test_create_update_delete_port(self):
+ # Verify that successful port creation & deletion
+ resp, body = self.client.create_port(self.network['id'])
+ self.assertEqual('201', resp['status'])
+ port = body['port']
+ # Verification of port update
+ new_port = "New_Port"
+ resp, body = self.client.update_port(port['id'], new_port)
+ self.assertEqual('200', resp['status'])
+ updated_port = body['port']
+ self.assertEqual(updated_port['name'], new_port)
+ # Verification of port delete
+ resp, body = self.client.delete_port(port['id'])
+ self.assertEqual('204', resp['status'])
+
+ @attr(type='gate')
+ def test_show_ports(self):
+ # Verify the details of port
+ resp, body = self.client.show_port(self.port['id'])
+ self.assertEqual('200', resp['status'])
+ port = body['port']
+ self.assertEqual(self.port['id'], port['id'])
+
+ @attr(type='gate')
+ def test_list_ports(self):
+ # Verify the port exists in the list of all ports
+ resp, body = self.client.list_ports()
+ self.assertEqual('200', resp['status'])
+ ports_list = body['ports']
+ found = None
+ for n in ports_list:
+ if (n['id'] == self.port['id']):
+ found = n['id']
+ self.assertIsNotNone(found, "Port list doesn't contain created port")
+
+ @attr(type=['negative', 'gate'])
+ def test_show_non_existent_network(self):
+ non_exist_id = rand_name('network')
+ self.assertRaises(exceptions.NotFound, self.client.show_network,
+ non_exist_id)
+
+ @attr(type=['negative', 'gate'])
+ def test_show_non_existent_subnet(self):
+ non_exist_id = rand_name('subnet')
+ self.assertRaises(exceptions.NotFound, self.client.show_subnet,
+ non_exist_id)
diff --git a/tempest/api/network/test_quotas.py b/tempest/api/network/test_quotas.py
new file mode 100644
index 0000000..ba70f34
--- /dev/null
+++ b/tempest/api/network/test_quotas.py
@@ -0,0 +1,91 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 OpenStack, LLC
+# 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 import clients
+from tempest.common.utils.data_utils import rand_name
+from tempest.test import attr
+
+
+class QuotasTest(base.BaseNetworkTest):
+
+ """
+ Tests the following operations in the Neutron API using the REST client for
+ Neutron:
+
+ list quotas for tenants who have non-default quota values
+ show quotas for a specified tenant
+ update quotas for a specified tenant
+ reset quotas to default values for a specified tenant
+
+ v2.0 of the API is assumed. It is also assumed that the following
+ option is defined in the [service_available] section of etc/tempest.conf:
+
+ neutron as True
+
+ Finally, it is assumed that the per-tenant quota extension API is
+ configured in /etc/neutron/neutron.conf as follows:
+
+ quota_driver = neutron.db.quota_db.DbQuotaDriver
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ super(QuotasTest, cls).setUpClass()
+ admin_manager = clients.AdminManager()
+ cls.admin_client = admin_manager.network_client
+ cls.identity_admin_client = admin_manager.identity_client
+
+ @attr(type='gate')
+ def test_quotas(self):
+ # Add a tenant to conduct the test
+ test_tenant = rand_name('test_tenant_')
+ test_description = rand_name('desc_')
+ _, tenant = self.identity_admin_client.create_tenant(
+ name=test_tenant,
+ description=test_description)
+ tenant_id = tenant['id']
+ self.addCleanup(self.identity_admin_client.delete_tenant, tenant_id)
+ # Change quotas for tenant
+ new_quotas = {'network': 0, 'security_group': 0}
+ resp, quota_set = self.admin_client.update_quotas(tenant_id,
+ **new_quotas)
+ self.assertEqual('200', resp['status'])
+ self.addCleanup(self.admin_client.reset_quotas, tenant_id)
+ self.assertEqual(0, quota_set['network'])
+ self.assertEqual(0, quota_set['security_group'])
+ # Confirm our tenant is listed among tenants with non default quotas
+ resp, non_default_quotas = self.admin_client.list_quotas()
+ self.assertEqual('200', resp['status'])
+ found = False
+ for qs in non_default_quotas:
+ if qs['tenant_id'] == tenant_id:
+ found = True
+ self.assertTrue(found)
+ # Confirm from APi quotas were changed as requested for tenant
+ resp, quota_set = self.admin_client.show_quotas(tenant_id)
+ self.assertEqual('200', resp['status'])
+ self.assertEqual(0, quota_set['network'])
+ self.assertEqual(0, quota_set['security_group'])
+ # Reset quotas to default and confirm
+ resp, body = self.admin_client.reset_quotas(tenant_id)
+ self.assertEqual('204', resp['status'])
+ resp, non_default_quotas = self.admin_client.list_quotas()
+ self.assertEqual('200', resp['status'])
+ for q in non_default_quotas:
+ self.assertNotEqual(tenant_id, q['tenant_id'])
diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py
new file mode 100644
index 0000000..bc050dc
--- /dev/null
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -0,0 +1,115 @@
+# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
+#
+# Author: Joe H. Rahme <joe.hakim.rahme@enovance.com>
+#
+# 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.object_storage import base
+from tempest import clients
+from tempest.common.utils.data_utils import arbitrary_string
+from tempest.common.utils.data_utils import rand_name
+import tempest.config
+from tempest import exceptions
+from tempest.test import attr
+
+
+class AccountQuotasTest(base.BaseObjectTest):
+ accounts_quotas_available = \
+ tempest.config.TempestConfig().object_storage.accounts_quotas_available
+
+ @classmethod
+ def setUpClass(cls):
+ super(AccountQuotasTest, cls).setUpClass()
+ cls.container_name = rand_name(name="TestContainer")
+ cls.container_client.create_container(cls.container_name)
+
+ cls.data.setup_test_user()
+
+ cls.os_reselleradmin = clients.Manager(
+ cls.data.test_user,
+ cls.data.test_password,
+ cls.data.test_tenant)
+
+ # Retrieve the ResellerAdmin role id
+ reseller_role_id = None
+ try:
+ _, roles = cls.os_admin.identity_client.list_roles()
+ reseller_role_id = next(r['id'] for r in roles if r['name']
+ == 'ResellerAdmin')
+ except StopIteration:
+ msg = "No ResellerAdmin role found"
+ raise exceptions.NotFound(msg)
+
+ # Retrieve the ResellerAdmin tenant id
+ _, users = cls.os_admin.identity_client.get_users()
+ reseller_user_id = next(usr['id'] for usr in users if usr['name']
+ == cls.data.test_user)
+
+ # Retrieve the ResellerAdmin tenant id
+ _, tenants = cls.os_admin.identity_client.list_tenants()
+ reseller_tenant_id = next(tnt['id'] for tnt in tenants if tnt['name']
+ == cls.data.test_tenant)
+
+ # Assign the newly created user the appropriate ResellerAdmin role
+ cls.os_admin.identity_client.assign_user_role(
+ reseller_tenant_id,
+ reseller_user_id,
+ reseller_role_id)
+
+ # Retrieve a ResellerAdmin auth token and use it to set a quota
+ # on the client's account
+ cls.reselleradmin_token = cls.token_client.get_token(
+ cls.data.test_user,
+ cls.data.test_password,
+ cls.data.test_tenant)
+
+ headers = {"X-Auth-Token": cls.reselleradmin_token,
+ "X-Account-Meta-Quota-Bytes": "20"}
+
+ cls.os.custom_account_client.request("POST", "", headers, "")
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.delete_containers([cls.container_name])
+ cls.data.teardown_all()
+
+ # remove the quota from the container
+ headers = {"X-Auth-Token": cls.reselleradmin_token,
+ "X-Remove-Account-Meta-Quota-Bytes": "x"}
+
+ cls.os.custom_account_client.request("POST", "", headers, "")
+
+ super(AccountQuotasTest, cls).tearDownClass()
+
+ @testtools.skipIf(not accounts_quotas_available,
+ "Account Quotas middleware not available")
+ @attr(type="smoke")
+ def test_upload_valid_object(self):
+ object_name = rand_name(name="TestObject")
+ data = arbitrary_string()
+ resp, _ = self.object_client.create_object(self.container_name,
+ object_name, data)
+
+ self.assertEqual(resp["status"], "201")
+
+ @testtools.skipIf(not accounts_quotas_available,
+ "Account Quotas middleware not available")
+ @attr(type=["negative", "smoke"])
+ def test_upload_large_object(self):
+ object_name = rand_name(name="TestObject")
+ data = arbitrary_string(30)
+ self.assertRaises(exceptions.OverLimit,
+ self.object_client.create_object,
+ self.container_name, object_name, data)
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 52b37c1..b443933 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -15,6 +15,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import random
+
from tempest.api.object_storage import base
from tempest.common.utils.data_utils import rand_name
from tempest import exceptions
@@ -26,12 +28,17 @@
@classmethod
def setUpClass(cls):
super(AccountTest, cls).setUpClass()
- cls.container_name = rand_name(name='TestContainer')
- cls.container_client.create_container(cls.container_name)
+ cls.containers = []
+ for i in xrange(ord('a'), ord('f') + 1):
+ name = rand_name(name='%s-' % chr(i))
+ cls.container_client.create_container(name)
+ cls.containers.append(name)
+ cls.containers_count = len(cls.containers)
@classmethod
def tearDownClass(cls):
- cls.container_client.delete_container(cls.container_name)
+ cls.delete_containers(cls.containers)
+ super(AccountTest, cls).tearDownClass()
@attr(type='smoke')
def test_list_containers(self):
@@ -42,7 +49,59 @@
self.assertIsNotNone(container_list)
container_names = [c['name'] for c in container_list]
- self.assertIn(self.container_name, container_names)
+ for container_name in self.containers:
+ self.assertIn(container_name, container_names)
+
+ @attr(type='smoke')
+ def test_list_containers_with_limit(self):
+ # list containers one of them, half of them then all of them
+ for limit in (1, self.containers_count / 2, self.containers_count):
+ params = {'limit': limit}
+ resp, container_list = \
+ self.account_client.list_account_containers(params=params)
+ self.assertEquals(len(container_list), limit)
+
+ @attr(type='smoke')
+ def test_list_containers_with_marker(self):
+ # list containers using marker param
+ # first expect to get 0 container as we specified last
+ # the container as marker
+ # second expect to get the bottom half of the containers
+ params = {'marker': self.containers[-1]}
+ resp, container_list = \
+ self.account_client.list_account_containers(params=params)
+ self.assertEquals(len(container_list), 0)
+ params = {'marker': self.containers[self.containers_count / 2]}
+ resp, container_list = \
+ self.account_client.list_account_containers(params=params)
+ self.assertEquals(len(container_list), self.containers_count / 2 - 1)
+
+ @attr(type='smoke')
+ def test_list_containers_with_end_marker(self):
+ # list containers using end_marker param
+ # first expect to get 0 container as we specified first container as
+ # end_marker
+ # second expect to get the top half of the containers
+ params = {'end_marker': self.containers[0]}
+ resp, container_list = \
+ self.account_client.list_account_containers(params=params)
+ self.assertEquals(len(container_list), 0)
+ params = {'end_marker': self.containers[self.containers_count / 2]}
+ resp, container_list = \
+ self.account_client.list_account_containers(params=params)
+ self.assertEquals(len(container_list), self.containers_count / 2)
+
+ @attr(type='smoke')
+ def test_list_containers_with_limit_and_marker(self):
+ # list containers combining marker and limit param
+ # result are always limitated by the limit whatever the marker
+ for marker in random.choice(self.containers):
+ limit = random.randint(0, self.containers_count - 1)
+ params = {'marker': marker,
+ 'limit': limit}
+ resp, container_list = \
+ self.account_client.list_account_containers(params=params)
+ self.assertLessEqual(len(container_list), limit)
@attr(type='smoke')
def test_list_account_metadata(self):
diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py
new file mode 100644
index 0000000..1a31b91
--- /dev/null
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -0,0 +1,225 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack, LLC
+# 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.object_storage import base
+from tempest.common.utils.data_utils import rand_name
+from tempest import exceptions
+from tempest.test import attr
+from tempest.test import HTTP_SUCCESS
+
+
+class ObjectTestACLs(base.BaseObjectTest):
+ @classmethod
+ def setUpClass(cls):
+ super(ObjectTestACLs, cls).setUpClass()
+ cls.data.setup_test_user()
+ cls.new_token = cls.token_client.get_token(cls.data.test_user,
+ cls.data.test_password,
+ cls.data.test_tenant)
+ cls.custom_headers = {'X-Auth-Token': cls.new_token}
+
+ @classmethod
+ def tearDownClass(cls):
+ cls.data.teardown_all()
+ super(ObjectTestACLs, cls).tearDownClass()
+
+ def setUp(self):
+ super(ObjectTestACLs, self).setUp()
+ self.container_name = rand_name(name='TestContainer')
+ self.container_client.create_container(self.container_name)
+
+ def tearDown(self):
+ self.delete_containers([self.container_name])
+ super(ObjectTestACLs, self).tearDown()
+
+ @attr(type=['negative', 'gate'])
+ def test_write_object_without_using_creds(self):
+ # trying to create object with empty headers
+ # X-Auth-Token is not provided
+ object_name = rand_name(name='Object')
+ self.assertRaises(exceptions.Unauthorized,
+ self.custom_object_client.create_object,
+ self.container_name, object_name, 'data')
+
+ @attr(type=['negative', 'gate'])
+ def test_delete_object_without_using_creds(self):
+ # create object
+ object_name = rand_name(name='Object')
+ resp, _ = self.object_client.create_object(self.container_name,
+ object_name, 'data')
+ # trying to delete object with empty headers
+ # X-Auth-Token is not provided
+ self.assertRaises(exceptions.Unauthorized,
+ self.custom_object_client.delete_object,
+ self.container_name, object_name)
+
+ @attr(type=['negative', 'gate'])
+ def test_write_object_with_non_authorized_user(self):
+ # attempt to upload another file using non-authorized user
+ # User provided token is forbidden. ACL are not set
+ object_name = rand_name(name='Object')
+ # trying to create object with non-authorized user
+ self.assertRaises(exceptions.Unauthorized,
+ self.custom_object_client.create_object,
+ self.container_name, object_name, 'data',
+ metadata=self.custom_headers)
+
+ @attr(type=['negative', 'gate'])
+ def test_read_object_with_non_authorized_user(self):
+ # attempt to read object using non-authorized user
+ # User provided token is forbidden. ACL are not set
+ object_name = rand_name(name='Object')
+ resp, _ = self.object_client.create_object(
+ self.container_name, object_name, 'data')
+ self.assertEqual(resp['status'], '201')
+ # trying to get object with non authorized user token
+ self.assertRaises(exceptions.Unauthorized,
+ self.custom_object_client.get_object,
+ self.container_name, object_name,
+ metadata=self.custom_headers)
+
+ @attr(type=['negative', 'gate'])
+ def test_delete_object_with_non_authorized_user(self):
+ # attempt to delete object using non-authorized user
+ # User provided token is forbidden. ACL are not set
+ object_name = rand_name(name='Object')
+ resp, _ = self.object_client.create_object(
+ self.container_name, object_name, 'data')
+ self.assertEqual(resp['status'], '201')
+ # trying to delete object with non-authorized user token
+ self.assertRaises(exceptions.Unauthorized,
+ self.custom_object_client.delete_object,
+ self.container_name, object_name,
+ metadata=self.custom_headers)
+
+ @attr(type=['negative', 'smoke'])
+ def test_read_object_without_rights(self):
+ # attempt to read object using non-authorized user
+ # update X-Container-Read metadata ACL
+ cont_headers = {'X-Container-Read': 'badtenant:baduser'}
+ resp_meta, body = self.container_client.update_container_metadata(
+ self.container_name, metadata=cont_headers,
+ metadata_prefix='')
+ self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ # create object
+ object_name = rand_name(name='Object')
+ resp, _ = self.object_client.create_object(self.container_name,
+ object_name, 'data')
+ self.assertEqual(resp['status'], '201')
+ # Trying to read the object without rights
+ self.assertRaises(exceptions.Unauthorized,
+ self.custom_object_client.get_object,
+ self.container_name, object_name,
+ metadata=self.custom_headers)
+
+ @attr(type=['negative', 'smoke'])
+ def test_write_object_without_rights(self):
+ # attempt to write object using non-authorized user
+ # update X-Container-Write metadata ACL
+ cont_headers = {'X-Container-Write': 'badtenant:baduser'}
+ resp_meta, body = self.container_client.update_container_metadata(
+ self.container_name, metadata=cont_headers,
+ metadata_prefix='')
+ self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ # Trying to write the object without rights
+ object_name = rand_name(name='Object')
+ self.assertRaises(exceptions.Unauthorized,
+ self.custom_object_client.create_object,
+ self.container_name,
+ object_name, 'data',
+ metadata=self.custom_headers)
+
+ @attr(type='smoke')
+ def test_read_object_with_rights(self):
+ # attempt to read object using authorized user
+ # update X-Container-Read metadata ACL
+ cont_headers = {'X-Container-Read':
+ self.data.test_tenant + ':' + self.data.test_user}
+ resp_meta, body = self.container_client.update_container_metadata(
+ self.container_name, metadata=cont_headers,
+ metadata_prefix='')
+ self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ # create object
+ object_name = rand_name(name='Object')
+ resp, _ = self.object_client.create_object(self.container_name,
+ object_name, 'data')
+ self.assertEqual(resp['status'], '201')
+ # Trying to read the object with rights
+ resp, _ = self.custom_object_client.get_object(
+ self.container_name, object_name,
+ metadata=self.custom_headers)
+ self.assertIn(int(resp['status']), HTTP_SUCCESS)
+
+ @attr(type='smoke')
+ def test_write_object_with_rights(self):
+ # attempt to write object using authorized user
+ # update X-Container-Write metadata ACL
+ cont_headers = {'X-Container-Write':
+ self.data.test_tenant + ':' + self.data.test_user}
+ resp_meta, body = self.container_client.update_container_metadata(
+ self.container_name, metadata=cont_headers,
+ metadata_prefix='')
+ self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ # Trying to write the object with rights
+ object_name = rand_name(name='Object')
+ resp, _ = self.custom_object_client.create_object(
+ self.container_name,
+ object_name, 'data',
+ metadata=self.custom_headers)
+ self.assertIn(int(resp['status']), HTTP_SUCCESS)
+
+ @attr(type=['negative', 'smoke'])
+ def test_write_object_without_write_rights(self):
+ # attempt to write object using non-authorized user
+ # update X-Container-Read and X-Container-Write metadata ACL
+ cont_headers = {'X-Container-Read':
+ self.data.test_tenant + ':' + self.data.test_user,
+ 'X-Container-Write': ''}
+ resp_meta, body = self.container_client.update_container_metadata(
+ self.container_name, metadata=cont_headers,
+ metadata_prefix='')
+ self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ # Trying to write the object without write rights
+ object_name = rand_name(name='Object')
+ self.assertRaises(exceptions.Unauthorized,
+ self.custom_object_client.create_object,
+ self.container_name,
+ object_name, 'data',
+ metadata=self.custom_headers)
+
+ @attr(type=['negative', 'smoke'])
+ def test_delete_object_without_write_rights(self):
+ # attempt to delete object using non-authorized user
+ # update X-Container-Read and X-Container-Write metadata ACL
+ cont_headers = {'X-Container-Read':
+ self.data.test_tenant + ':' + self.data.test_user,
+ 'X-Container-Write': ''}
+ resp_meta, body = self.container_client.update_container_metadata(
+ self.container_name, metadata=cont_headers,
+ metadata_prefix='')
+ self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+ # create object
+ object_name = rand_name(name='Object')
+ resp, _ = self.object_client.create_object(self.container_name,
+ object_name, 'data')
+ self.assertEqual(resp['status'], '201')
+ # Trying to delete the object without write rights
+ self.assertRaises(exceptions.Unauthorized,
+ self.custom_object_client.delete_object,
+ self.container_name,
+ object_name,
+ metadata=self.custom_headers)
diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py
index aaa2c64..b546cec 100644
--- a/tempest/api/object_storage/test_object_expiry.py
+++ b/tempest/api/object_storage/test_object_expiry.py
@@ -45,7 +45,7 @@
@testtools.skip('Until Bug #1069849 is resolved.')
@attr(type='gate')
def test_get_object_after_expiry_time(self):
- #TODO(harika-vakadi): similar test case has to be created for
+ # TODO(harika-vakadi): similar test case has to be created for
# "X-Delete-At", after this test case works.
# create object
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 6136216..c8d9965 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -21,7 +21,6 @@
from tempest.api.object_storage import base
from tempest.common.utils.data_utils import arbitrary_string
from tempest.common.utils.data_utils import rand_name
-from tempest import exceptions
from tempest.test import attr
from tempest.test import HTTP_SUCCESS
@@ -230,74 +229,6 @@
self.fail("Got exception :%s ; while copying"
" object across containers" % e)
- @attr(type=['negative', 'gate'])
- def test_write_object_without_using_creds(self):
- # trying to create object with empty headers
- object_name = rand_name(name='Object')
- data = arbitrary_string(size=len(object_name),
- base_text=object_name)
- obj_headers = {'Content-Type': 'application/json',
- 'Accept': 'application/json'}
- self.assertRaises(exceptions.Unauthorized,
- self.custom_object_client.create_object,
- self.container_name, object_name, data,
- metadata=obj_headers)
-
- @attr(type=['negative', 'gate'])
- def test_delete_object_without_using_creds(self):
- # create object
- object_name = rand_name(name='Object')
- data = arbitrary_string(size=len(object_name),
- base_text=object_name)
- resp, _ = self.object_client.create_object(self.container_name,
- object_name, data)
- # trying to delete object with empty headers
- self.assertRaises(exceptions.Unauthorized,
- self.custom_object_client.delete_object,
- self.container_name, object_name)
-
- @attr(type=['negative', 'gate'])
- def test_write_object_with_non_authorized_user(self):
- # attempt to upload another file using non-authorized user
- object_name = rand_name(name='Object')
- data = arbitrary_string(size=len(object_name) * 5,
- base_text=object_name)
-
- # trying to create object with non-authorized user
- self.assertRaises(exceptions.Unauthorized,
- self.custom_object_client.create_object,
- self.container_name, object_name, data,
- metadata=self.custom_headers)
-
- @attr(type=['negative', 'gate'])
- def test_read_object_with_non_authorized_user(self):
- object_name = rand_name(name='Object')
- data = arbitrary_string(size=len(object_name) * 5,
- base_text=object_name)
- resp, body = self.object_client.create_object(
- self.container_name, object_name, data)
- self.assertEqual(resp['status'], '201')
-
- # trying to get object with non authorized user token
- self.assertRaises(exceptions.Unauthorized,
- self.custom_object_client.get_object,
- self.container_name, object_name,
- metadata=self.custom_headers)
-
- @attr(type=['negative', 'gate'])
- def test_delete_object_with_non_authorized_user(self):
- object_name = rand_name(name='Object')
- data = arbitrary_string(size=len(object_name) * 5,
- base_text=object_name)
- resp, body = self.object_client.create_object(
- self.container_name, object_name, data)
- self.assertEqual(resp['status'], '201')
- # trying to delete object with non-authorized user token
- self.assertRaises(exceptions.Unauthorized,
- self.custom_object_client.delete_object,
- self.container_name, object_name,
- metadata=self.custom_headers)
-
@attr(type='gate')
def test_get_object_using_temp_url(self):
# access object using temporary URL within expiration time
diff --git a/tempest/api/orchestration/stacks/test_instance_cfn_init.py b/tempest/api/orchestration/stacks/test_instance_cfn_init.py
index 7897b70..fe55ecf 100644
--- a/tempest/api/orchestration/stacks/test_instance_cfn_init.py
+++ b/tempest/api/orchestration/stacks/test_instance_cfn_init.py
@@ -145,7 +145,7 @@
'ImageId': cls.orchestration_cfg.image_ref
})
- @attr(type='gate')
+ @attr(type='slow')
@testtools.skipIf(existing_keypair, 'Server ssh tests are disabled.')
def test_can_log_into_created_server(self):
@@ -168,7 +168,7 @@
server, 'ec2-user', pkey=self.keypair['private_key'])
self.assertTrue(linux_client.can_authenticate())
- @attr(type='gate')
+ @attr(type='slow')
def test_stack_wait_condition_data(self):
sid = self.stack_identifier
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index 13d0d48..b64a324 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -88,12 +88,12 @@
@classmethod
def tearDownClass(cls):
- ## volumes deletion
+ # volumes deletion
for volume_id in cls.volume_id_list:
cls.volume_client.delete_volume(volume_id)
cls.volume_client.wait_for_resource_deletion(volume_id)
- ## volume types deletion
+ # volume types deletion
for volume_type_id in cls.volume_type_id_list:
cls.type_client.delete_volume_type(volume_type_id)
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index bb0047d..52ab5b7 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -18,6 +18,7 @@
import time
from tempest import clients
+from tempest.common import isolated_creds
from tempest.openstack.common import log as logging
import tempest.test
@@ -30,14 +31,14 @@
@classmethod
def setUpClass(cls):
- cls.isolated_creds = []
+ cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
if not cls.config.service_available.cinder:
skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
raise cls.skipException(skip_msg)
if cls.config.compute.allow_tenant_isolation:
- creds = cls._get_isolated_creds()
+ creds = cls.isolated_creds.get_primary_creds()
username, tenant_name, password = creds
os = clients.Manager(username=username,
password=password,
@@ -67,7 +68,8 @@
def tearDownClass(cls):
cls.clear_snapshots()
cls.clear_volumes()
- cls._clear_isolated_creds()
+ cls.isolated_creds.clear_isolated_creds()
+ super(BaseVolumeTest, cls).tearDownClass()
@classmethod
def create_snapshot(cls, volume_id=1, **kwargs):
@@ -80,7 +82,7 @@
'available')
return snapshot
- #NOTE(afazekas): these create_* and clean_* could be defined
+ # NOTE(afazekas): these create_* and clean_* could be defined
# only in a single location in the source, and could be more general.
@classmethod
@@ -149,7 +151,7 @@
"in configuration.")
raise cls.skipException(msg)
if cls.config.compute.allow_tenant_isolation:
- creds = cls._get_isolated_creds(admin=True)
+ creds = cls.isolated_creds.get_admin_creds()
admin_username, admin_tenant_name, admin_password = creds
cls.os_adm = clients.Manager(username=admin_username,
password=admin_password,
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index ee285db..39f61f3 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -34,7 +34,7 @@
volume = {}
v_name = rand_name('Volume')
metadata = {'Type': 'Test'}
- #Create a volume
+ # Create a volume
resp, volume = self.client.create_volume(size=1,
display_name=v_name,
metadata=metadata,
@@ -86,7 +86,7 @@
self.assertIn('id', volume)
self.assertIn('display_name', volume)
self.client.wait_for_volume_status(volume['id'], 'available')
- #GET Volume
+ # GET Volume
resp, fetched_volume = self.client.get_volume(volume['id'])
self.assertEqual(200, resp.status)
self.assertEqual(fetched_volume['metadata'], {})
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index eea37e0..e2b15a4 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -32,7 +32,7 @@
@attr(type='gate')
def test_volume_get_nonexistant_volume_id(self):
# Should not be able to get a nonexistant volume
- #Creating a nonexistant volume id
+ # Creating a nonexistant volume id
volume_id_list = []
resp, volumes = self.client.list_volumes()
for i in range(len(volumes)):
@@ -41,7 +41,7 @@
non_exist_id = rand_name('999')
if non_exist_id not in volume_id_list:
break
- #Trying to Get a non existant volume
+ # Trying to Get a non existant volume
self.assertRaises(exceptions.NotFound, self.client.get_volume,
non_exist_id)
diff --git a/tempest/cli/__init__.py b/tempest/cli/__init__.py
index 00e025d..f04d23f 100644
--- a/tempest/cli/__init__.py
+++ b/tempest/cli/__init__.py
@@ -35,6 +35,9 @@
cfg.StrOpt('cli_dir',
default='/usr/local/bin/',
help="directory where python client binaries are located"),
+ cfg.IntOpt('timeout',
+ default=15,
+ help="Number of seconds to wait on a CLI timeout"),
]
CONF = cfg.CONF
diff --git a/tempest/cli/simple_read_only/test_compute.py b/tempest/cli/simple_read_only/test_compute.py
index e60e238..4c7f604 100644
--- a/tempest/cli/simple_read_only/test_compute.py
+++ b/tempest/cli/simple_read_only/test_compute.py
@@ -176,7 +176,7 @@
self.nova('list', flags='--debug')
def test_admin_timeout(self):
- self.nova('list', flags='--timeout 2')
+ self.nova('list', flags='--timeout %d' % CONF.cli.timeout)
def test_admin_timing(self):
self.nova('list', flags='--timing')
diff --git a/tempest/cli/simple_read_only/test_keystone.py b/tempest/cli/simple_read_only/test_keystone.py
index 4002081..4c7982b 100644
--- a/tempest/cli/simple_read_only/test_keystone.py
+++ b/tempest/cli/simple_read_only/test_keystone.py
@@ -18,9 +18,13 @@
import re
import subprocess
+from oslo.config import cfg
+
import tempest.cli
from tempest.openstack.common import log as logging
+CONF = cfg.CONF
+
LOG = logging.getLogger(__name__)
@@ -117,4 +121,4 @@
self.keystone('catalog', flags='--debug')
def test_admin_timeout(self):
- self.keystone('catalog', flags='--timeout 15')
+ self.keystone('catalog', flags='--timeout %d' % CONF.cli.timeout)
diff --git a/tempest/cli/simple_read_only/test_neutron.py b/tempest/cli/simple_read_only/test_neutron.py
index 4860090..7b8340d 100644
--- a/tempest/cli/simple_read_only/test_neutron.py
+++ b/tempest/cli/simple_read_only/test_neutron.py
@@ -56,7 +56,8 @@
self.assertTableStruct(ext, ['alias', 'name'])
def test_neutron_dhcp_agent_list_hosting_net(self):
- self.neutron('dhcp-agent-list-hosting-net', params="private")
+ self.neutron('dhcp-agent-list-hosting-net',
+ params=CONF.compute.fixed_network_name)
def test_neutron_agent_list(self):
agents = self.parser.listing(self.neutron('agent-list'))
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
new file mode 100644
index 0000000..22e1bd2
--- /dev/null
+++ b/tempest/common/isolated_creds.py
@@ -0,0 +1,248 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corp.
+#
+# 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 keystoneclient.v2_0.client
+
+from tempest import clients
+from tempest.common.utils.data_utils import rand_name
+from tempest import config
+from tempest import exceptions
+from tempest.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+
+class IsolatedCreds(object):
+
+ def __init__(self, name, tempest_client=True, interface='json',
+ password='pass'):
+ self.isolated_creds = {}
+ self.name = name
+ self.config = config.TempestConfig()
+ self.tempest_client = tempest_client
+ self.interface = interface
+ self.password = password
+ self.admin_client = self._get_identity_admin_client()
+
+ def _get_keystone_client(self):
+ username = self.config.identity.admin_username
+ password = self.config.identity.admin_password
+ tenant_name = self.config.identity.admin_tenant_name
+ auth_url = self.config.identity.uri
+ dscv = self.config.identity.disable_ssl_certificate_validation
+ return keystoneclient.v2_0.client.Client(username=username,
+ password=password,
+ tenant_name=tenant_name,
+ auth_url=auth_url,
+ insecure=dscv)
+
+ def _get_identity_admin_client(self):
+ """
+ Returns an instance of the Identity Admin API client
+ """
+ if self.tempest_client:
+ os = clients.AdminManager(interface=self.interface)
+ admin_client = os.identity_client
+ else:
+ admin_client = self._get_keystone_client()
+ return admin_client
+
+ def _create_tenant(self, name, description):
+ if self.tempest_client:
+ resp, tenant = self.admin_client.create_tenant(
+ name=name, description=description)
+ else:
+ tenant = self.admin_client.tenants.create(name,
+ description=description)
+ return tenant
+
+ def _get_tenant_by_name(self, name):
+ if self.tempest_client:
+ resp, tenant = self.admin_client.get_tenant_by_name(name)
+ else:
+ tenants = self.admin_client.tenants.list()
+ for ten in tenants:
+ if ten['name'] == name:
+ tenant = ten
+ raise exceptions.NotFound('No such tenant')
+ return tenant
+
+ def _create_user(self, username, password, tenant, email):
+ if self.tempest_client:
+ resp, user = self.admin_client.create_user(username, password,
+ tenant['id'], email)
+ else:
+ user = self.admin_client.users.create(username, password, email,
+ tenant_id=tenant.id)
+ return user
+
+ def _get_user(self, tenant, username):
+ if self.tempest_client:
+ resp, user = self.admin_client.get_user_by_username(tenant['id'],
+ username)
+ else:
+ user = self.admin_client.users.get(username)
+ return user
+
+ def _list_roles(self):
+ if self.tempest_client:
+ resp, roles = self.admin_client.list_roles()
+ else:
+ roles = self.admin_client.roles.list()
+ return roles
+
+ def _assign_user_role(self, tenant, user, role):
+ if self.tempest_client:
+ self.admin_client.assign_user_role(tenant, user, role)
+ else:
+ self.admin_client.roles.add_user_role(user, role, tenant=tenant)
+
+ def _delete_user(self, user):
+ if self.tempest_client:
+ self.admin_client.delete_user(user)
+ else:
+ self.admin_client.users.delete(user)
+
+ def _delete_tenant(self, tenant):
+ if self.tempest_client:
+ self.admin_client.delete_tenant(tenant)
+ else:
+ self.admin_client.tenants.delete(tenant)
+
+ def _create_creds(self, suffix=None, admin=False):
+ rand_name_root = rand_name(self.name)
+ if suffix:
+ rand_name_root += suffix
+ tenant_name = rand_name_root + "-tenant"
+ tenant_desc = tenant_name + "-desc"
+ rand_name_root = rand_name(self.name)
+ tenant = self._create_tenant(name=tenant_name,
+ description=tenant_desc)
+ if suffix:
+ rand_name_root += suffix
+ username = rand_name_root + "-user"
+ email = rand_name_root + "@example.com"
+ user = self._create_user(username, self.password,
+ tenant, email)
+ if admin:
+ role = None
+ try:
+ roles = self._list_roles()
+ if self.tempest_client:
+ role = next(r for r in roles if r['name'] == 'admin')
+ else:
+ role = next(r for r in roles if r.name == 'admin')
+ except StopIteration:
+ msg = "No admin role found"
+ raise exceptions.NotFound(msg)
+ if self.tempest_client:
+ self._assign_user_role(tenant['id'], user['id'], role['id'])
+ else:
+ self._assign_user_role(tenant.id, user.id, role.id)
+ return user, tenant
+
+ def _get_cred_names(self, user, tenant):
+ if self.tempest_client:
+ username = user.get('name')
+ tenant_name = tenant.get('name')
+ else:
+ username = user.name
+ tenant_name = tenant.name
+ return username, tenant_name
+
+ def get_primary_tenant(self):
+ return self.isolated_creds.get('primary')[1]
+
+ def get_primary_user(self):
+ return self.isolated_creds.get('primary')[0]
+
+ def get_alt_tenant(self):
+ return self.isolated_creds.get('alt')[1]
+
+ def get_alt_user(self):
+ return self.isolated_creds.get('alt')[0]
+
+ def get_admin_tenant(self):
+ return self.isolated_creds.get('admin')[1]
+
+ def get_admin_user(self):
+ return self.isolated_creds.get('admin')[0]
+
+ def get_primary_creds(self):
+ if self.isolated_creds.get('primary'):
+ user, tenant = self.isolated_creds['primary']
+ username, tenant_name = self._get_cred_names(user, tenant)
+ else:
+ user, tenant = self._create_creds()
+ username, tenant_name = self._get_cred_names(user, tenant)
+ self.isolated_creds['primary'] = (user, tenant)
+ LOG.info("Aquired isolated creds:\n user: %s, tenant: %s"
+ % (username, tenant_name))
+ return username, tenant_name, self.password
+
+ def get_admin_creds(self):
+ if self.isolated_creds.get('admin'):
+ user, tenant = self.isolated_creds['admin']
+ username, tenant_name = self._get_cred_names(user, tenant)
+ else:
+ user, tenant = self._create_creds(admin=True)
+ username, tenant_name = self._get_cred_names(user, tenant)
+ self.isolated_creds['admin'] = (user, tenant)
+ LOG.info("Aquired admin isolated creds:\n user: %s, tenant: %s"
+ % (username, tenant_name))
+ return username, tenant_name, self.password
+
+ def get_alt_creds(self):
+ if self.isolated_creds.get('alt'):
+ user, tenant = self.isolated_creds['alt']
+ username, tenant_name = self._get_cred_names(user, tenant)
+ else:
+ user, tenant = self._create_creds()
+ username, tenant_name = self._get_cred_names(user, tenant)
+ self.isolated_creds['alt'] = (user, tenant)
+ LOG.info("Aquired alt isolated creds:\n user: %s, tenant: %s"
+ % (username, tenant_name))
+ return username, tenant_name, self.password
+
+ def clear_isolated_creds(self):
+ if not self.isolated_creds:
+ return
+ for cred in self.isolated_creds:
+ user, tenant = self.isolated_creds.get(cred)
+ try:
+ if self.tempest_client:
+ self._delete_user(user['id'])
+ else:
+ self._delete_user(user.id)
+ except exceptions.NotFound:
+ if self.tempest_client:
+ name = user['name']
+ else:
+ name = user.name
+ LOG.warn("user with name: %s not found for delete" % name)
+ pass
+ try:
+ if self.tempest_client:
+ self._delete_tenant(tenant['id'])
+ else:
+ self._delete_tenant(tenant.id)
+ except exceptions.NotFound:
+ if self.tempest_client:
+ name = tenant['name']
+ else:
+ name = tenant.name
+ LOG.warn("tenant with name: %s not found for delete" % name)
+ pass
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 09b87b2..759ab81 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -166,7 +166,8 @@
elif resp.status == 401:
raise exceptions.AuthenticationFailure(user=user,
- password=password)
+ password=password,
+ tenant=tenant_name)
raise exceptions.IdentityError('Unexpected status code {0}'.format(
resp.status))
diff --git a/tempest/common/ssh.py b/tempest/common/ssh.py
index 04cc851..be350c8 100644
--- a/tempest/common/ssh.py
+++ b/tempest/common/ssh.py
@@ -112,10 +112,10 @@
channel.shutdown_write()
out_data = []
err_data = []
-
- select_params = [channel], [], [], self.channel_timeout
+ poll = select.poll()
+ poll.register(channel, select.POLLIN)
while True:
- ready = select.select(*select_params)
+ ready = poll.poll(self.channel_timeout)
if not any(ready):
raise exceptions.TimeoutException(
"Command: '{0}' executed on host '{1}'.".format(
diff --git a/tempest/config.py b/tempest/config.py
index 19170ae..9b1a91e 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -366,6 +366,9 @@
default=5,
help="Number of seconds to wait while looping to check the"
"status of a container to container synchronization"),
+ cfg.BoolOpt('accounts_quotas_available',
+ default=True,
+ help="Set to True if the Account Quota middleware is enabled"),
]
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 448fbdf..62bd8cf 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -105,7 +105,7 @@
class AuthenticationFailure(RestClientException):
message = ("Authentication with user %(user)s and password "
- "%(password)s failed")
+ "%(password)s failed auth using tenant %(tenant)s.")
class EndpointNotFound(TempestException):
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index e785299..4447da0 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -29,6 +29,7 @@
from tempest.api.network import common as net_common
+from tempest.common import isolated_creds
from tempest.common import ssh
from tempest.common.utils.data_utils import rand_name
import tempest.manager
@@ -48,33 +49,24 @@
NOVACLIENT_VERSION = '2'
CINDERCLIENT_VERSION = '1'
- def __init__(self):
+ def __init__(self, username, password, tenant_name):
super(OfficialClientManager, self).__init__()
- self.compute_client = self._get_compute_client()
+ self.compute_client = self._get_compute_client(username,
+ password,
+ tenant_name)
+ self.identity_client = self._get_identity_client(username,
+ password,
+ tenant_name)
self.image_client = self._get_image_client()
- self.identity_client = self._get_identity_client()
self.network_client = self._get_network_client()
- self.volume_client = self._get_volume_client()
- self.client_attr_names = [
- 'compute_client',
- 'image_client',
- 'identity_client',
- 'network_client',
- 'volume_client'
- ]
+ self.volume_client = self._get_volume_client(username,
+ password,
+ tenant_name)
- def _get_compute_client(self, username=None, password=None,
- tenant_name=None):
+ def _get_compute_client(self, username, password, tenant_name):
# Novaclient will not execute operations for anyone but the
# identified user, so a new client needs to be created for
# each user that operations need to be performed for.
- if not username:
- username = self.config.identity.username
- if not password:
- password = self.config.identity.password
- if not tenant_name:
- tenant_name = self.config.identity.tenant_name
-
self._validate_credentials(username, password, tenant_name)
auth_url = self.config.identity.uri
@@ -91,23 +83,14 @@
insecure=dscv)
def _get_image_client(self):
- keystone = self._get_identity_client()
- token = keystone.auth_token
- endpoint = keystone.service_catalog.url_for(service_type='image',
- endpoint_type='publicURL')
+ token = self.identity_client.auth_token
+ endpoint = self.identity_client.service_catalog.url_for(
+ service_type='image', endpoint_type='publicURL')
dscv = self.config.identity.disable_ssl_certificate_validation
return glanceclient.Client('1', endpoint=endpoint, token=token,
insecure=dscv)
- def _get_volume_client(self, username=None, password=None,
- tenant_name=None):
- if not username:
- username = self.config.identity.username
- if not password:
- password = self.config.identity.password
- if not tenant_name:
- tenant_name = self.config.identity.tenant_name
-
+ def _get_volume_client(self, username, password, tenant_name):
auth_url = self.config.identity.uri
return cinderclient.client.Client(self.CINDERCLIENT_VERSION,
username,
@@ -115,17 +98,9 @@
tenant_name,
auth_url)
- def _get_identity_client(self, username=None, password=None,
- tenant_name=None):
+ def _get_identity_client(self, username, password, tenant_name):
# This identity client is not intended to check the security
# of the identity service, so use admin credentials by default.
- if not username:
- username = self.config.identity.admin_username
- if not password:
- password = self.config.identity.admin_password
- if not tenant_name:
- tenant_name = self.config.identity.admin_tenant_name
-
self._validate_credentials(username, password, tenant_name)
auth_url = self.config.identity.uri
@@ -160,7 +135,7 @@
insecure=dscv)
-class OfficialClientTest(tempest.test.TestCase):
+class OfficialClientTest(tempest.test.BaseTestCase):
"""
Official Client test base class for scenario testing.
@@ -173,7 +148,26 @@
* Use only the default client tool for calling an API
"""
- manager_class = OfficialClientManager
+ @classmethod
+ def setUpClass(cls):
+ cls.isolated_creds = isolated_creds.IsolatedCreds(
+ __name__, tempest_client=False)
+ if cls.config.compute.allow_tenant_isolation:
+ creds = cls.isolated_creds.get_primary_creds()
+ username, tenant_name, password = creds
+ else:
+ username = cls.config.identity.username
+ password = cls.config.identity.password
+ tenant_name = cls.config.identity.tenant_name
+
+ cls.manager = OfficialClientManager(username, password, tenant_name)
+ cls.compute_client = cls.manager.compute_client
+ cls.image_client = cls.manager.image_client
+ cls.identity_client = cls.manager.identity_client
+ cls.network_client = cls.manager.network_client
+ cls.volume_client = cls.manager.volume_client
+ cls.resource_keys = {}
+ cls.os_resources = []
@classmethod
def tearDownClass(cls):
@@ -214,6 +208,54 @@
# Block until resource deletion has completed or timed-out
tempest.test.call_until_true(is_deletion_complete, 10, 1)
+ cls.isolated_creds.clear_isolated_creds()
+ super(OfficialClientTest, cls).tearDownClass()
+
+ @classmethod
+ def set_resource(cls, key, thing):
+ LOG.debug("Adding %r to shared resources of %s" %
+ (thing, cls.__name__))
+ cls.resource_keys[key] = thing
+ cls.os_resources.append(thing)
+
+ @classmethod
+ def get_resource(cls, key):
+ return cls.resource_keys[key]
+
+ @classmethod
+ def remove_resource(cls, key):
+ thing = cls.resource_keys[key]
+ cls.os_resources.remove(thing)
+ del cls.resource_keys[key]
+
+ def status_timeout(self, things, thing_id, expected_status):
+ """
+ Given a thing and an expected status, do a loop, sleeping
+ for a configurable amount of time, checking for the
+ expected status to show. At any time, if the returned
+ status of the thing is ERROR, fail out.
+ """
+ def check_status():
+ # python-novaclient has resources available to its client
+ # that all implement a get() method taking an identifier
+ # for the singular resource to retrieve.
+ thing = things.get(thing_id)
+ new_status = thing.status
+ if new_status == 'ERROR':
+ self.fail("%s failed to get to expected status. "
+ "In ERROR state."
+ % thing)
+ elif new_status == expected_status:
+ return True # All good.
+ LOG.debug("Waiting for %s to get to %s status. "
+ "Currently in %s status",
+ thing, expected_status, new_status)
+ if not tempest.test.call_until_true(
+ check_status,
+ self.config.compute.build_timeout,
+ self.config.compute.build_interval):
+ self.fail("Timed out waiting for thing %s to become %s"
+ % (thing_id, expected_status))
class NetworkScenarioTest(OfficialClientTest):
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 390e004..5311eae 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -16,8 +16,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.api.network import common as net_common
from tempest.common.utils.data_utils import rand_name
+from tempest import config
from tempest.scenario import manager
from tempest.test import attr
@@ -88,6 +91,8 @@
"""
+ CONF = config.TempestConfig()
+
@classmethod
def check_preconditions(cls):
super(TestNetworkBasicOps, cls).check_preconditions()
@@ -242,6 +247,8 @@
self.floating_ips[server].append(floating_ip)
@attr(type='smoke')
+ @testtools.skipIf(CONF.service_available.neutron,
+ "Skipped unti bug #1210664 is resolved")
def test_008_check_public_network_connectivity(self):
if not self.floating_ips:
raise self.skipTest('No floating ips have been allocated.')
diff --git a/tempest/scenario/test_volume_snapshot_pattern.py b/tempest/scenario/test_volume_snapshot_pattern.py
new file mode 100644
index 0000000..4d8a400
--- /dev/null
+++ b/tempest/scenario/test_volume_snapshot_pattern.py
@@ -0,0 +1,122 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.openstack.common import log as logging
+
+from tempest.common.utils.data_utils import rand_name
+from tempest.scenario import manager
+
+LOG = logging.getLogger(__name__)
+
+
+class TestVolumeSnapshotPattern(manager.OfficialClientTest):
+
+ """
+ This test case attempts to reproduce the following steps:
+
+ * Create in Cinder some bootable volume importing a Glance image
+ * Boot an instance from the bootable volume
+ * Create a volume snapshot while the instance is running
+ * Boot an additional instance from the new snapshot based volume
+ """
+
+ def _create_volume_from_image(self):
+ img_uuid = self.config.compute.image_ref
+ vol_name = rand_name('volume-origin')
+ vol = self.volume_client.volumes.create(size=1,
+ display_name=vol_name,
+ imageRef=img_uuid)
+ self.set_resource(vol.id, vol)
+ self.status_timeout(self.volume_client.volumes,
+ vol.id,
+ 'available')
+ return vol
+
+ def _boot_instance_from_volume(self, vol_id):
+ # NOTE(gfidente): the img_uuid here is only needed because
+ # the novaclient requires it to be passed as arg
+ img_uuid = self.config.compute.image_ref
+ i_name = rand_name('instance')
+ flavor_id = self.config.compute.flavor_ref
+ # NOTE(gfidente): the syntax for block_device_mapping is
+ # dev_name=id:type:size:delete_on_terminate
+ # where type needs to be "snap" if the server is booted
+ # from a snapshot, size instead can be safely left empty
+ bd_map = {
+ 'vda': vol_id + ':::0'
+ }
+ create_kwargs = {
+ 'block_device_mapping': bd_map
+ }
+ i = self.compute_client.servers.create(name=i_name,
+ image=img_uuid,
+ flavor=flavor_id,
+ **create_kwargs)
+ self.set_resource(i.id, i)
+ self.status_timeout(self.compute_client.servers,
+ i.id,
+ 'ACTIVE')
+ return i
+
+ def _create_snapshot_from_volume(self, vol_id):
+ volume_snapshots = self.volume_client.volume_snapshots
+ snap_name = rand_name('snapshot')
+ snap = volume_snapshots.create(volume_id=vol_id,
+ force=True,
+ display_name=snap_name)
+ self.set_resource(snap.id, snap)
+ self.status_timeout(volume_snapshots,
+ snap.id,
+ 'available')
+ return snap
+
+ def _create_volume_from_snapshot(self, snap_id):
+ vol_name = rand_name('volume')
+ vol = self.volume_client.volumes.create(size=1,
+ display_name=vol_name,
+ snapshot_id=snap_id)
+ self.set_resource(vol.id, vol)
+ self.status_timeout(self.volume_client.volumes,
+ vol.id,
+ 'available')
+ return vol
+
+ def _stop_instances(self, instances):
+ # NOTE(gfidente): two loops so we do not wait for the status twice
+ for i in instances:
+ self.compute_client.servers.stop(i)
+ for i in instances:
+ self.status_timeout(self.compute_client.servers,
+ i.id,
+ 'SHUTOFF')
+
+ def _detach_volumes(self, volumes):
+ # NOTE(gfidente): two loops so we do not wait for the status twice
+ for v in volumes:
+ self.volume_client.volumes.detach(v)
+ for v in volumes:
+ self.status_timeout(self.volume_client.volumes,
+ v.id,
+ 'available')
+
+ def test_volume_snapshot_pattern(self):
+ volume_origin = self._create_volume_from_image()
+ i_origin = self._boot_instance_from_volume(volume_origin.id)
+ snapshot = self._create_snapshot_from_volume(volume_origin.id)
+ volume = self._create_volume_from_snapshot(snapshot.id)
+ i = self._boot_instance_from_volume(volume.id)
+ # NOTE(gfidente): ensure resources are in clean state for
+ # deletion operations to succeed
+ self._stop_instances([i_origin, i])
+ self._detach_volumes([volume_origin, volume])
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index 56a1a72..0a56e84 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -63,11 +63,12 @@
def update_user(self, user_id, name, **kwargs):
"""Updates a user."""
- email = kwargs.get('email', None)
- en = kwargs.get('enabled', True)
- project_id = kwargs.get('project_id', None)
- description = kwargs.get('description', None)
- domain_id = kwargs.get('domain_id', 'default')
+ resp, body = self.get_user(user_id)
+ email = kwargs.get('email', body['email'])
+ en = kwargs.get('enabled', body['enabled'])
+ project_id = kwargs.get('project_id', body['project_id'])
+ description = kwargs.get('description', body['description'])
+ domain_id = kwargs.get('domain_id', body['domain_id'])
post_body = {
'name': name,
'email': email,
@@ -149,6 +150,17 @@
body = json.loads(body)
return resp, body['role']
+ def update_role(self, name, role_id):
+ """Create a Role."""
+ post_body = {
+ 'name': name
+ }
+ post_body = json.dumps({'role': post_body})
+ resp, body = self.patch('roles/%s' % str(role_id), post_body,
+ self.headers)
+ body = json.loads(body)
+ return resp, body['role']
+
def delete_role(self, role_id):
"""Delete a role."""
resp, body = self.delete('roles/%s' % str(role_id))
@@ -222,6 +234,107 @@
resp, body = self.delete("auth/tokens", headers=headers)
return resp, body
+ def create_group(self, name, **kwargs):
+ """Creates a group."""
+ description = kwargs.get('description', None)
+ domain_id = kwargs.get('domain_id', 'default')
+ project_id = kwargs.get('project_id', None)
+ post_body = {
+ 'description': description,
+ 'domain_id': domain_id,
+ 'project_id': project_id,
+ 'name': name
+ }
+ post_body = json.dumps({'group': post_body})
+ resp, body = self.post('groups', post_body, self.headers)
+ body = json.loads(body)
+ return resp, body['group']
+
+ def delete_group(self, group_id):
+ """Delete a group."""
+ resp, body = self.delete('groups/%s' % str(group_id))
+ return resp, body
+
+ def assign_user_role_on_project(self, project_id, user_id, role_id):
+ """Add roles to a user on a project."""
+ resp, body = self.put('projects/%s/users/%s/roles/%s' %
+ (project_id, user_id, role_id), None,
+ self.headers)
+ return resp, body
+
+ def assign_user_role_on_domain(self, domain_id, user_id, role_id):
+ """Add roles to a user on a domain."""
+ resp, body = self.put('domains/%s/users/%s/roles/%s' %
+ (domain_id, user_id, role_id), None,
+ self.headers)
+ return resp, body
+
+ def list_user_roles_on_project(self, project_id, user_id):
+ """list roles of a user on a project."""
+ resp, body = self.get('projects/%s/users/%s/roles' %
+ (project_id, user_id))
+ body = json.loads(body)
+ return resp, body['roles']
+
+ def list_user_roles_on_domain(self, domain_id, user_id):
+ """list roles of a user on a domain."""
+ resp, body = self.get('domains/%s/users/%s/roles' %
+ (domain_id, user_id))
+ body = json.loads(body)
+ return resp, body['roles']
+
+ def revoke_role_from_user_on_project(self, project_id, user_id, role_id):
+ """Delete role of a user on a project."""
+ resp, body = self.delete('projects/%s/users/%s/roles/%s' %
+ (project_id, user_id, role_id))
+ return resp, body
+
+ def revoke_role_from_user_on_domain(self, domain_id, user_id, role_id):
+ """Delete role of a user on a domain."""
+ resp, body = self.delete('domains/%s/users/%s/roles/%s' %
+ (domain_id, user_id, role_id))
+ return resp, body
+
+ def assign_group_role_on_project(self, project_id, group_id, role_id):
+ """Add roles to a user on a project."""
+ resp, body = self.put('projects/%s/groups/%s/roles/%s' %
+ (project_id, group_id, role_id), None,
+ self.headers)
+ return resp, body
+
+ def assign_group_role_on_domain(self, domain_id, group_id, role_id):
+ """Add roles to a user on a domain."""
+ resp, body = self.put('domains/%s/groups/%s/roles/%s' %
+ (domain_id, group_id, role_id), None,
+ self.headers)
+ return resp, body
+
+ def list_group_roles_on_project(self, project_id, group_id):
+ """list roles of a user on a project."""
+ resp, body = self.get('projects/%s/groups/%s/roles' %
+ (project_id, group_id))
+ body = json.loads(body)
+ return resp, body['roles']
+
+ def list_group_roles_on_domain(self, domain_id, group_id):
+ """list roles of a user on a domain."""
+ resp, body = self.get('domains/%s/groups/%s/roles' %
+ (domain_id, group_id))
+ body = json.loads(body)
+ return resp, body['roles']
+
+ def revoke_role_from_group_on_project(self, project_id, group_id, role_id):
+ """Delete role of a user on a project."""
+ resp, body = self.delete('projects/%s/groups/%s/roles/%s' %
+ (project_id, group_id, role_id))
+ return resp, body
+
+ def revoke_role_from_group_on_domain(self, domain_id, group_id, role_id):
+ """Delete role of a user on a domain."""
+ resp, body = self.delete('domains/%s/groups/%s/roles/%s' %
+ (domain_id, group_id, role_id))
+ return resp, body
+
class V3TokenClientJSON(RestClient):
diff --git a/tempest/services/identity/v3/xml/identity_client.py b/tempest/services/identity/v3/xml/identity_client.py
index 571b491..03e06dc 100644
--- a/tempest/services/identity/v3/xml/identity_client.py
+++ b/tempest/services/identity/v3/xml/identity_client.py
@@ -52,6 +52,14 @@
array.append(xml_to_json(child))
return array
+ def _parse_roles(self, node):
+ array = []
+ for child in node.getchildren():
+ tag_list = child.tag.split('}', 1)
+ if tag_list[1] == "role":
+ array.append(xml_to_json(child))
+ return array
+
def _parse_array(self, node):
array = []
for child in node.getchildren():
@@ -95,11 +103,12 @@
def update_user(self, user_id, name, **kwargs):
"""Updates a user."""
- email = kwargs.get('email', None)
- en = kwargs.get('enabled', True)
- project_id = kwargs.get('project_id', None)
- domain_id = kwargs.get('domain_id', 'default')
- description = kwargs.get('description', None)
+ resp, body = self.get_user(user_id)
+ email = kwargs.get('email', body['email'])
+ en = kwargs.get('enabled', body['enabled'])
+ project_id = kwargs.get('project_id', body['project_id'])
+ description = kwargs.get('description', body['description'])
+ domain_id = kwargs.get('domain_id', body['domain_id'])
update_user = Element("user",
xmlns=XMLNS,
name=name,
@@ -182,6 +191,17 @@
body = self._parse_body(etree.fromstring(body))
return resp, body
+ def update_role(self, name, role_id):
+ """Updates a Role."""
+ post_body = Element("role",
+ xmlns=XMLNS,
+ name=name)
+ resp, body = self.patch('roles/%s' % str(role_id),
+ str(Document(post_body)),
+ self.headers)
+ body = self._parse_body(etree.fromstring(body))
+ return resp, body
+
def delete_role(self, role_id):
"""Delete a role."""
resp, body = self.delete('roles/%s' % str(role_id),
@@ -257,6 +277,107 @@
resp, body = self.delete("auth/tokens", headers=headers)
return resp, body
+ def create_group(self, name, **kwargs):
+ """Creates a group."""
+ description = kwargs.get('description', None)
+ domain_id = kwargs.get('domain_id', 'default')
+ project_id = kwargs.get('project_id', None)
+ post_body = Element("group",
+ xmlns=XMLNS,
+ name=name,
+ description=description,
+ domain_id=domain_id,
+ project_id=project_id)
+ resp, body = self.post('groups', str(Document(post_body)),
+ self.headers)
+ body = self._parse_body(etree.fromstring(body))
+ return resp, body
+
+ def delete_group(self, group_id):
+ """Delete a group."""
+ resp, body = self.delete('groups/%s' % group_id, self.headers)
+ return resp, body
+
+ def assign_user_role_on_project(self, project_id, user_id, role_id):
+ """Add roles to a user on a project."""
+ resp, body = self.put('projects/%s/users/%s/roles/%s' %
+ (project_id, user_id, role_id), '',
+ self.headers)
+ return resp, body
+
+ def assign_user_role_on_domain(self, domain_id, user_id, role_id):
+ """Add roles to a user on a domain."""
+ resp, body = self.put('domains/%s/users/%s/roles/%s' %
+ (domain_id, user_id, role_id), '',
+ self.headers)
+ return resp, body
+
+ def list_user_roles_on_project(self, project_id, user_id):
+ """list roles of a user on a project."""
+ resp, body = self.get('projects/%s/users/%s/roles' %
+ (project_id, user_id), self.headers)
+ body = self._parse_roles(etree.fromstring(body))
+ return resp, body
+
+ def list_user_roles_on_domain(self, domain_id, user_id):
+ """list roles of a user on a domain."""
+ resp, body = self.get('domains/%s/users/%s/roles' %
+ (domain_id, user_id), self.headers)
+ body = self._parse_roles(etree.fromstring(body))
+ return resp, body
+
+ def revoke_role_from_user_on_project(self, project_id, user_id, role_id):
+ """Delete role of a user on a project."""
+ resp, body = self.delete('projects/%s/users/%s/roles/%s' %
+ (project_id, user_id, role_id), self.headers)
+ return resp, body
+
+ def revoke_role_from_user_on_domain(self, domain_id, user_id, role_id):
+ """Delete role of a user on a domain."""
+ resp, body = self.delete('domains/%s/users/%s/roles/%s' %
+ (domain_id, user_id, role_id), self.headers)
+ return resp, body
+
+ def assign_group_role_on_project(self, project_id, group_id, role_id):
+ """Add roles to a user on a project."""
+ resp, body = self.put('projects/%s/groups/%s/roles/%s' %
+ (project_id, group_id, role_id), '',
+ self.headers)
+ return resp, body
+
+ def assign_group_role_on_domain(self, domain_id, group_id, role_id):
+ """Add roles to a user on a domain."""
+ resp, body = self.put('domains/%s/groups/%s/roles/%s' %
+ (domain_id, group_id, role_id), '',
+ self.headers)
+ return resp, body
+
+ def list_group_roles_on_project(self, project_id, group_id):
+ """list roles of a user on a project."""
+ resp, body = self.get('projects/%s/groups/%s/roles' %
+ (project_id, group_id), self.headers)
+ body = self._parse_roles(etree.fromstring(body))
+ return resp, body
+
+ def list_group_roles_on_domain(self, domain_id, group_id):
+ """list roles of a user on a domain."""
+ resp, body = self.get('domains/%s/groups/%s/roles' %
+ (domain_id, group_id), self.headers)
+ body = self._parse_roles(etree.fromstring(body))
+ return resp, body
+
+ def revoke_role_from_group_on_project(self, project_id, group_id, role_id):
+ """Delete role of a user on a project."""
+ resp, body = self.delete('projects/%s/groups/%s/roles/%s' %
+ (project_id, group_id, role_id), self.headers)
+ return resp, body
+
+ def revoke_role_from_group_on_domain(self, domain_id, group_id, role_id):
+ """Delete role of a user on a domain."""
+ resp, body = self.delete('domains/%s/groups/%s/roles/%s' %
+ (domain_id, group_id, role_id), self.headers)
+ return resp, body
+
class V3TokenClientXML(RestClientXML):
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 446a674..2c808a9 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -23,13 +23,11 @@
Tempest REST client for Neutron. Uses v2 of the Neutron API, since the
V1 API has been removed from the code base.
- Implements the following operations for each one of the basic Neutron
+ Implements create, delete, list and show for the basic Neutron
abstractions (networks, sub-networks and ports):
- create
- delete
- list
- show
+ It also implements list, show, update and reset for OpenStack Networking
+ quotas
"""
def __init__(self, config, username, password, auth_url, tenant_name=None):
@@ -128,3 +126,64 @@
resp, body = self.get(uri, self.headers)
body = json.loads(body)
return resp, body
+
+ def update_quotas(self, tenant_id, **kwargs):
+ put_body = {'quota': kwargs}
+ body = json.dumps(put_body)
+ uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
+ resp, body = self.put(uri, body, self.headers)
+ body = json.loads(body)
+ return resp, body['quota']
+
+ def show_quotas(self, tenant_id):
+ uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
+ resp, body = self.get(uri, self.headers)
+ body = json.loads(body)
+ return resp, body['quota']
+
+ def reset_quotas(self, tenant_id):
+ uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
+ resp, body = self.delete(uri, self.headers)
+ return resp, body
+
+ def list_quotas(self):
+ uri = '%s/quotas' % (self.uri_prefix)
+ resp, body = self.get(uri, self.headers)
+ body = json.loads(body)
+ return resp, body['quotas']
+
+ def update_subnet(self, subnet_id, new_name):
+ put_body = {
+ 'subnet': {
+ 'name': new_name,
+ }
+ }
+ body = json.dumps(put_body)
+ uri = '%s/subnets/%s' % (self.uri_prefix, subnet_id)
+ resp, body = self.put(uri, body=body, headers=self.headers)
+ body = json.loads(body)
+ return resp, body
+
+ def update_port(self, port_id, new_name):
+ put_body = {
+ 'port': {
+ 'name': new_name,
+ }
+ }
+ body = json.dumps(put_body)
+ uri = '%s/ports/%s' % (self.uri_prefix, port_id)
+ resp, body = self.put(uri, body=body, headers=self.headers)
+ body = json.loads(body)
+ return resp, body
+
+ def update_network(self, network_id, new_name):
+ put_body = {
+ "network": {
+ "name": new_name,
+ }
+ }
+ body = json.dumps(put_body)
+ uri = '%s/networks/%s' % (self.uri_prefix, network_id)
+ resp, body = self.put(uri, body=body, headers=self.headers)
+ body = json.loads(body)
+ return resp, body
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index aba4f8c..8defbbb 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -84,10 +84,13 @@
DEFAULT: Python-List returned in response body
"""
- url = '?format=%s' % self.format
if params:
- url += '&%s' + urllib.urlencode(params)
+ if 'format' not in params:
+ params['format'] = self.format
+ else:
+ params = {'format': self.format}
+ url = '?' + urllib.urlencode(params)
resp, body = self.get(url)
body = json.loads(body)
return resp, body
diff --git a/tempest/stress/README.rst b/tempest/stress/README.rst
index 661763c..7c180f6 100644
--- a/tempest/stress/README.rst
+++ b/tempest/stress/README.rst
@@ -23,14 +23,15 @@
target_controller = "hostname or ip of controller node (for nova-manage)
log_check_interval = "time between checking logs for errors (default 60s)"
-
+To activate logging on your console please make sure that you activate `use_stderr`
+in tempest.conf or use the default `logging.conf.sample` file.
Running the sample test
-----------------------
To test installation, do the following (from the tempest/stress directory):
- ./run_stress.py etc/sample-test.json -d 30
+ ./run_stress.py etc/server-create-destroy-test.json -d 30
This sample test tries to create a few VMs and kill a few VMs.
diff --git a/tempest/stress/actions/create_destroy_server.py b/tempest/stress/actions/server_create_destroy.py
similarity index 96%
rename from tempest/stress/actions/create_destroy_server.py
rename to tempest/stress/actions/server_create_destroy.py
index 68dc148..1a1e30b 100644
--- a/tempest/stress/actions/create_destroy_server.py
+++ b/tempest/stress/actions/server_create_destroy.py
@@ -16,7 +16,7 @@
import tempest.stress.stressaction as stressaction
-class CreateDestroyServerTest(stressaction.StressAction):
+class ServerCreateDestroyTest(stressaction.StressAction):
def setUp(self, **kwargs):
self.image = self.manager.config.compute.image_ref
diff --git a/tempest/stress/actions/volume_create_delete.py b/tempest/stress/actions/volume_create_delete.py
index 184f870..e29d9c4 100644
--- a/tempest/stress/actions/volume_create_delete.py
+++ b/tempest/stress/actions/volume_create_delete.py
@@ -14,20 +14,20 @@
import tempest.stress.stressaction as stressaction
-class CreateDeleteTest(stressaction.StressAction):
+class VolumeCreateDeleteTest(stressaction.StressAction):
def run(self):
name = rand_name("volume")
self.logger.info("creating %s" % name)
- resp, volume = self.manager.volumes_client.\
- create_volume(size=1, display_name=name)
+ volumes_client = self.manager.volumes_client
+ resp, volume = volumes_client.create_volume(size=1,
+ display_name=name)
assert(resp.status == 200)
vol_id = volume['id']
- status = 'available'
- self.manager.volumes_client.wait_for_volume_status(vol_id, status)
+ volumes_client.wait_for_volume_status(vol_id, 'available')
self.logger.info("created %s" % volume['id'])
self.logger.info("deleting %s" % name)
- resp, _ = self.manager.volumes_client.delete_volume(vol_id)
+ resp, _ = volumes_client.delete_volume(vol_id)
assert(resp.status == 202)
- self.manager.volumes_client.wait_for_resource_deletion(vol_id)
+ volumes_client.wait_for_resource_deletion(vol_id)
self.logger.info("deleted %s" % vol_id)
diff --git a/tempest/stress/cleanup.py b/tempest/stress/cleanup.py
index bfcf34f..1bd9485 100644
--- a/tempest/stress/cleanup.py
+++ b/tempest/stress/cleanup.py
@@ -17,13 +17,16 @@
# limitations under the License.
from tempest import clients
+from tempest.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
-def cleanup(logger):
+def cleanup():
admin_manager = clients.AdminManager()
_, body = admin_manager.servers_client.list_servers({"all_tenants": True})
- logger.debug("Cleanup::remove %s servers" % len(body['servers']))
+ LOG.info("Cleanup::remove %s servers" % len(body['servers']))
for s in body['servers']:
try:
admin_manager.servers_client.delete_server(s['id'])
@@ -37,7 +40,7 @@
pass
_, keypairs = admin_manager.keypairs_client.list_keypairs()
- logger.debug("Cleanup::remove %s keypairs" % len(keypairs))
+ LOG.info("Cleanup::remove %s keypairs" % len(keypairs))
for k in keypairs:
try:
admin_manager.keypairs_client.delete_keypair(k['name'])
@@ -45,7 +48,7 @@
pass
_, floating_ips = admin_manager.floating_ips_client.list_floating_ips()
- logger.debug("Cleanup::remove %s floating ips" % len(floating_ips))
+ LOG.info("Cleanup::remove %s floating ips" % len(floating_ips))
for f in floating_ips:
try:
admin_manager.floating_ips_client.delete_floating_ip(f['id'])
@@ -53,13 +56,13 @@
pass
_, users = admin_manager.identity_client.get_users()
- logger.debug("Cleanup::remove %s users" % len(users))
+ LOG.info("Cleanup::remove %s users" % len(users))
for user in users:
if user['name'].startswith("stress_user"):
admin_manager.identity_client.delete_user(user['id'])
_, tenants = admin_manager.identity_client.list_tenants()
- logger.debug("Cleanup::remove %s tenants" % len(tenants))
+ LOG.info("Cleanup::remove %s tenants" % len(tenants))
for tenant in tenants:
if tenant['name'].startswith("stress_tenant"):
admin_manager.identity_client.delete_tenant(tenant['id'])
@@ -69,7 +72,7 @@
_, snaps = admin_manager.snapshots_client.\
list_snapshots({"all_tenants": True})
- logger.debug("Cleanup::remove %s snapshots" % len(snaps))
+ LOG.info("Cleanup::remove %s snapshots" % len(snaps))
for v in snaps:
try:
admin_manager.snapshots_client.\
@@ -85,7 +88,7 @@
pass
_, vols = admin_manager.volumes_client.list_volumes({"all_tenants": True})
- logger.debug("Cleanup::remove %s volumes" % len(vols))
+ LOG.info("Cleanup::remove %s volumes" % len(vols))
for v in vols:
try:
admin_manager.volumes_client.\
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index c4c2041..efc57a9 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -12,8 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import logging
import multiprocessing
+import signal
import time
from tempest import clients
@@ -21,30 +21,13 @@
from tempest.common.utils.data_utils import rand_name
from tempest import exceptions
from tempest.openstack.common import importutils
+from tempest.openstack.common import log as logging
from tempest.stress import cleanup
admin_manager = clients.AdminManager()
-# setup logging to file
-logging.basicConfig(
- format='%(asctime)s %(process)d %(name)-20s %(levelname)-8s %(message)s',
- datefmt='%m-%d %H:%M:%S',
- filename="stress.debug.log",
- filemode="w",
- level=logging.DEBUG,
-)
-
-# define a Handler which writes INFO messages or higher to the sys.stdout
-_console = logging.StreamHandler()
-_console.setLevel(logging.INFO)
-# set a format which is simpler for console use
-format_str = '%(asctime)s %(process)d %(name)-20s: %(levelname)-8s %(message)s'
-_formatter = logging.Formatter(format_str)
-# tell the handler to use this format
-_console.setFormatter(_formatter)
-# add the handler to the root logger
-logger = logging.getLogger('tempest.stress')
-logger.addHandler(_console)
+LOG = logging.getLogger(__name__)
+processes = []
def do_ssh(command, host):
@@ -88,15 +71,34 @@
if not errors:
return None
if len(errors) > 0:
- logger.error('%s: %s' % (node, errors))
+ LOG.error('%s: %s' % (node, errors))
return errors
return None
-def stress_openstack(tests, duration, max_runs=None):
+def sigchld_handler(signal, frame):
+ """
+ Signal handler (only active if stop_on_error is True).
+ """
+ terminate_all_processes()
+
+
+def terminate_all_processes():
+ """
+ Goes through the process list and terminates all child processes.
+ """
+ for process in processes:
+ if process['process'].is_alive():
+ try:
+ process['process'].terminate()
+ except Exception:
+ pass
+ process['process'].join()
+
+
+def stress_openstack(tests, duration, max_runs=None, stop_on_error=False):
"""
Workload driver. Executes an action function against a nova-cluster.
-
"""
logfiles = admin_manager.config.stress.target_logfiles
log_check_interval = int(admin_manager.config.stress.log_check_interval)
@@ -105,7 +107,6 @@
computes = _get_compute_nodes(controller)
for node in computes:
do_ssh("rm -f %s" % logfiles, node)
- processes = []
for test in tests:
if test.get('use_admin', False):
manager = admin_manager
@@ -127,13 +128,13 @@
tenant_name=tenant_name)
test_obj = importutils.import_class(test['action'])
- test_run = test_obj(manager, logger, max_runs)
+ test_run = test_obj(manager, max_runs, stop_on_error)
kwargs = test.get('kwargs', {})
test_run.setUp(**dict(kwargs.iteritems()))
- logger.debug("calling Target Object %s" %
- test_run.__class__.__name__)
+ LOG.debug("calling Target Object %s" %
+ test_run.__class__.__name__)
mp_manager = multiprocessing.Manager()
shared_statistic = mp_manager.dict()
@@ -150,6 +151,9 @@
processes.append(process)
p.start()
+ if stop_on_error:
+ # NOTE(mkoderer): only the parent should register the handler
+ signal.signal(signal.SIGCHLD, sigchld_handler)
end_time = time.time() + duration
had_errors = False
while True:
@@ -168,6 +172,11 @@
break
time.sleep(min(remaining, log_check_interval))
+ if stop_on_error:
+ for process in processes:
+ if process['statistic']['fails'] > 0:
+ break
+
if not logfiles:
continue
errors = _error_in_logs(logfiles, computes)
@@ -175,32 +184,29 @@
had_errors = True
break
- for process in processes:
- if process['process'].is_alive():
- process['process'].terminate()
- process['process'].join()
+ terminate_all_processes()
sum_fails = 0
sum_runs = 0
- logger.info("Statistics (per process):")
+ LOG.info("Statistics (per process):")
for process in processes:
if process['statistic']['fails'] > 0:
had_errors = True
sum_runs += process['statistic']['runs']
sum_fails += process['statistic']['fails']
- logger.info(" Process %d (%s): Run %d actions (%d failed)" %
- (process['p_number'],
- process['action'],
- process['statistic']['runs'],
+ LOG.info(" Process %d (%s): Run %d actions (%d failed)" %
+ (process['p_number'],
+ process['action'],
+ process['statistic']['runs'],
process['statistic']['fails']))
- logger.info("Summary:")
- logger.info("Run %d actions (%d failed)" %
- (sum_runs, sum_fails))
+ LOG.info("Summary:")
+ LOG.info("Run %d actions (%d failed)" %
+ (sum_runs, sum_fails))
if not had_errors:
- logger.info("cleaning up")
- cleanup.cleanup(logger)
+ LOG.info("cleaning up")
+ cleanup.cleanup()
if had_errors:
return 1
else:
diff --git a/tempest/stress/etc/sample-test.json b/tempest/stress/etc/sample-test.json
deleted file mode 100644
index 494c823..0000000
--- a/tempest/stress/etc/sample-test.json
+++ /dev/null
@@ -1,7 +0,0 @@
-[{"action": "tempest.stress.actions.create_destroy_server.CreateDestroyServerTest",
- "threads": 8,
- "use_admin": false,
- "use_isolated_tenants": false,
- "kwargs": {}
- }
-]
diff --git a/tempest/stress/etc/server-create-destroy-test.json b/tempest/stress/etc/server-create-destroy-test.json
new file mode 100644
index 0000000..17d5e1a
--- /dev/null
+++ b/tempest/stress/etc/server-create-destroy-test.json
@@ -0,0 +1,7 @@
+[{"action": "tempest.stress.actions.server_create_destroy.ServerCreateDestroyTest",
+ "threads": 8,
+ "use_admin": false,
+ "use_isolated_tenants": false,
+ "kwargs": {}
+ }
+]
diff --git a/tempest/stress/etc/stress-tox-job.json b/tempest/stress/etc/stress-tox-job.json
index 3534c26..dffc469 100644
--- a/tempest/stress/etc/stress-tox-job.json
+++ b/tempest/stress/etc/stress-tox-job.json
@@ -1,10 +1,10 @@
-[{"action": "tempest.stress.actions.create_destroy_server.CreateDestroyServerTest",
+[{"action": "tempest.stress.actions.server_create_destroy.ServerCreateDestroyTest",
"threads": 8,
"use_admin": false,
"use_isolated_tenants": false,
"kwargs": {}
},
- {"action": "tempest.stress.actions.volume_create_delete.CreateDeleteTest",
+ {"action": "tempest.stress.actions.volume_create_delete.VolumeCreateDeleteTest",
"threads": 4,
"use_admin": false,
"use_isolated_tenants": false,
diff --git a/tempest/stress/etc/volume-assign-delete-test.json b/tempest/stress/etc/volume-attach-delete-test.json
similarity index 100%
rename from tempest/stress/etc/volume-assign-delete-test.json
rename to tempest/stress/etc/volume-attach-delete-test.json
diff --git a/tempest/stress/etc/volume-create-delete-test.json b/tempest/stress/etc/volume-create-delete-test.json
index 6325bdc..e8a58f7 100644
--- a/tempest/stress/etc/volume-create-delete-test.json
+++ b/tempest/stress/etc/volume-create-delete-test.json
@@ -1,4 +1,4 @@
-[{"action": "tempest.stress.actions.volume_create_delete.CreateDeleteTest",
+[{"action": "tempest.stress.actions.volume_create_delete.VolumeCreateDeleteTest",
"threads": 4,
"use_admin": false,
"use_isolated_tenants": false,
diff --git a/tempest/stress/run_stress.py b/tempest/stress/run_stress.py
index 106049d..32e3ae0 100755
--- a/tempest/stress/run_stress.py
+++ b/tempest/stress/run_stress.py
@@ -22,7 +22,7 @@
def main(ns):
- #NOTE(kodererm): moved import to make "-h" possible without OpenStack
+ # NOTE(mkoderer): moved import to make "-h" possible without OpenStack
from tempest.stress import driver
result = 0
tests = json.load(open(ns.tests, 'r'))
@@ -30,12 +30,13 @@
for test in tests:
step_result = driver.stress_openstack([test],
ns.duration,
- ns.number)
- #NOTE(kodererm): we just save the last result code
+ ns.number,
+ ns.stop)
+ # NOTE(mkoderer): we just save the last result code
if (step_result != 0):
result = step_result
else:
- driver.stress_openstack(tests, ns.duration, ns.number)
+ driver.stress_openstack(tests, ns.duration, ns.number, ns.stop)
return result
@@ -44,6 +45,8 @@
help="Duration of test in secs.")
parser.add_argument('-s', '--serial', action='store_true',
help="Trigger running tests serially.")
+parser.add_argument('-S', '--stop', action='store_true',
+ default=False, help="Stop on first error.")
parser.add_argument('-n', '--number', type=int,
help="How often an action is executed for each process.")
parser.add_argument('tests', help="Name of the file with test description.")
diff --git a/tempest/stress/stressaction.py b/tempest/stress/stressaction.py
index 77ddd1c..3719841 100644
--- a/tempest/stress/stressaction.py
+++ b/tempest/stress/stressaction.py
@@ -17,13 +17,17 @@
import signal
import sys
+from tempest.openstack.common import log as logging
+
class StressAction(object):
- def __init__(self, manager, logger, max_runs=None):
+ def __init__(self, manager, max_runs=None, stop_on_error=False):
+ full_cname = self.__module__ + "." + self.__class__.__name__
+ self.logger = logging.getLogger(full_cname)
self.manager = manager
- self.logger = logger
self.max_runs = max_runs
+ self.stop_on_error = stop_on_error
def _shutdown_handler(self, signal, frame):
self.tearDown()
@@ -63,6 +67,11 @@
self.logger.exception("Failure in run")
finally:
shared_statistic['runs'] += 1
+ if self.stop_on_error and (shared_statistic['fails'] > 1):
+ self.logger.warn("Stop process due to"
+ "\"stop-on-error\" argument")
+ self.tearDown()
+ sys.exit(1)
def run(self):
"""This method is where the stress test code runs."""
diff --git a/tempest/stress/tools/cleanup.py b/tempest/stress/tools/cleanup.py
index b6a26cd..3885ba0 100755
--- a/tempest/stress/tools/cleanup.py
+++ b/tempest/stress/tools/cleanup.py
@@ -14,15 +14,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import logging
-
from tempest.stress import cleanup
-_console = logging.StreamHandler()
-_console.setLevel(logging.DEBUG)
-# add the handler to the root logger
-logger = logging.getLogger('tempest.stress.cleanup')
-logger.addHandler(logging.StreamHandler())
-logger.setLevel(logging.DEBUG)
-
-cleanup.cleanup(logger)
+cleanup.cleanup()
diff --git a/tempest/test.py b/tempest/test.py
index 6c304c3..0cd0b08 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -24,9 +24,7 @@
import testtools
from tempest import clients
-from tempest.common.utils.data_utils import rand_name
from tempest import config
-from tempest import exceptions
from tempest.openstack.common import log as logging
LOG = logging.getLogger(__name__)
@@ -143,85 +141,6 @@
cls.config.identity.uri
)
- @classmethod
- def _get_isolated_creds(cls, admin=False):
- """
- Creates a new set of user/tenant/password credentials for a
- **regular** user of the Compute API so that a test case can
- operate in an isolated tenant container.
- """
- admin_client = cls._get_identity_admin_client()
- password = "pass"
-
- while True:
- try:
- rand_name_root = rand_name(cls.__name__)
- if cls.isolated_creds:
- # Main user already created. Create the alt or admin one...
- if admin:
- rand_name_root += '-admin'
- else:
- rand_name_root += '-alt'
- tenant_name = rand_name_root + "-tenant"
- tenant_desc = tenant_name + "-desc"
-
- resp, tenant = admin_client.create_tenant(
- name=tenant_name, description=tenant_desc)
- break
- except exceptions.Duplicate:
- if cls.config.compute.allow_tenant_reuse:
- tenant = admin_client.get_tenant_by_name(tenant_name)
- LOG.info('Re-using existing tenant %s', tenant)
- break
-
- while True:
- try:
- rand_name_root = rand_name(cls.__name__)
- if cls.isolated_creds:
- # Main user already created. Create the alt one...
- rand_name_root += '-alt'
- username = rand_name_root + "-user"
- email = rand_name_root + "@example.com"
- resp, user = admin_client.create_user(username,
- password,
- tenant['id'],
- email)
- break
- except exceptions.Duplicate:
- if cls.config.compute.allow_tenant_reuse:
- user = admin_client.get_user_by_username(tenant['id'],
- username)
- LOG.info('Re-using existing user %s', user)
- break
- # Store the complete creds (including UUID ids...) for later
- # but return just the username, tenant_name, password tuple
- # that the various clients will use.
- cls.isolated_creds.append((user, tenant))
-
- # Assign admin role if this is for admin creds
- if admin:
- _, roles = admin_client.list_roles()
- role = None
- try:
- _, roles = admin_client.list_roles()
- role = next(r for r in roles if r['name'] == 'admin')
- except StopIteration:
- msg = "No admin role found"
- raise exceptions.NotFound(msg)
- admin_client.assign_user_role(tenant['id'], user['id'], role['id'])
-
- return username, tenant_name, password
-
- @classmethod
- def _clear_isolated_creds(cls):
- if not cls.isolated_creds:
- return
- admin_client = cls._get_identity_admin_client()
-
- for user, tenant in cls.isolated_creds:
- admin_client.delete_user(user['id'])
- admin_client.delete_tenant(tenant['id'])
-
def call_until_true(func, duration, sleep_for):
"""
@@ -244,70 +163,3 @@
time.sleep(sleep_for)
now = time.time()
return False
-
-
-class TestCase(BaseTestCase):
- """Base test case class for all Tempest tests
-
- Contains basic setup and convenience methods
- """
-
- manager_class = None
-
- @classmethod
- def setUpClass(cls):
- cls.manager = cls.manager_class()
- for attr_name in cls.manager.client_attr_names:
- # Ensure that pre-existing class attributes won't be
- # accidentally overriden.
- assert not hasattr(cls, attr_name)
- client = getattr(cls.manager, attr_name)
- setattr(cls, attr_name, client)
- cls.resource_keys = {}
- cls.os_resources = []
-
- @classmethod
- def set_resource(cls, key, thing):
- LOG.debug("Adding %r to shared resources of %s" %
- (thing, cls.__name__))
- cls.resource_keys[key] = thing
- cls.os_resources.append(thing)
-
- @classmethod
- def get_resource(cls, key):
- return cls.resource_keys[key]
-
- @classmethod
- def remove_resource(cls, key):
- thing = cls.resource_keys[key]
- cls.os_resources.remove(thing)
- del cls.resource_keys[key]
-
- def status_timeout(self, things, thing_id, expected_status):
- """
- Given a thing and an expected status, do a loop, sleeping
- for a configurable amount of time, checking for the
- expected status to show. At any time, if the returned
- status of the thing is ERROR, fail out.
- """
- def check_status():
- # python-novaclient has resources available to its client
- # that all implement a get() method taking an identifier
- # for the singular resource to retrieve.
- thing = things.get(thing_id)
- new_status = thing.status
- if new_status == 'ERROR':
- self.fail("%s failed to get to expected status. "
- "In ERROR state."
- % thing)
- elif new_status == expected_status:
- return True # All good.
- LOG.debug("Waiting for %s to get to %s status. "
- "Currently in %s status",
- thing, expected_status, new_status)
- conf = config.TempestConfig()
- if not call_until_true(check_status,
- conf.compute.build_timeout,
- conf.compute.build_interval):
- self.fail("Timed out waiting for thing %s to become %s"
- % (thing_id, expected_status))
diff --git a/tempest/thirdparty/boto/test.py b/tempest/thirdparty/boto/test.py
index ba627e3..8812a10 100644
--- a/tempest/thirdparty/boto/test.py
+++ b/tempest/thirdparty/boto/test.py
@@ -170,7 +170,7 @@
add_cls = getattr(add_cls, part)
-#TODO(afazekas): classmethod handling
+# TODO(afazekas): classmethod handling
def friendly_function_name_simple(call_able):
name = ""
if hasattr(call_able, "im_class"):
@@ -224,7 +224,7 @@
"""Cancel Clean up request."""
del cls._resource_trash_bin[key]
- #TODO(afazekas): Add "with" context handling
+ # TODO(afazekas): Add "with" context handling
def assertBotoError(self, excMatcher, callableObj,
*args, **kwargs):
"""Example usage:
@@ -272,7 +272,7 @@
s3_error_code.server = ServerError()
s3_error_code.client = ClientError()
valid_image_state = set(('available', 'pending', 'failed'))
- #NOTE(afazekas): 'paused' is not valid status in EC2, but it does not have
+ # NOTE(afazekas): 'paused' is not valid status in EC2, but it does not have
# a good mapping, because it uses memory, but not really a running machine
valid_instance_state = set(('pending', 'running', 'shutting-down',
'terminated', 'stopping', 'stopped', 'paused'))
@@ -380,7 +380,7 @@
def assertAddressReleasedWait(self, address):
def _address_delete():
- #NOTE(afazekas): the filter gives back IP
+ # NOTE(afazekas): the filter gives back IP
# even if it is not associated to my tenant
if (address.public_ip not in map(lambda a: a.public_ip,
self.ec2_client.get_all_addresses())):
@@ -448,7 +448,7 @@
if cls.ec2_error_code.\
client.InvalidInstanceID.NotFound.match(exc):
return "_GONE"
- #NOTE(afazekas): incorrect code,
+ # NOTE(afazekas): incorrect code,
# but the resource must be destoreyd
if exc.error_code == "InstanceNotFound":
return "_GONE"
@@ -465,7 +465,7 @@
if exc_num:
raise exceptions.TearDownException(num=exc_num)
- #NOTE(afazekas): The incorrect ErrorCodes makes very, very difficult
+ # NOTE(afazekas): The incorrect ErrorCodes makes very, very difficult
# to write better teardown
@classmethod
@@ -473,7 +473,7 @@
"""Delete group.
Use just for teardown!
"""
- #NOTE(afazekas): should wait/try until all related instance terminates
+ # NOTE(afazekas): should wait/try until all related instance terminates
group.delete()
@classmethod
@@ -487,7 +487,7 @@
LOG.critical("%s Volume has %s snapshot(s)", volume.id,
map(snaps.id, snaps))
- #Note(afazekas): detaching/attching not valid EC2 status
+ # NOTE(afazekas): detaching/attching not valid EC2 status
def _volume_state():
volume.update(validate=True)
try:
@@ -495,7 +495,7 @@
volume.detach(force=True)
except BaseException as exc:
LOG.exception(exc)
- #exc_num += 1 "nonlocal" not in python2
+ # exc_num += 1 "nonlocal" not in python2
return volume.status
try:
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index df2ff6a..5007503 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -231,7 +231,7 @@
else:
self.assertNotEqual(instance.state, "running")
- #NOTE(afazekas): doctored test case,
+ # NOTE(afazekas): doctored test case,
# with normal validation it would fail
@testtools.skip("Until Bug #1182679 is fixed")
@attr(type='smoke')
@@ -277,10 +277,10 @@
self.assertTrue(address.associate(instance.id))
rcuk_da = self.addResourceCleanUp(address.disassociate)
- #TODO(afazekas): ping test. dependecy/permission ?
+ # TODO(afazekas): ping test. dependecy/permission ?
self.assertVolumeStatusWait(volume, "available")
- #NOTE(afazekas): it may be reports availble before it is available
+ # NOTE(afazekas): it may be reports availble before it is available
ssh = RemoteClient(address.public_ip,
self.os.config.compute.ssh_user,
@@ -304,7 +304,7 @@
self.assertVolumeStatusWait(_volume_state, "in-use")
re_search_wait(_volume_state, "in-use")
- #NOTE(afazekas): Different Hypervisor backends names
+ # NOTE(afazekas): Different Hypervisor backends names
# differently the devices,
# now we just test is the partition number increased/decrised
@@ -319,7 +319,7 @@
state_wait(_part_state, 'INCREASE')
part_lines = ssh.get_partitions().split('\n')
- #TODO(afazekas): Resource compare to the flavor settings
+ # TODO(afazekas): Resource compare to the flavor settings
volume.detach()
@@ -340,7 +340,7 @@
LOG.info("state: %s", instance.state)
if instance.state != "stopped":
self.assertInstanceStateWait(instance, "stopped")
- #TODO(afazekas): move steps from teardown to the test case
+ # TODO(afazekas): move steps from teardown to the test case
-#TODO(afazekas): Snapshot/volume read/write test case
+# TODO(afazekas): Snapshot/volume read/write test case
diff --git a/tempest/thirdparty/boto/test_ec2_keys.py b/tempest/thirdparty/boto/test_ec2_keys.py
index 1072356..1b4d7ec 100644
--- a/tempest/thirdparty/boto/test_ec2_keys.py
+++ b/tempest/thirdparty/boto/test_ec2_keys.py
@@ -37,7 +37,7 @@
cls.client = cls.os.ec2api_client
cls.ec = cls.ec2_error_code
-#TODO(afazekas): merge create, delete, get test cases
+# TODO(afazekas): merge create, delete, get test cases
@attr(type='smoke')
def test_create_ec2_keypair(self):
# EC2 create KeyPair
diff --git a/tempest/thirdparty/boto/test_ec2_network.py b/tempest/thirdparty/boto/test_ec2_network.py
index f4602d8..6226dbb 100644
--- a/tempest/thirdparty/boto/test_ec2_network.py
+++ b/tempest/thirdparty/boto/test_ec2_network.py
@@ -30,7 +30,7 @@
cls.os = clients.Manager()
cls.client = cls.os.ec2api_client
-#Note(afazekas): these tests for things duable without an instance
+# Note(afazekas): these tests for things duable without an instance
@testtools.skip("Skipped until the Bug #1080406 is resolved")
@attr(type='smoke')
def test_disassociate_not_associated_floating_ip(self):
diff --git a/tempest/thirdparty/boto/test_ec2_security_groups.py b/tempest/thirdparty/boto/test_ec2_security_groups.py
index 3db9a88..81ddcf6 100644
--- a/tempest/thirdparty/boto/test_ec2_security_groups.py
+++ b/tempest/thirdparty/boto/test_ec2_security_groups.py
@@ -43,7 +43,7 @@
group_get = groups_get[0]
self.assertEqual(group.name, group_get.name)
self.assertEqual(group.name, group_get.name)
- #ping (icmp_echo) and other icmp allowed from everywhere
+ # ping (icmp_echo) and other icmp allowed from everywhere
# from_port and to_port act as icmp type
success = self.client.authorize_security_group(group_name,
ip_protocol="icmp",
@@ -51,17 +51,17 @@
from_port=-1,
to_port=-1)
self.assertTrue(success)
- #allow standard ssh port from anywhere
+ # allow standard ssh port from anywhere
success = self.client.authorize_security_group(group_name,
ip_protocol="tcp",
cidr_ip="0.0.0.0/0",
from_port=22,
to_port=22)
self.assertTrue(success)
- #TODO(afazekas): Duplicate tests
+ # TODO(afazekas): Duplicate tests
group_get = self.client.get_all_security_groups(
groupnames=(group_name,))[0]
- #remove listed rules
+ # remove listed rules
for ip_permission in group_get.rules:
for cidr in ip_permission.grants:
self.assertTrue(self.client.revoke_security_group(group_name,
@@ -72,5 +72,5 @@
group_get = self.client.get_all_security_groups(
groupnames=(group_name,))[0]
- #all rules shuld be removed now
+ # all rules shuld be removed now
self.assertEqual(0, len(group_get.rules))
diff --git a/tempest/thirdparty/boto/test_s3_ec2_images.py b/tempest/thirdparty/boto/test_s3_ec2_images.py
index e2ca15f..26c2701 100644
--- a/tempest/thirdparty/boto/test_s3_ec2_images.py
+++ b/tempest/thirdparty/boto/test_s3_ec2_images.py
@@ -59,7 +59,7 @@
image["image_id"] = self.images_client.register_image(
name=image["name"],
image_location=image["location"])
- #Note(afazekas): delete_snapshot=True might trigger boto lib? bug
+ # NOTE(afazekas): delete_snapshot=True might trigger boto lib? bug
image["cleanUp"] = self.addResourceCleanUp(
self.images_client.deregister_image,
image["image_id"])
@@ -119,4 +119,4 @@
self.images_client.deregister_image(image["image_id"])
self.cancelResourceCleanUp(image["cleanUp"])
-#TODO(afazekas): less copy-paste style
+# TODO(afazekas): less copy-paste style
diff --git a/tempest/thirdparty/boto/utils/wait.py b/tempest/thirdparty/boto/utils/wait.py
index d8fca3b..1507deb 100644
--- a/tempest/thirdparty/boto/utils/wait.py
+++ b/tempest/thirdparty/boto/utils/wait.py
@@ -34,7 +34,7 @@
def state_wait(lfunction, final_set=set(), valid_set=None):
- #TODO(afazekas): evaluate using ABC here
+ # TODO(afazekas): evaluate using ABC here
if not isinstance(final_set, set):
final_set = set((final_set,))
if not isinstance(valid_set, set) and valid_set is not None:
@@ -112,7 +112,7 @@
time.sleep(default_check_interval)
-#NOTE(afazekas): EC2/boto normally raise exception instead of empty list
+# NOTE(afazekas): EC2/boto normally raise exception instead of empty list
def wait_exception(lfunction):
"""Returns with the exception or raises one."""
start_time = time.time()
@@ -129,4 +129,4 @@
dtime)
time.sleep(default_check_interval)
-#TODO(afazekas): consider strategy design pattern..
+# TODO(afazekas): consider strategy design pattern..
diff --git a/tempest/whitebox/test_servers_whitebox.py b/tempest/whitebox/test_servers_whitebox.py
index 2694b95..1c1cdeb 100644
--- a/tempest/whitebox/test_servers_whitebox.py
+++ b/tempest/whitebox/test_servers_whitebox.py
@@ -25,7 +25,6 @@
@classmethod
def setUpClass(cls):
- raise cls.skipException("Until Bug 1034129 is fixed")
super(ServersWhiteboxTest, cls).setUpClass()
#NOTE(afazekas): Strange relationship
BaseIdentityAdminTest.setUpClass()
@@ -80,7 +79,7 @@
stmt = instances.select().where(instances.c.uuid == server['id'])
result = self.connection.execute(stmt).first()
- self.assertEqual(1, result.deleted)
+ self.assertEqual(True, result.deleted > 0)
self.assertEqual('deleted', result.vm_state)
self.assertEqual(None, result.task_state)
except Exception:
diff --git a/tools/pretty_tox_serial.sh b/tools/pretty_tox_serial.sh
index 490d263..45f05bd 100755
--- a/tools/pretty_tox_serial.sh
+++ b/tools/pretty_tox_serial.sh
@@ -5,5 +5,7 @@
if [ ! -d .testrepository ]; then
testr init
fi
-testr run --subunit $TESTRARGS | subunit-2to1 | tools/colorizer.py
+testr run --subunit $TESTRARGS | subunit2pyunit
+retval=$?
testr slowest
+exit $retval
diff --git a/tox.ini b/tox.ini
index 7eae948..dc8980d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -11,57 +11,34 @@
sitepackages = True
setenv = VIRTUAL_ENV={envdir}
commands =
- python setup.py testr --slowest
-
+ python setup.py testr --slowest --testr-args='{posargs}'
[testenv:full]
sitepackages = True
setenv = VIRTUAL_ENV={envdir}
- NOSE_WITH_OPENSTACK=1
- NOSE_OPENSTACK_COLOR=1
- NOSE_OPENSTACK_RED=15
- NOSE_OPENSTACK_YELLOW=3
- NOSE_OPENSTACK_SHOW_ELAPSED=1
- NOSE_OPENSTACK_STDOUT=1
+# The regex below is used to select which tests to run and exclude the slow tag:
+# See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
- nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit --xunit-file=nosetests-full.xml -sv tempest/api tempest/scenario tempest/thirdparty tempest/cli
-
-[testenv:testr-serial]
-sitepackages = True
-setenv = VIRTUAL_ENV={envdir}
-commands =
- sh tools/pretty_tox_serial.sh '{posargs} tempest.api tempest.scenario tempest.thirdparty tempest.cli'
+ sh tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
[testenv:testr-full]
sitepackages = True
setenv = VIRTUAL_ENV={envdir}
commands =
- sh tools/pretty_tox.sh 'tempest.api tempest.scenario tempest.thirdparty tempest.cli {posargs}'
+ sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
[testenv:smoke]
sitepackages = True
setenv = VIRTUAL_ENV={envdir}
- NOSE_WITH_OPENSTACK=1
- NOSE_OPENSTACK_COLOR=1
- NOSE_OPENSTACK_RED=15
- NOSE_OPENSTACK_YELLOW=3
- NOSE_OPENSTACK_SHOW_ELAPSED=1
- NOSE_OPENSTACK_STDOUT=1
commands =
- nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit -sv --attr=type=smoke --xunit-file=nosetests-smoke.xml tempest
+ sh tools/pretty_tox_serial.sh 'smoke {posargs}'
[testenv:coverage]
sitepackages = True
setenv = VIRTUAL_ENV={envdir}
- NOSE_WITH_OPENSTACK=1
- NOSE_OPENSTACK_COLOR=1
- NOSE_OPENSTACK_RED=15
- NOSE_OPENSTACK_YELLOW=3
- NOSE_OPENSTACK_SHOW_ELAPSED=1
- NOSE_OPENSTACK_STDOUT=1
commands =
python -m tools/tempest_coverage -c start --combine
- nosetests --logging-format '%(asctime)-15s %(message)s' --with-xunit --xunit-file=nosetests-full.xml -sv tempest/api tempest/scenario tempest/thirdparty tempest/cli
+ sh tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli))'
python -m tools/tempest_coverage -c report --html {posargs}
[testenv:stress]