Merge "xenapi:live-block-migration - fix XML client test"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 9280c57..ac18490 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -35,9 +35,9 @@
# This should be the username of a user WITH administrative privileges
admin_username = admin
-# The above non-administrative user's password
+# The above administrative user's password
admin_password = secret
-# The above non-administrative user's tenant name
+# The above administrative user's tenant name
admin_tenant_name = admin
[compute]
diff --git a/run_tests.sh b/run_tests.sh
index 3f394e3..25b9729 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -33,7 +33,7 @@
config_file=""
update=0
-if ! options=$(getopt -o VNnfuswcphdsC: -l virtual-env,no-virtual-env,no-site-packages,force,update,smoke,whitebox,nova-coverage,pep8,help,debug,stdout,config: -- "$@")
+if ! options=$(getopt -o VNnfuswcphdSC: -l virtual-env,no-virtual-env,no-site-packages,force,update,smoke,whitebox,nova-coverage,pep8,help,debug,stdout,config: -- "$@")
then
# parse error
usage
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 955068f..1b965f3 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -106,3 +106,29 @@
"""Unsets extra Specs from the mentioned flavor."""
return self.delete('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
key))
+
+ def add_flavor_access(self, flavor_id, tenant_id):
+ """Add flavor access for the specified tenant."""
+ post_body = {
+ 'addTenantAccess': {
+ 'tenant': tenant_id
+ }
+ }
+ post_body = json.dumps(post_body)
+ resp, body = self.post('flavors/%s/action' % flavor_id,
+ post_body, self.headers)
+ body = json.loads(body)
+ return resp, body['flavor_access']
+
+ def remove_flavor_access(self, flavor_id, tenant_id):
+ """Remove flavor access from the specified tenant."""
+ post_body = {
+ 'removeTenantAccess': {
+ 'tenant': tenant_id
+ }
+ }
+ post_body = json.dumps(post_body)
+ resp, body = self.post('flavors/%s/action' % flavor_id,
+ post_body, self.headers)
+ body = json.loads(body)
+ return resp, body['flavor_access']
diff --git a/tempest/services/compute/xml/flavors_client.py b/tempest/services/compute/xml/flavors_client.py
index ece362b..a6451df 100644
--- a/tempest/services/compute/xml/flavors_client.py
+++ b/tempest/services/compute/xml/flavors_client.py
@@ -147,3 +147,28 @@
"""Unsets an extra spec based on the mentioned flavor and key."""
return self.delete('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
key))
+
+ def _parse_array_access(self, node):
+ return [xml_to_json(x) for x in node]
+
+ def add_flavor_access(self, flavor_id, tenant_id):
+ """Add flavor access for the specified tenant."""
+ doc = Document()
+ server = Element("addTenantAccess")
+ doc.append(server)
+ server.add_attr("tenant", tenant_id)
+ resp, body = self.post('flavors/%s/action' % str(flavor_id),
+ str(doc), self.headers)
+ body = self._parse_array_access(etree.fromstring(body))
+ return resp, body
+
+ def remove_flavor_access(self, flavor_id, tenant_id):
+ """Remove flavor access from the specified tenant."""
+ doc = Document()
+ server = Element("removeTenantAccess")
+ doc.append(server)
+ server.add_attr("tenant", tenant_id)
+ resp, body = self.post('flavors/%s/action' % str(flavor_id),
+ str(doc), self.headers)
+ body = self._parse_array_access(etree.fromstring(body))
+ return resp, body
diff --git a/tempest/tests/compute/admin/test_flavors_access.py b/tempest/tests/compute/admin/test_flavors_access.py
new file mode 100644
index 0000000..4cc3f57
--- /dev/null
+++ b/tempest/tests/compute/admin/test_flavors_access.py
@@ -0,0 +1,128 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 NEC Corporation.
+# 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.common.utils.data_utils import rand_int_id
+from tempest.common.utils.data_utils import rand_name
+from tempest import exceptions
+from tempest.test import attr
+from tempest.tests import compute
+from tempest.tests.compute import base
+
+
+class FlavorsAccessTestJSON(base.BaseComputeAdminTest):
+
+ """
+ Tests Flavor Access API extension.
+ Add and remove Flavor Access require admin privileges.
+ """
+
+ _interface = 'json'
+
+ @classmethod
+ def setUpClass(cls):
+ super(FlavorsAccessTestJSON, cls).setUpClass()
+ if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+ msg = "FlavorExtraData extension not enabled."
+ raise cls.skipException(msg)
+
+ cls.client = cls.os_adm.flavors_client
+ admin_client = cls._get_identity_admin_client()
+ resp, tenants = admin_client.list_tenants()
+ cls.tenant_id = [tnt['id'] for tnt in tenants if tnt['name'] ==
+ cls.flavors_client.tenant_name][0]
+
+ cls.flavor_name_prefix = 'test_flavor_access_'
+ cls.ram = 512
+ cls.vcpus = 1
+ cls.disk = 10
+
+ @attr('positive')
+ def test_flavor_access_add_remove(self):
+ #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,
+ self.ram, self.vcpus,
+ self.disk,
+ new_flavor_id,
+ is_public='False')
+ self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+ #Add flavor access to a tenant.
+ resp_body = {
+ "tenant_id": str(self.tenant_id),
+ "flavor_id": str(new_flavor['id']),
+ }
+ add_resp, add_body = \
+ self.client.add_flavor_access(new_flavor['id'], self.tenant_id)
+ self.assertEqual(add_resp.status, 200)
+ self.assertIn(resp_body, add_body)
+
+ #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_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.
+ 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('negative')
+ def test_flavor_non_admin_add(self):
+ #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,
+ self.ram, self.vcpus,
+ self.disk,
+ new_flavor_id,
+ is_public='False')
+ self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+ self.assertRaises(exceptions.Unauthorized,
+ self.flavors_client.add_flavor_access,
+ new_flavor['id'],
+ self.tenant_id)
+
+ @attr('negative')
+ def test_flavor_non_admin_remove(self):
+ #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,
+ self.ram, self.vcpus,
+ self.disk,
+ new_flavor_id,
+ is_public='False')
+ self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+ #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)
+ self.assertRaises(exceptions.Unauthorized,
+ self.flavors_client.remove_flavor_access,
+ new_flavor['id'],
+ self.tenant_id)
+
+
+class FlavorsAdminTestXML(FlavorsAccessTestJSON):
+ _interface = 'xml'
diff --git a/tempest/tests/compute/images/test_list_images.py b/tempest/tests/compute/images/test_list_images.py
index ec9e7bc..07c48fe 100644
--- a/tempest/tests/compute/images/test_list_images.py
+++ b/tempest/tests/compute/images/test_list_images.py
@@ -27,10 +27,6 @@
super(ListImagesTestJSON, cls).setUpClass()
cls.client = cls.images_client
- @classmethod
- def tearDownClass(cls):
- super(ListImagesTestJSON, cls).tearDownClass()
-
@attr(type='smoke')
def test_get_image(self):
# Returns the correct details for a single image
diff --git a/tempest/tests/volume/admin/test_volume_types.py b/tempest/tests/volume/admin/test_volume_types.py
index 6eb3629..38ac74a 100644
--- a/tempest/tests/volume/admin/test_volume_types.py
+++ b/tempest/tests/volume/admin/test_volume_types.py
@@ -37,10 +37,6 @@
auth_url,
adm_tenant)
- @classmethod
- def tearDownClass(cls):
- super(VolumeTypesTest, cls).tearDownClass()
-
def test_volume_type_list(self):
# List Volume types.
try: