Merge "scenario test involving glance, cinder and nova functionalities"
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 3aa0497..f1aaa07 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -10,6 +10,8 @@
# 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
@@ -98,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
@@ -267,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
@@ -365,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/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 64f1854..14eced2 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -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/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index 697a839..5f8606e 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -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
@@ -191,6 +193,8 @@
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
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 66d8264..893d9e0 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -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_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/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_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_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/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/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/stress/README.rst b/tempest/stress/README.rst
index 31642b0..7c180f6 100644
--- a/tempest/stress/README.rst
+++ b/tempest/stress/README.rst
@@ -23,7 +23,8 @@
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
-----------------------
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 d9b95e0..efc57a9 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import logging
import multiprocessing
import signal
import time
@@ -22,30 +21,12 @@
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 = []
@@ -90,7 +71,7 @@
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
@@ -147,13 +128,13 @@
tenant_name=tenant_name)
test_obj = importutils.import_class(test['action'])
- test_run = test_obj(manager, logger, max_runs, stop_on_error)
+ 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()
@@ -208,24 +189,24 @@
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/stressaction.py b/tempest/stress/stressaction.py
index ab09adc..3719841 100644
--- a/tempest/stress/stressaction.py
+++ b/tempest/stress/stressaction.py
@@ -17,12 +17,15 @@
import signal
import sys
+from tempest.openstack.common import log as logging
+
class StressAction(object):
- def __init__(self, manager, logger, max_runs=None, stop_on_error=False):
+ 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
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/tools/pretty_tox_serial.sh b/tools/pretty_tox_serial.sh
index 490d263..dd7b682 100755
--- a/tools/pretty_tox_serial.sh
+++ b/tools/pretty_tox_serial.sh
@@ -5,5 +5,5 @@
if [ ! -d .testrepository ]; then
testr init
fi
-testr run --subunit $TESTRARGS | subunit-2to1 | tools/colorizer.py
+testr run --subunit $TESTRARGS | subunit2pyunit
testr slowest
diff --git a/tox.ini b/tox.ini
index c3562e6..53f85c1 100644
--- a/tox.ini
+++ b/tox.ini
@@ -13,22 +13,11 @@
commands =
python setup.py testr --slowest
-
[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
-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}
+# 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 =
sh tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
@@ -41,27 +30,15 @@
[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)) {posargs}'
python -m tools/tempest_coverage -c report --html {posargs}
[testenv:stress]