Merge "Add a test case for metadata POST"
diff --git a/releasenotes/notes/add-image-clients-tests-49dbc0a0a4281a77.yaml b/releasenotes/notes/add-image-clients-tests-49dbc0a0a4281a77.yaml
index 9d1a003..eaab1f0 100644
--- a/releasenotes/notes/add-image-clients-tests-49dbc0a0a4281a77.yaml
+++ b/releasenotes/notes/add-image-clients-tests-49dbc0a0a4281a77.yaml
@@ -6,4 +6,5 @@
there are some apis are not included, add them.
* namespace_objects_client(v2)
+ * namespace_tags_client(v2)
diff --git a/tempest/api/compute/admin/test_keypairs_v210.py b/tempest/api/compute/admin/test_keypairs_v210.py
index dfa7c39..9011433 100644
--- a/tempest/api/compute/admin/test_keypairs_v210.py
+++ b/tempest/api/compute/admin/test_keypairs_v210.py
@@ -32,9 +32,9 @@
key_list = list()
for i in range(2):
k_name = data_utils.rand_name('keypair')
- keypair = self._create_keypair(k_name,
- keypair_type='ssh',
- user_id=user_id)
+ keypair = self.create_keypair(k_name,
+ keypair_type='ssh',
+ user_id=user_id)
self.assertEqual(k_name, keypair['name'],
"The created keypair name is not equal "
"to the requested name!")
@@ -56,8 +56,7 @@
self.assertEqual(user_id, keypair_detail['user_id'],
"The fetched keypair is not for requested user!")
# Create a admin keypair
- admin_k_name = data_utils.rand_name('keypair')
- admin_keypair = self._create_keypair(admin_k_name, keypair_type='ssh')
+ admin_keypair = self.create_keypair(keypair_type='ssh')
admin_keypair.pop('private_key', None)
admin_keypair.pop('user_id')
diff --git a/tempest/api/compute/admin/test_networks.py b/tempest/api/compute/admin/test_networks.py
index 8504840..d8f688d 100644
--- a/tempest/api/compute/admin/test_networks.py
+++ b/tempest/api/compute/admin/test_networks.py
@@ -61,5 +61,5 @@
configured_network = CONF.compute.fixed_network_name
self.assertIn(configured_network, [x['label'] for x in networks])
else:
- network_name = map(lambda x: x['label'], networks)
- self.assertGreaterEqual(len(network_name), 1)
+ network_labels = [x['label'] for x in networks]
+ self.assertGreaterEqual(len(network_labels), 1)
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index a8a8b83..0f19850 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -101,7 +101,7 @@
params = {'tenant_id': tenant_id}
body = self.client.list_servers(detail=True, **params)
servers = body['servers']
- servers_name = map(lambda x: x['name'], servers)
+ servers_name = [x['name'] for x in servers]
self.assertNotIn(self.s1_name, servers_name)
self.assertNotIn(self.s2_name, servers_name)
@@ -109,7 +109,7 @@
params = {'all_tenants': '', 'tenant_id': tenant_id}
body = self.client.list_servers(detail=True, **params)
servers = body['servers']
- servers_name = map(lambda x: x['name'], servers)
+ servers_name = [x['name'] for x in servers]
self.assertIn(self.s1_name, servers_name)
self.assertIn(self.s2_name, servers_name)
@@ -118,7 +118,7 @@
params = {'all_tenants': '', 'tenant_id': admin_tenant_id}
body = self.client.list_servers(detail=True, **params)
servers = body['servers']
- servers_name = map(lambda x: x['name'], servers)
+ servers_name = [x['name'] for x in servers]
self.assertNotIn(self.s1_name, servers_name)
self.assertNotIn(self.s2_name, servers_name)
diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py
index 3923068..6c97072 100644
--- a/tempest/api/compute/images/test_images_negative.py
+++ b/tempest/api/compute/images/test_images_negative.py
@@ -62,7 +62,7 @@
# Create a new image with invalid server id
meta = {'image_type': 'test'}
self.assertRaises(lib_exc.NotFound, self.create_image_from_server,
- '!@$^&*()', meta=meta)
+ data_utils.rand_name('invalid'), meta=meta)
@test.attr(type=['negative'])
@test.idempotent_id('ec176029-73dc-4037-8d72-2e4ff60cf538')
@@ -87,7 +87,7 @@
def test_delete_image_with_invalid_image_id(self):
# An image should not be deleted with invalid image id
self.assertRaises(lib_exc.NotFound, self.client.delete_image,
- '!@$^&*()')
+ data_utils.rand_name('invalid'))
@test.attr(type=['negative'])
@test.idempotent_id('137aef61-39f7-44a1-8ddf-0adf82511701')
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 0b4a2a8..7768596 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -89,7 +89,7 @@
# We use a string with 3 byte utf-8 character due to bug
# #1370954 in glance which will 500 if mysql is used as the
# backend and it attempts to store a 4 byte utf-8 character
- utf8_name = data_utils.rand_name('\xe2\x82\xa1')
+ utf8_name = data_utils.rand_name(b'\xe2\x82\xa1'.decode('utf-8'))
body = self.client.create_image(server_id, name=utf8_name)
image_id = data_utils.parse_image_id(body.response['location'])
self.addCleanup(self.client.delete_image, image_id)
diff --git a/tempest/api/compute/keypairs/base.py b/tempest/api/compute/keypairs/base.py
index ad7f958..21f504b 100644
--- a/tempest/api/compute/keypairs/base.py
+++ b/tempest/api/compute/keypairs/base.py
@@ -14,6 +14,7 @@
# under the License.
from tempest.api.compute import base
+from tempest.common.utils import data_utils
class BaseKeypairTest(base.BaseV2ComputeTest):
@@ -27,9 +28,12 @@
def _delete_keypair(self, keypair_name, **params):
self.client.delete_keypair(keypair_name, **params)
- def _create_keypair(self, keypair_name,
- pub_key=None, keypair_type=None,
- user_id=None):
+ def create_keypair(self, keypair_name=None,
+ pub_key=None, keypair_type=None,
+ user_id=None):
+ if keypair_name is None:
+ keypair_name = data_utils.rand_name(
+ self.__class__.__name__ + '-keypair')
kwargs = {'name': keypair_name}
delete_params = {}
if pub_key:
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index 562a508..8acc25a 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -27,8 +27,7 @@
# Create 3 keypairs
key_list = list()
for i in range(3):
- k_name = data_utils.rand_name('keypair')
- keypair = self._create_keypair(k_name)
+ keypair = self.create_keypair()
# 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')
@@ -51,7 +50,7 @@
def test_keypair_create_delete(self):
# Keypair should be created, verified and deleted
k_name = data_utils.rand_name('keypair')
- keypair = self._create_keypair(k_name)
+ keypair = self.create_keypair(k_name)
private_key = keypair['private_key']
key_name = keypair['name']
self.assertEqual(key_name, k_name,
@@ -64,7 +63,7 @@
def test_get_keypair_detail(self):
# Keypair should be created, Got details by name and deleted
k_name = data_utils.rand_name('keypair')
- self._create_keypair(k_name)
+ self.create_keypair(k_name)
keypair_detail = self.client.show_keypair(k_name)['keypair']
self.assertIn('name', keypair_detail)
self.assertIn('public_key', keypair_detail)
@@ -88,7 +87,7 @@
"LOeB1kYMOBaiUPLQTWXR3JpckqFIQwhIH0zoHlJvZE8hh90"
"XcPojYN56tI0OlrGqojbediJYD0rUsJu4weZpbn8vilb3JuDY+jws"
"snSA8wzBx3A/8y9Pp1B nova@ubuntu")
- keypair = self._create_keypair(k_name, pub_key)
+ keypair = self.create_keypair(k_name, pub_key)
self.assertNotIn('private_key', keypair,
"Field private_key is not empty!")
key_name = keypair['name']
diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py
index 2a6139b..f5ffa19 100644
--- a/tempest/api/compute/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/keypairs/test_keypairs_negative.py
@@ -25,10 +25,9 @@
@test.idempotent_id('29cca892-46ae-4d48-bc32-8fe7e731eb81')
def test_keypair_create_with_invalid_pub_key(self):
# Keypair should not be created with a non RSA public key
- k_name = data_utils.rand_name('keypair')
pub_key = "ssh-rsa JUNK nova@ubuntu"
self.assertRaises(lib_exc.BadRequest,
- self._create_keypair, k_name, pub_key)
+ self.create_keypair, pub_key=pub_key)
@test.attr(type=['negative'])
@test.idempotent_id('7cc32e47-4c42-489d-9623-c5e2cb5a2fa5')
@@ -42,19 +41,17 @@
@test.idempotent_id('dade320e-69ca-42a9-ba4a-345300f127e0')
def test_create_keypair_with_empty_public_key(self):
# Keypair should not be created with an empty public key
- k_name = data_utils.rand_name("keypair")
pub_key = ' '
- self.assertRaises(lib_exc.BadRequest, self._create_keypair,
- k_name, pub_key)
+ self.assertRaises(lib_exc.BadRequest, self.create_keypair,
+ pub_key=pub_key)
@test.attr(type=['negative'])
@test.idempotent_id('fc100c19-2926-4b9c-8fdc-d0589ee2f9ff')
def test_create_keypair_when_public_key_bits_exceeds_maximum(self):
# Keypair should not be created when public key bits are too long
- k_name = data_utils.rand_name("keypair")
pub_key = 'ssh-rsa ' + 'A' * 2048 + ' openstack@ubuntu'
- self.assertRaises(lib_exc.BadRequest, self._create_keypair,
- k_name, pub_key)
+ self.assertRaises(lib_exc.BadRequest, self.create_keypair,
+ pub_key=pub_key)
@test.attr(type=['negative'])
@test.idempotent_id('0359a7f1-f002-4682-8073-0c91e4011b7c')
@@ -63,7 +60,7 @@
k_name = data_utils.rand_name('keypair')
self.client.create_keypair(name=k_name)
# Now try the same keyname to create another key
- self.assertRaises(lib_exc.Conflict, self._create_keypair,
+ self.assertRaises(lib_exc.Conflict, self.create_keypair,
k_name)
self.client.delete_keypair(k_name)
@@ -71,7 +68,7 @@
@test.idempotent_id('1398abe1-4a84-45fb-9294-89f514daff00')
def test_create_keypair_with_empty_name_string(self):
# Keypairs with name being an empty string should not be created
- self.assertRaises(lib_exc.BadRequest, self._create_keypair,
+ self.assertRaises(lib_exc.BadRequest, self.create_keypair,
'')
@test.attr(type=['negative'])
@@ -79,7 +76,7 @@
def test_create_keypair_with_long_keynames(self):
# Keypairs with name longer than 255 chars should not be created
k_name = 'keypair-'.ljust(260, '0')
- self.assertRaises(lib_exc.BadRequest, self._create_keypair,
+ self.assertRaises(lib_exc.BadRequest, self.create_keypair,
k_name)
@test.attr(type=['negative'])
@@ -87,5 +84,5 @@
def test_create_keypair_invalid_name(self):
# Keypairs with name being an invalid name should not be created
k_name = 'key_/.\@:'
- self.assertRaises(lib_exc.BadRequest, self._create_keypair,
+ self.assertRaises(lib_exc.BadRequest, self.create_keypair,
k_name)
diff --git a/tempest/api/compute/keypairs/test_keypairs_v22.py b/tempest/api/compute/keypairs/test_keypairs_v22.py
index 997ef9b..4bd1a40 100644
--- a/tempest/api/compute/keypairs/test_keypairs_v22.py
+++ b/tempest/api/compute/keypairs/test_keypairs_v22.py
@@ -28,7 +28,7 @@
def _test_keypairs_create_list_show(self, keypair_type=None):
k_name = data_utils.rand_name('keypair')
- keypair = self._create_keypair(k_name, keypair_type=keypair_type)
+ keypair = self.create_keypair(k_name, keypair_type=keypair_type)
# Verify whether 'type' is present in keypair create response of
# version 2.2 and it is with default value 'ssh'.
self._check_keypair_type(keypair, keypair_type)
diff --git a/tempest/api/compute/security_groups/base.py b/tempest/api/compute/security_groups/base.py
index f70f6d3..cb18775 100644
--- a/tempest/api/compute/security_groups/base.py
+++ b/tempest/api/compute/security_groups/base.py
@@ -14,6 +14,11 @@
# under the License.
from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
class BaseSecurityGroupsTest(base.BaseV2ComputeTest):
@@ -23,3 +28,11 @@
# A network and a subnet will be created for these tests
cls.set_network_resources(network=True, subnet=True)
super(BaseSecurityGroupsTest, cls).setup_credentials()
+
+ @staticmethod
+ def generate_random_security_group_id():
+ if (CONF.service_available.neutron and
+ test.is_extension_enabled('security-group', 'network')):
+ return data_utils.rand_uuid()
+ else:
+ return data_utils.rand_int_id(start=999)
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
index 32b3ea3..78c19ca 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -15,20 +15,9 @@
from tempest.api.compute.security_groups import base
from tempest.common.utils import data_utils
-from tempest import config
from tempest.lib import exceptions as lib_exc
from tempest import test
-CONF = config.CONF
-
-
-def not_existing_id():
- if (CONF.service_available.neutron and
- test.is_extension_enabled('security-group', 'network')):
- return data_utils.rand_uuid()
- else:
- return data_utils.rand_int_id(start=999)
-
class SecurityGroupRulesNegativeTestJSON(base.BaseSecurityGroupsTest):
@@ -44,7 +33,7 @@
# Negative test: Creation of Security Group rule should FAIL
# with non existent Parent group id
# Adding rules to the non existent Security Group id
- parent_group_id = not_existing_id()
+ parent_group_id = self.generate_random_security_group_id()
ip_protocol = 'tcp'
from_port = 22
to_port = 22
@@ -179,7 +168,7 @@
def test_delete_security_group_rule_with_non_existent_id(self):
# Negative test: Deletion of Security Group rule should be FAIL
# with non existent id
- non_existent_rule_id = not_existing_id()
+ non_existent_rule_id = self.generate_random_security_group_id()
self.assertRaises(lib_exc.NotFound,
self.rules_client.delete_security_group_rule,
non_existent_rule_id)
diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py
index e6abf28..bcada1e 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -37,29 +37,13 @@
super(SecurityGroupsNegativeTestJSON, cls).resource_setup()
cls.neutron_available = CONF.service_available.neutron
- def _generate_a_non_existent_security_group_id(self):
- security_group_id = []
- body = self.client.list_security_groups()['security_groups']
- for i in range(len(body)):
- security_group_id.append(body[i]['id'])
- # Generate a non-existent security group id
- while True:
- if (self.neutron_available and
- test.is_extension_enabled('security-group', 'network')):
- non_exist_id = data_utils.rand_uuid()
- else:
- non_exist_id = data_utils.rand_int_id(start=999)
- if non_exist_id not in security_group_id:
- break
- return non_exist_id
-
@test.attr(type=['negative'])
@test.idempotent_id('673eaec1-9b3e-48ed-bdf1-2786c1b9661c')
@test.services('network')
def test_security_group_get_nonexistent_group(self):
# Negative test:Should not be able to GET the details
# of non-existent Security Group
- non_exist_id = self._generate_a_non_existent_security_group_id()
+ non_exist_id = self.generate_random_security_group_id()
self.assertRaises(lib_exc.NotFound, self.client.show_security_group,
non_exist_id)
@@ -139,7 +123,7 @@
@test.services('network')
def test_delete_nonexistent_security_group(self):
# Negative test:Deletion of a non-existent Security Group should fail
- non_exist_id = self._generate_a_non_existent_security_group_id()
+ non_exist_id = self.generate_random_security_group_id()
self.assertRaises(lib_exc.NotFound,
self.client.delete_security_group, non_exist_id)
@@ -204,7 +188,7 @@
@test.services('network')
def test_update_non_existent_security_group(self):
# Update a non-existent Security Group should Fail
- non_exist_id = self._generate_a_non_existent_security_group_id()
+ non_exist_id = self.generate_random_security_group_id()
s_name = data_utils.rand_name('sg')
s_description = data_utils.rand_name('description')
self.assertRaises(lib_exc.NotFound,
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index f66bc72..2b4cee7 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -209,7 +209,7 @@
@test.attr(type=['negative'])
@test.idempotent_id('c3e0fb12-07fc-4d76-a22e-37409887afe8')
def test_create_server_name_length_exceeds_256(self):
- # Create a server with name length exceeding 256 characters
+ # Create a server with name length exceeding 255 characters
server_name = 'a' * 256
self.assertRaises(lib_exc.BadRequest,
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 30549ec..fa465af 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import logging
+from oslo_log import log as logging
import testtools
from tempest.api.compute import base
diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py
index c4041cb..0e1fef2 100644
--- a/tempest/api/compute/volumes/test_volumes_negative.py
+++ b/tempest/api/compute/volumes/test_volumes_negative.py
@@ -95,7 +95,8 @@
# Negative: Should not be able to delete volume when invalid ID is
# passed
self.assertRaises(lib_exc.NotFound,
- self.client.delete_volume, '!@#$%^&*()')
+ self.client.delete_volume,
+ data_utils.rand_name('invalid'))
@test.attr(type=['negative'])
@test.idempotent_id('0d1417c5-4ae8-4c2c-adc5-5f0b864253e5')
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 23bd628..cd4f820 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -143,6 +143,7 @@
cls.resource_types_client = cls.os.resource_types_client
cls.namespace_properties_client = cls.os.namespace_properties_client
cls.namespace_objects_client = cls.os.namespace_objects_client
+ cls.namespace_tags_client = cls.os.namespace_tags_client
cls.schemas_client = cls.os.schemas_client
def create_namespace(cls, namespace_name=None, visibility='public',
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 453bb34..36dc6c3 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -126,11 +126,12 @@
self.assertEqual(new_image_name, body['name'])
-class ListImagesTest(base.BaseV2ImageTest):
+class ListUserImagesTest(base.BaseV2ImageTest):
+ """Here we test the listing of image information"""
@classmethod
def resource_setup(cls):
- super(ListImagesTest, cls).resource_setup()
+ super(ListUserImagesTest, cls).resource_setup()
# We add a few images here to test the listing functionality of
# the images API
container_fmts = CONF.image.container_formats
@@ -166,10 +167,6 @@
return image['id']
-
-class ListUserImagesTest(ListImagesTest):
- """Here we test the listing of image information"""
-
def _list_by_param_value_and_assert(self, params):
"""Perform list action with given params and validates result."""
# Retrieve the list of images that meet the filter
@@ -323,7 +320,7 @@
self.assertEqual("images", body['name'])
-class ListSharedImagesTest(ListImagesTest):
+class ListSharedImagesTest(base.BaseV2ImageTest):
"""Here we test the listing of a shared image information"""
credentials = ['primary', 'alt']
@@ -336,17 +333,22 @@
@test.idempotent_id('3fa50be4-8e38-4c02-a8db-7811bb780122')
def test_list_images_param_member_status(self):
- # Share one of the images created with the alt user
+ # Create an image to be shared using default visibility
+ image_file = six.BytesIO(data_utils.random_bytes(2048))
+ container_format = CONF.image.container_formats[0]
+ disk_format = CONF.image.disk_formats[0]
+ image = self.create_image(container_format=container_format,
+ disk_format=disk_format)
+ self.client.store_image_file(image['id'], data=image_file)
+
+ # Share the image created with the alt user
self.image_member_client.create_image_member(
- image_id=self.test_data['id'],
- member=self.alt_img_client.tenant_id)
- # Update the info on the test data so it remains accurate
- self.test_data['updated_at'] = self.client.show_image(
- self.test_data['id'])['updated_at']
+ image_id=image['id'], member=self.alt_img_client.tenant_id)
+
# As an image consumer you need to provide the member_status parameter
# along with the visibility=shared parameter in order for it to show
# results
params = {'member_status': 'pending', 'visibility': 'shared'}
fetched_images = self.alt_img_client.list_images(params)['images']
self.assertEqual(1, len(fetched_images))
- self.assertEqual(self.test_data['id'], fetched_images[0]['id'])
+ self.assertEqual(image['id'], fetched_images[0]['id'])
diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_tags.py b/tempest/api/image/v2/test_images_metadefs_namespace_tags.py
new file mode 100644
index 0000000..186d9c8
--- /dev/null
+++ b/tempest/api/image/v2/test_images_metadefs_namespace_tags.py
@@ -0,0 +1,90 @@
+# 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.image import base
+from tempest.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest import test
+
+
+class MetadataNamespaceTagsTest(base.BaseV2ImageTest):
+ """Test the Metadata definition namespace tags basic functionality"""
+
+ tags = [
+ {
+ "name": "sample-tag1"
+ },
+ {
+ "name": "sample-tag2"
+ },
+ {
+ "name": "sample-tag3"
+ }
+ ]
+ tag_list = ["sample-tag1", "sample-tag2", "sample-tag3"]
+
+ def _create_namespace_tags(self, namespace):
+ # Create a namespace
+ namespace_tags = self.namespace_tags_client.create_namespace_tags(
+ namespace['namespace'], tags=self.tags)
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.namespace_tags_client.delete_namespace_tags,
+ namespace['namespace'])
+ return namespace_tags
+
+ @test.idempotent_id('a2a3765e-3a6d-4f6d-a3a7-3cc3476aa876')
+ def test_create_list_delete_namespace_tags(self):
+ # Create a namespace
+ namespace = self.create_namespace()
+ self._create_namespace_tags(namespace)
+ # List namespace tags
+ body = self.namespace_tags_client.list_namespace_tags(
+ namespace['namespace'])
+ self.assertTrue(3, len(body['tags']))
+ self.assertIn(body['tags'][0]['name'], self.tag_list)
+ self.assertIn(body['tags'][1]['name'], self.tag_list)
+ self.assertIn(body['tags'][2]['name'], self.tag_list)
+ # Delete all tag definitions
+ self.namespace_tags_client.delete_namespace_tags(
+ namespace['namespace'])
+ body = self.namespace_tags_client.list_namespace_tags(
+ namespace['namespace'])
+ self.assertEqual([], body['tags'])
+
+ @test.idempotent_id('a2a3765e-1a2c-3f6d-a3a7-3cc3466ab875')
+ def test_create_update_delete_tag(self):
+ # Create a namespace
+ namespace = self.create_namespace()
+ self._create_namespace_tags(namespace)
+ # Create a tag
+ tag_name = data_utils.rand_name('tag_name')
+ self.namespace_tags_client.create_namespace_tag(
+ namespace=namespace['namespace'], tag_name=tag_name)
+
+ body = self.namespace_tags_client.show_namespace_tag(
+ namespace['namespace'], tag_name)
+ self.assertEqual(tag_name, body['name'])
+ # Update tag definition
+ update_tag_definition = data_utils.rand_name('update-tag')
+ body = self.namespace_tags_client.update_namespace_tag(
+ namespace['namespace'], tag_name=tag_name,
+ name=update_tag_definition)
+ self.assertEqual(update_tag_definition, body['name'])
+ # Delete tag definition
+ self.namespace_tags_client.delete_namespace_tag(
+ namespace['namespace'], update_tag_definition)
+ # List namespace tags and validate deletion
+ namespace_tags = [
+ namespace_tag['name'] for namespace_tag in
+ self.namespace_tags_client.list_namespace_tags(
+ namespace['namespace'])['tags']]
+ self.assertNotIn(update_tag_definition, namespace_tags)
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index c2c42bb..132e23e 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -108,10 +108,10 @@
# Not all classes in the hierarchy have the client class variable
if len(cls.metering_label_rules) > 0:
label_rules_client = cls.admin_metering_label_rules_client
- for metering_label_rule in cls.metering_label_rules:
- test_utils.call_and_ignore_notfound_exc(
- label_rules_client.delete_metering_label_rule,
- metering_label_rule['id'])
+ for metering_label_rule in cls.metering_label_rules:
+ test_utils.call_and_ignore_notfound_exc(
+ label_rules_client.delete_metering_label_rule,
+ metering_label_rule['id'])
# Clean up metering labels
for metering_label in cls.metering_labels:
test_utils.call_and_ignore_notfound_exc(
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 535137e..e0216fd 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -121,7 +121,7 @@
if object_name is None:
object_name = data_utils.rand_name(name='TestObject')
if data is None:
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
cls.object_client.create_object(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
index ffdd1de..e555fd9 100644
--- a/tempest/api/object_storage/test_container_acl.py
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -26,17 +26,6 @@
credentials = [['operator', CONF.object_storage.operator_role],
['operator_alt', CONF.object_storage.operator_role]]
- @classmethod
- def setup_credentials(cls):
- super(ObjectTestACLs, cls).setup_credentials()
- cls.os = cls.os_roles_operator
- cls.os_operator = cls.os_roles_operator_alt
-
- @classmethod
- def resource_setup(cls):
- super(ObjectTestACLs, cls).resource_setup()
- cls.test_auth_data = cls.os_operator.auth_provider.auth_data
-
def setUp(self):
super(ObjectTestACLs, self).setUp()
self.container_name = self.create_container()
@@ -49,24 +38,26 @@
def test_read_object_with_rights(self):
# attempt to read object using authorized user
# update X-Container-Read metadata ACL
- tenant_name = self.os_operator.credentials.tenant_name
- username = self.os_operator.credentials.username
+ tenant_name = self.os_roles_operator_alt.credentials.tenant_name
+ username = self.os_roles_operator_alt.credentials.username
cont_headers = {'X-Container-Read': tenant_name + ':' + username}
- resp_meta, body = self.container_client.update_container_metadata(
- self.container_name, metadata=cont_headers,
- metadata_prefix='')
+ resp_meta, body = self.os_roles_operator.container_client.\
+ update_container_metadata(
+ self.container_name, metadata=cont_headers,
+ metadata_prefix='')
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')
- resp, _ = self.object_client.create_object(self.container_name,
- object_name, 'data')
+ resp, _ = self.os_roles_operator.object_client.create_object(
+ self.container_name, object_name, 'data')
self.assertHeaders(resp, 'Object', 'PUT')
- # Trying to read the object with rights
- self.object_client.auth_provider.set_alt_auth_data(
+ # set alternative authentication data; cannot simply use the
+ # other object client.
+ self.os_roles_operator.object_client.auth_provider.set_alt_auth_data(
request_part='headers',
- auth_data=self.test_auth_data
- )
- resp, _ = self.object_client.get_object(
+ auth_data=self.os_roles_operator_alt.object_client.auth_provider.
+ auth_data)
+ resp, _ = self.os_roles_operator.object_client.get_object(
self.container_name, object_name)
self.assertHeaders(resp, 'Object', 'GET')
@@ -74,20 +65,23 @@
def test_write_object_with_rights(self):
# attempt to write object using authorized user
# update X-Container-Write metadata ACL
- tenant_name = self.os_operator.credentials.tenant_name
- username = self.os_operator.credentials.username
+ tenant_name = self.os_roles_operator_alt.credentials.tenant_name
+ username = self.os_roles_operator_alt.credentials.username
cont_headers = {'X-Container-Write': tenant_name + ':' + username}
- resp_meta, body = self.container_client.update_container_metadata(
- self.container_name, metadata=cont_headers,
- metadata_prefix='')
+ resp_meta, body = self.os_roles_operator.container_client.\
+ update_container_metadata(self.container_name,
+ metadata=cont_headers,
+ metadata_prefix='')
self.assertHeaders(resp_meta, 'Container', 'POST')
- # Trying to write the object with rights
- self.object_client.auth_provider.set_alt_auth_data(
+ # set alternative authentication data; cannot simply use the
+ # other object client.
+ self.os_roles_operator.object_client.auth_provider.set_alt_auth_data(
request_part='headers',
- auth_data=self.test_auth_data
- )
+ auth_data=self.os_roles_operator_alt.object_client.auth_provider.
+ auth_data)
+ # Trying to write the object with rights
object_name = data_utils.rand_name(name='Object')
- resp, _ = self.object_client.create_object(
+ resp, _ = self.os_roles_operator.object_client.create_object(
self.container_name,
object_name, 'data', headers={})
self.assertHeaders(resp, 'Object', 'PUT')
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 9ce1b18..e4476a1 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -133,7 +133,7 @@
resp, object_list = self.container_client.list_container_contents(
container_name)
self.assertHeaders(resp, 'Container', 'GET')
- self.assertEqual(object_name, object_list.strip('\n'))
+ self.assertEqual([object_name], object_list)
@test.idempotent_id('4646ac2d-9bfb-4c7d-a3c5-0f527402b3df')
def test_list_container_contents_with_no_object(self):
@@ -143,7 +143,7 @@
resp, object_list = self.container_client.list_container_contents(
container_name)
self.assertHeaders(resp, 'Container', 'GET')
- self.assertEqual('', object_list.strip('\n'))
+ self.assertEmpty(object_list)
@test.idempotent_id('fe323a32-57b9-4704-a996-2e68f83b09bc')
def test_list_container_contents_with_delimiter(self):
@@ -157,7 +157,7 @@
container_name,
params=params)
self.assertHeaders(resp, 'Container', 'GET')
- self.assertEqual(object_name.split('/')[0], object_list.strip('/\n'))
+ self.assertEqual([object_name.split('/')[0] + '/'], object_list)
@test.idempotent_id('55b4fa5c-e12e-4ca9-8fcf-a79afe118522')
def test_list_container_contents_with_end_marker(self):
@@ -170,7 +170,7 @@
container_name,
params=params)
self.assertHeaders(resp, 'Container', 'GET')
- self.assertEqual(object_name, object_list.strip('\n'))
+ self.assertEqual([object_name], object_list)
@test.idempotent_id('196f5034-6ab0-4032-9da9-a937bbb9fba9')
def test_list_container_contents_with_format_json(self):
@@ -226,7 +226,7 @@
container_name,
params=params)
self.assertHeaders(resp, 'Container', 'GET')
- self.assertEqual(object_name, object_list.strip('\n'))
+ self.assertEqual([object_name], object_list)
@test.idempotent_id('c31ddc63-2a58-4f6b-b25c-94d2937e6867')
def test_list_container_contents_with_marker(self):
@@ -239,7 +239,7 @@
container_name,
params=params)
self.assertHeaders(resp, 'Container', 'GET')
- self.assertEqual(object_name, object_list.strip('\n'))
+ self.assertEqual([object_name], object_list)
@test.idempotent_id('58ca6cc9-6af0-408d-aaec-2a6a7b2f0df9')
def test_list_container_contents_with_path(self):
@@ -253,7 +253,7 @@
container_name,
params=params)
self.assertHeaders(resp, 'Container', 'GET')
- self.assertEqual(object_name, object_list.strip('\n'))
+ self.assertEqual([object_name], object_list)
@test.idempotent_id('77e742c7-caf2-4ec9-8aa4-f7d509a3344c')
def test_list_container_contents_with_prefix(self):
@@ -267,7 +267,7 @@
container_name,
params=params)
self.assertHeaders(resp, 'Container', 'GET')
- self.assertEqual(object_name, object_list.strip('\n'))
+ self.assertEqual([object_name], object_list)
@test.attr(type='smoke')
@test.idempotent_id('96e68f0e-19ec-4aa2-86f3-adc6a45e14dd')
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 47ef0d3..edc9271 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -96,7 +96,7 @@
# Check only the format of common headers with custom matcher
self.assertThat(resp, custom_matchers.AreAllWellFormatted())
- self.assertIn(self.object_name, body)
+ self.assertIn(self.object_name, body.decode())
# clean up before exiting
self.container_client.update_container_metadata(self.container_name,
@@ -126,9 +126,9 @@
resp, body = self.account_client.request("GET",
self.container_name,
headers={})
- self.assertIn(self.object_name, body)
+ self.assertIn(self.object_name, body.decode())
css = '<link rel="stylesheet" type="text/css" href="listings.css" />'
- self.assertIn(css, body)
+ self.assertIn(css, body.decode())
@test.idempotent_id('f18b4bef-212e-45e7-b3ca-59af3a465f82')
@test.requires_ext(extension='staticweb', service='object')
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index e10b900..f134335 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -96,7 +96,7 @@
cont_client[0].put(str(cont[0]), body=None, headers=headers)
# create object in container
object_name = data_utils.rand_name(name='TestSyncObject')
- data = object_name[::-1] # data_utils.arbitrary_string()
+ data = object_name[::-1].encode() # Raw data, we need bytes
resp, _ = obj_client[0].create_object(cont[0], object_name, data)
self.objects.append(object_name)
@@ -127,7 +127,7 @@
for obj_client, cont in obj_clients:
for obj_name in object_lists[0]:
resp, object_content = obj_client.get_object(cont, obj_name)
- self.assertEqual(object_content, obj_name[::-1])
+ self.assertEqual(object_content, obj_name[::-1].encode())
@test.attr(type='slow')
@decorators.skip_because(bug='1317133')
diff --git a/tempest/api/object_storage/test_crossdomain.py b/tempest/api/object_storage/test_crossdomain.py
index 8dbfd06..18dc254 100644
--- a/tempest/api/object_storage/test_crossdomain.py
+++ b/tempest/api/object_storage/test_crossdomain.py
@@ -40,6 +40,7 @@
@test.requires_ext(extension='crossdomain', service='object')
def test_get_crossdomain_policy(self):
resp, body = self.account_client.get("crossdomain.xml", {})
+ body = body.decode()
self.assertTrue(body.startswith(self.xml_start) and
body.endswith(self.xml_end))
diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py
index 102ec2f..0a87a64 100644
--- a/tempest/api/object_storage/test_object_formpost.py
+++ b/tempest/api/object_storage/test_object_formpost.py
@@ -72,7 +72,9 @@
max_file_count,
expires)
- signature = hmac.new(self.key, hmac_body, hashlib.sha1).hexdigest()
+ signature = hmac.new(
+ self.key.encode(), hmac_body.encode(), hashlib.sha1
+ ).hexdigest()
fields = {'redirect': redirect,
'max_file_size': str(max_file_size),
@@ -119,4 +121,4 @@
resp, body = self.object_client.get("%s/%s%s" % (
self.container_name, self.object_name, "testfile"))
self.assertHeaders(resp, "Object", "GET")
- self.assertEqual(body, "hello world")
+ self.assertEqual(body.decode(), "hello world")
diff --git a/tempest/api/object_storage/test_object_formpost_negative.py b/tempest/api/object_storage/test_object_formpost_negative.py
index 8ff5d82..f193111 100644
--- a/tempest/api/object_storage/test_object_formpost_negative.py
+++ b/tempest/api/object_storage/test_object_formpost_negative.py
@@ -73,7 +73,9 @@
max_file_count,
expires)
- signature = hmac.new(self.key, hmac_body, hashlib.sha1).hexdigest()
+ signature = hmac.new(
+ self.key.encode(), hmac_body.encode(), hashlib.sha1
+ ).hexdigest()
fields = {'redirect': redirect,
'max_file_size': str(max_file_size),
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index e2e9919..7716bdb 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -79,12 +79,12 @@
def test_create_object(self):
# create object
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
# create another object
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
self.assertHeaders(resp, 'Object', 'PUT')
@@ -98,7 +98,7 @@
def test_create_object_with_content_disposition(self):
# create object with content_disposition
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
metadata = {}
metadata['content-disposition'] = 'inline'
resp, _ = self.object_client.create_object(
@@ -122,7 +122,7 @@
object_name = data_utils.rand_name(name='TestObject')
# put compressed string
- data_before = 'x' * 2000
+ data_before = b'x' * 2000
data = zlib.compress(data_before)
metadata = {}
metadata['content-encoding'] = 'deflate'
@@ -147,7 +147,7 @@
def test_create_object_with_etag(self):
# create object with etag
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
md5 = hashlib.md5(data).hexdigest()
metadata = {'Etag': md5}
resp, _ = self.object_client.create_object(
@@ -167,7 +167,7 @@
# create object with expect_continue
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
status, _ = self.object_client.create_object_continue(
self.container_name, object_name, data)
@@ -183,7 +183,7 @@
def test_create_object_with_transfer_encoding(self):
# create object with transfer_encoding
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string(1024)
+ data = data_utils.random_bytes(1024)
status, _, resp_headers = self.object_client.put_object_with_chunk(
container=self.container_name,
name=object_name,
@@ -200,7 +200,7 @@
def test_create_object_with_x_fresh_metadata(self):
# create object with x_fresh_metadata
object_name_base = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
metadata_1 = {'X-Object-Meta-test-meta': 'Meta'}
self.object_client.create_object(self.container_name,
object_name_base,
@@ -226,7 +226,7 @@
def test_create_object_with_x_object_meta(self):
# create object with object_meta
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
metadata = {'X-Object-Meta-test-meta': 'Meta'}
resp, _ = self.object_client.create_object(
self.container_name,
@@ -245,7 +245,7 @@
def test_create_object_with_x_object_metakey(self):
# create object with the blank value of metadata
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
metadata = {'X-Object-Meta-test-meta': ''}
resp, _ = self.object_client.create_object(
self.container_name,
@@ -264,7 +264,7 @@
def test_create_object_with_x_remove_object_meta(self):
# create object with x_remove_object_meta
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
metadata_add = {'X-Object-Meta-test-meta': 'Meta'}
self.object_client.create_object(self.container_name,
object_name,
@@ -287,7 +287,7 @@
def test_create_object_with_x_remove_object_metakey(self):
# create object with the blank value of remove metadata
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
metadata_add = {'X-Object-Meta-test-meta': 'Meta'}
self.object_client.create_object(self.container_name,
object_name,
@@ -310,7 +310,7 @@
def test_delete_object(self):
# create object
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
# delete object
@@ -342,7 +342,7 @@
def test_update_object_metadata_with_remove_metadata(self):
# update object metadata with remove metadata
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
create_metadata = {'X-Object-Meta-test-meta1': 'Meta1'}
self.object_client.create_object(self.container_name,
object_name,
@@ -366,7 +366,7 @@
def test_update_object_metadata_with_create_and_remove_metadata(self):
# creation and deletion of metadata with one request
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
create_metadata = {'X-Object-Meta-test-meta1': 'Meta1'}
self.object_client.create_object(self.container_name,
object_name,
@@ -464,7 +464,7 @@
def test_list_object_metadata(self):
# get object metadata
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
metadata = {'X-Object-Meta-test-meta': 'Meta'}
self.object_client.create_object(self.container_name,
object_name,
@@ -547,7 +547,7 @@
def test_get_object_with_metadata(self):
# get object with metadata
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
metadata = {'X-Object-Meta-test-meta': 'Meta'}
self.object_client.create_object(self.container_name,
object_name,
@@ -566,7 +566,7 @@
def test_get_object_with_range(self):
# get object with range
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string(100)
+ data = data_utils.random_bytes(100)
self.object_client.create_object(self.container_name,
object_name,
data,
@@ -621,13 +621,13 @@
self.assertEqual(resp['x-object-manifest'],
'%s/%s' % (self.container_name, object_name))
- self.assertEqual(''.join(data_segments), body)
+ self.assertEqual(''.join(data_segments), body.decode())
@test.idempotent_id('c05b4013-e4de-47af-be84-e598062b16fc')
def test_get_object_with_if_match(self):
# get object with if_match
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string(10)
+ data = data_utils.random_bytes(10)
create_md5 = hashlib.md5(data).hexdigest()
create_metadata = {'Etag': create_md5}
self.object_client.create_object(self.container_name,
@@ -647,7 +647,7 @@
def test_get_object_with_if_modified_since(self):
# get object with if_modified_since
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string()
+ data = data_utils.random_bytes()
time_now = time.time()
self.object_client.create_object(self.container_name,
object_name,
@@ -667,7 +667,7 @@
def test_get_object_with_if_none_match(self):
# get object with if_none_match
object_name = data_utils.rand_name(name='TestObject')
- data = data_utils.arbitrary_string(10)
+ data = data_utils.random_bytes()
create_md5 = hashlib.md5(data).hexdigest()
create_metadata = {'Etag': create_md5}
self.object_client.create_object(self.container_name,
@@ -675,7 +675,7 @@
data,
metadata=create_metadata)
- list_data = data_utils.arbitrary_string(15)
+ list_data = data_utils.random_bytes()
list_md5 = hashlib.md5(list_data).hexdigest()
list_metadata = {'If-None-Match': list_md5}
resp, body = self.object_client.get_object(
@@ -717,15 +717,13 @@
def test_copy_object_in_same_container(self):
# create source object
src_object_name = data_utils.rand_name(name='SrcObject')
- src_data = data_utils.arbitrary_string(size=len(src_object_name) * 2,
- base_text=src_object_name)
+ src_data = data_utils.random_bytes(size=len(src_object_name) * 2)
resp, _ = self.object_client.create_object(self.container_name,
src_object_name,
src_data)
# create destination object
dst_object_name = data_utils.rand_name(name='DstObject')
- dst_data = data_utils.arbitrary_string(size=len(dst_object_name) * 3,
- base_text=dst_object_name)
+ dst_data = data_utils.random_bytes(size=len(dst_object_name) * 3)
resp, _ = self.object_client.create_object(self.container_name,
dst_object_name,
dst_data)
@@ -764,14 +762,12 @@
def test_copy_object_2d_way(self):
# create source object
src_object_name = data_utils.rand_name(name='SrcObject')
- src_data = data_utils.arbitrary_string(size=len(src_object_name) * 2,
- base_text=src_object_name)
+ src_data = data_utils.random_bytes(size=len(src_object_name) * 2)
resp, _ = self.object_client.create_object(self.container_name,
src_object_name, src_data)
# create destination object
dst_object_name = data_utils.rand_name(name='DstObject')
- dst_data = data_utils.arbitrary_string(size=len(dst_object_name) * 3,
- base_text=dst_object_name)
+ dst_data = data_utils.random_bytes(size=len(dst_object_name) * 3)
resp, _ = self.object_client.create_object(self.container_name,
dst_object_name, dst_data)
# copy source object to destination
@@ -799,8 +795,7 @@
self.containers.append(dst_container_name)
# create object in source container
object_name = data_utils.rand_name(name='Object')
- data = data_utils.arbitrary_string(size=len(object_name) * 2,
- base_text=object_name)
+ data = data_utils.random_bytes(size=len(object_name) * 2)
resp, _ = self.object_client.create_object(src_container_name,
object_name, data)
# set object metadata
@@ -933,7 +928,7 @@
# downloading the object
resp, body = self.object_client.get_object(
self.container_name, object_name)
- self.assertEqual(''.join(data_segments), body)
+ self.assertEqual(''.join(data_segments), body.decode())
@test.idempotent_id('50d01f12-526f-4360-9ac2-75dd508d7b68')
def test_get_object_if_different(self):
@@ -958,7 +953,7 @@
# local copy is different, download
local_data = "something different"
- md5 = hashlib.md5(local_data).hexdigest()
+ md5 = hashlib.md5(local_data.encode()).hexdigest()
headers = {'If-None-Match': md5}
resp, body = self.object_client.get(url, headers=headers)
self.assertHeaders(resp, 'Object', 'GET')
@@ -1002,8 +997,7 @@
# create object
object_name = data_utils.rand_name(name='Object')
- data = data_utils.arbitrary_string(size=len(object_name),
- base_text=object_name)
+ data = data_utils.random_bytes(size=len(object_name))
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
self.assertHeaders(resp, 'Object', 'PUT')
@@ -1039,8 +1033,7 @@
# create object
object_name = data_utils.rand_name(name='Object')
- data = data_utils.arbitrary_string(size=len(object_name) * 1,
- base_text=object_name)
+ data = data_utils.random_bytes(size=len(object_name))
resp, _ = self.object_client.create_object(self.container_name,
object_name, data)
self.assertHeaders(resp, 'Object', 'PUT')
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
index e00bbab..f9c1148 100644
--- a/tempest/api/object_storage/test_object_slo.py
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -56,7 +56,7 @@
object_name_base_1 = object_name + '_01'
object_name_base_2 = object_name + '_02'
data_size = MIN_SEGMENT_SIZE
- self.content = data_utils.arbitrary_string(data_size)
+ self.content = data_utils.random_bytes(data_size)
self._create_object(self.container_name,
object_name_base_1,
self.content)
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index 7287a2d..bd0d213 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -75,7 +75,9 @@
container, object_name)
hmac_body = '%s\n%s\n%s' % (method, expires, path)
- sig = hmac.new(key, hmac_body, hashlib.sha1).hexdigest()
+ sig = hmac.new(
+ key.encode(), hmac_body.encode(), hashlib.sha1
+ ).hexdigest()
url = "%s/%s?temp_url_sig=%s&temp_url_expires=%s" % (container,
object_name,
@@ -129,9 +131,7 @@
@test.idempotent_id('9b08dade-3571-4152-8a4f-a4f2a873a735')
@test.requires_ext(extension='tempurl', service='object')
def test_put_object_using_temp_url(self):
- new_data = data_utils.arbitrary_string(
- size=len(self.object_name),
- base_text=data_utils.rand_name(name="random"))
+ new_data = data_utils.random_bytes(size=len(self.object_name))
expires = self._get_expiry_date()
url = self._get_temp_url(self.container_name,
diff --git a/tempest/api/object_storage/test_object_temp_url_negative.py b/tempest/api/object_storage/test_object_temp_url_negative.py
index 577f3bd..df7a7f6 100644
--- a/tempest/api/object_storage/test_object_temp_url_negative.py
+++ b/tempest/api/object_storage/test_object_temp_url_negative.py
@@ -80,7 +80,9 @@
container, object_name)
hmac_body = '%s\n%s\n%s' % (method, expires, path)
- sig = hmac.new(key, hmac_body, hashlib.sha1).hexdigest()
+ sig = hmac.new(
+ key.encode(), hmac_body.encode(), hashlib.sha1
+ ).hexdigest()
url = "%s/%s?temp_url_sig=%s&temp_url_expires=%s" % (container,
object_name,
diff --git a/tempest/api/object_storage/test_object_version.py b/tempest/api/object_storage/test_object_version.py
index 3f6623b..6d064a2 100644
--- a/tempest/api/object_storage/test_object_version.py
+++ b/tempest/api/object_storage/test_object_version.py
@@ -69,22 +69,24 @@
vers_container_name)
object_name = data_utils.rand_name(name='TestObject')
# create object
+ data_1 = data_utils.random_bytes()
resp, _ = self.object_client.create_object(base_container_name,
- object_name, '1')
+ object_name, data_1)
# create 2nd version of object
+ data_2 = data_utils.random_bytes()
resp, _ = self.object_client.create_object(base_container_name,
- object_name, '2')
+ object_name, data_2)
resp, body = self.object_client.get_object(base_container_name,
object_name)
- self.assertEqual(body, '2')
+ self.assertEqual(body, data_2)
# delete object version 2
resp, _ = self.object_client.delete_object(base_container_name,
object_name)
- self.assertContainer(base_container_name, '1', '1',
+ self.assertContainer(base_container_name, '1', '1024',
vers_container_name)
resp, body = self.object_client.get_object(base_container_name,
object_name)
- self.assertEqual(body, '1')
+ self.assertEqual(body, data_1)
# delete object version 1
resp, _ = self.object_client.delete_object(base_container_name,
object_name)
diff --git a/tempest/api/volume/admin/test_volume_retype_with_migration.py b/tempest/api/volume/admin/test_volume_retype_with_migration.py
new file mode 100644
index 0000000..8a69ea3
--- /dev/null
+++ b/tempest/api/volume/admin/test_volume_retype_with_migration.py
@@ -0,0 +1,109 @@
+# 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 oslo_log import log as logging
+
+from tempest.api.volume import base
+from tempest.common import waiters
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
+
+LOG = logging.getLogger(__name__)
+
+
+class VolumeRetypeWithMigrationV2Test(base.BaseVolumeAdminTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(VolumeRetypeWithMigrationV2Test, cls).skip_checks()
+
+ if not CONF.volume_feature_enabled.multi_backend:
+ raise cls.skipException("Cinder multi-backend feature disabled.")
+
+ if len(set(CONF.volume.backend_names)) < 2:
+ raise cls.skipException("Requires at least two different "
+ "backend names")
+
+ @classmethod
+ def resource_setup(cls):
+ super(VolumeRetypeWithMigrationV2Test, cls).resource_setup()
+ # read backend name from a list.
+ cls.backend_src = CONF.volume.backend_names[0]
+ cls.backend_dst = CONF.volume.backend_names[1]
+
+ extra_specs_src = {"volume_backend_name": cls.backend_src}
+ extra_specs_dst = {"volume_backend_name": cls.backend_dst}
+
+ cls.src_vol_type = cls.create_volume_type(extra_specs=extra_specs_src)
+ cls.dst_vol_type = cls.create_volume_type(extra_specs=extra_specs_dst)
+
+ cls.src_vol = cls.create_volume(volume_type=cls.src_vol_type['name'])
+
+ @classmethod
+ def resource_cleanup(cls):
+ # When retyping a volume, Cinder creates an internal volume in the
+ # target backend. The volume in the source backend is deleted after
+ # the migration, so we need to wait for Cinder delete this volume
+ # before deleting the types we've created.
+
+ # This list should return 2 volumes until the copy and cleanup
+ # process is finished.
+ fetched_list = cls.admin_volume_client.list_volumes(
+ params={'all_tenants': True,
+ 'display_name': cls.src_vol['name']})['volumes']
+
+ for fetched_vol in fetched_list:
+ if fetched_vol['id'] != cls.src_vol['id']:
+ # This is the Cinder internal volume
+ LOG.debug('Waiting for internal volume %s deletion',
+ fetched_vol['id'])
+ cls.admin_volume_client.wait_for_resource_deletion(
+ fetched_vol['id'])
+ break
+
+ super(VolumeRetypeWithMigrationV2Test, cls).resource_cleanup()
+
+ @test.idempotent_id('a1a41f3f-9dad-493e-9f09-3ff197d477cd')
+ def test_available_volume_retype_with_migration(self):
+
+ keys_with_no_change = ('id', 'size', 'description', 'name', 'user_id',
+ 'os-vol-tenant-attr:tenant_id')
+ keys_with_change = ('volume_type', 'os-vol-host-attr:host')
+
+ volume_source = self.admin_volume_client.show_volume(
+ self.src_vol['id'])['volume']
+
+ # TODO(erlon): change this to volumes_client client after Bug
+ # #1657806 is fixed
+ self.admin_volume_client.retype_volume(
+ self.src_vol['id'],
+ new_type=self.dst_vol_type['name'],
+ migration_policy='on-demand')
+
+ waiters.wait_for_volume_retype(self.volumes_client, self.src_vol['id'],
+ self.dst_vol_type['name'])
+ volume_dest = self.admin_volume_client.show_volume(
+ self.src_vol['id'])['volume']
+
+ # Check the volume information after the migration.
+ self.assertEqual('success',
+ volume_dest['os-vol-mig-status-attr:migstat'])
+ self.assertEqual('success', volume_dest['migration_status'])
+
+ for key in keys_with_no_change:
+ self.assertEqual(volume_source[key], volume_dest[key])
+
+ for key in keys_with_change:
+ self.assertNotEqual(volume_source[key], volume_dest[key])
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 6b2acc6..3d44bbe 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -42,7 +42,7 @@
extra_specs = {"storage_protocol": proto,
"vendor_name": vendor}
# Create two volume_types
- for i in range(2):
+ for _ in range(2):
vol_type = self.create_volume_type(
extra_specs=extra_specs)
volume_types.append(vol_type)
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index 61d4ba7..7591612 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -32,6 +32,9 @@
super(VolumesBackupsAdminV2Test, cls).skip_checks()
if not CONF.volume_feature_enabled.backup:
raise cls.skipException("Cinder backup feature disabled")
+ if not CONF.service_available.swift:
+ skip_msg = ("%s skipped as swift is not available" % cls.__name__)
+ raise cls.skipException(skip_msg)
def _delete_backup(self, backup_id):
self.admin_backups_client.delete_backup(backup_id)
diff --git a/tempest/api/volume/admin/v2/test_backends_capabilities.py b/tempest/api/volume/admin/v2/test_backends_capabilities.py
index fc9066c..9751845 100644
--- a/tempest/api/volume/admin/v2/test_backends_capabilities.py
+++ b/tempest/api/volume/admin/v2/test_backends_capabilities.py
@@ -72,8 +72,8 @@
]
# Returns a tuple of VOLUME_STATS values
- expected_list = map(operator.itemgetter(*VOLUME_STATS),
- cinder_pools)
- observed_list = map(operator.itemgetter(*VOLUME_STATS),
- capabilities)
+ expected_list = list(map(operator.itemgetter(*VOLUME_STATS),
+ cinder_pools))
+ observed_list = list(map(operator.itemgetter(*VOLUME_STATS),
+ capabilities))
self.assertEqual(expected_list, observed_list)
diff --git a/tempest/api/volume/admin/v2/test_volumes_list.py b/tempest/api/volume/admin/v2/test_volumes_list.py
index cdd9df9..fd36d0a 100644
--- a/tempest/api/volume/admin/v2/test_volumes_list.py
+++ b/tempest/api/volume/admin/v2/test_volumes_list.py
@@ -32,7 +32,7 @@
# NOTE(zhufl): When using pre-provisioned credentials, the project
# may have volumes other than those created below.
cls.volume_list = cls.volumes_client.list_volumes()['volumes']
- for i in range(3):
+ for _ in range(3):
volume = cls.create_volume()
# Fetch volume details
volume_details = cls.volumes_client.show_volume(
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 6dcde08..03a3774 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -29,6 +29,9 @@
super(VolumesBackupsV2Test, cls).skip_checks()
if not CONF.volume_feature_enabled.backup:
raise cls.skipException("Cinder backup feature disabled")
+ if not CONF.service_available.swift:
+ skip_msg = ("%s skipped as swift is not available" % cls.__name__)
+ raise cls.skipException(skip_msg)
def restore_backup(self, backup_id):
# Restore a backup
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 030ea6c..5e3f49f 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -61,7 +61,7 @@
# Create 3 test volumes
cls.volume_list = []
cls.metadata = {'Type': 'work'}
- for i in range(3):
+ for _ in range(3):
volume = cls.create_volume(metadata=cls.metadata)
volume = cls.volumes_client.show_volume(volume['id'])['volume']
cls.volume_list.append(volume)
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index c45ace6..bcdbd22 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -133,7 +133,8 @@
v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume')
metadata = {'Type': 'work'}
self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume,
- volume_id='#$%%&^&^', display_name=v_name,
+ volume_id=data_utils.rand_name('invalid'),
+ display_name=v_name,
metadata=metadata)
@test.attr(type=['negative'])
@@ -150,7 +151,7 @@
def test_get_invalid_volume_id(self):
# Should not be able to get volume with invalid id
self.assertRaises(lib_exc.NotFound, self.volumes_client.show_volume,
- '#$%%&^&^')
+ data_utils.rand_name('invalid'))
@test.attr(type=['negative'])
@test.idempotent_id('c6c3db06-29ad-4e91-beb0-2ab195fe49e3')
@@ -164,7 +165,7 @@
def test_delete_invalid_volume_id(self):
# Should not be able to delete volume when invalid ID is passed
self.assertRaises(lib_exc.NotFound, self.volumes_client.delete_volume,
- '!@#$%^&*()')
+ data_utils.rand_name('invalid'))
@test.attr(type=['negative'])
@test.idempotent_id('441a1550-5d44-4b30-af0f-a6d402f52026')
diff --git a/tempest/api/volume/test_volumes_snapshots_list.py b/tempest/api/volume/test_volumes_snapshots_list.py
index 4416bef..b831252 100644
--- a/tempest/api/volume/test_volumes_snapshots_list.py
+++ b/tempest/api/volume/test_volumes_snapshots_list.py
@@ -105,12 +105,6 @@
# List returns zero elements
self._list_snapshots_by_param_limit(limit=0, expected_elements=0)
- def cleanup_snapshot(self, snapshot):
- # Delete the snapshot
- self.snapshots_client.delete_snapshot(snapshot['id'])
- self.snapshots_client.wait_for_resource_deletion(snapshot['id'])
- self.snapshots.remove(snapshot)
-
class VolumesV1SnapshotLimitTestJSON(VolumesV2SnapshotListTestJSON):
_api_version = 1
diff --git a/tempest/api/volume/v2/test_volumes_list.py b/tempest/api/volume/v2/test_volumes_list.py
index fb8c65d..28ba941 100644
--- a/tempest/api/volume/v2/test_volumes_list.py
+++ b/tempest/api/volume/v2/test_volumes_list.py
@@ -42,7 +42,7 @@
# may have volumes other than those created below.
existing_volumes = cls.volumes_client.list_volumes()['volumes']
cls.volume_id_list = [vol['id'] for vol in existing_volumes]
- for i in range(3):
+ for _ in range(3):
volume = cls.create_volume(metadata=cls.metadata)
cls.volume_id_list.append(volume['id'])
diff --git a/tempest/clients.py b/tempest/clients.py
index 8d30aaa..18116f3 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -131,6 +131,8 @@
self.schemas_client = self.image_v2.SchemasClient()
self.namespace_properties_client = \
self.image_v2.NamespacePropertiesClient()
+ self.namespace_tags_client = \
+ self.image_v2.NamespaceTagsClient()
def _set_compute_clients(self):
self.agents_client = self.compute.AgentsClient()
@@ -163,6 +165,7 @@
self.aggregates_client = self.compute.AggregatesClient()
self.services_client = self.compute.ServicesClient()
self.tenant_usages_client = self.compute.TenantUsagesClient()
+ self.baremetal_nodes_client = self.compute.BaremetalNodesClient()
self.hosts_client = self.compute.HostsClient()
self.hypervisor_client = self.compute.HypervisorClient()
self.instance_usages_audit_log_client = (
diff --git a/tempest/cmd/workspace.py b/tempest/cmd/workspace.py
index 3c58648..d2dc00d 100644
--- a/tempest/cmd/workspace.py
+++ b/tempest/cmd/workspace.py
@@ -151,7 +151,7 @@
if not os.path.isfile(self.path):
return
with open(self.path, 'r') as f:
- self.workspaces = yaml.load(f) or {}
+ self.workspaces = yaml.safe_load(f) or {}
class TempestWorkspace(command.Command):
diff --git a/tempest/common/preprov_creds.py b/tempest/common/preprov_creds.py
index 6a95588..a92d16a 100644
--- a/tempest/common/preprov_creds.py
+++ b/tempest/common/preprov_creds.py
@@ -33,7 +33,7 @@
def read_accounts_yaml(path):
try:
with open(path, 'r') as yaml_file:
- accounts = yaml.load(yaml_file)
+ accounts = yaml.safe_load(yaml_file)
except IOError:
raise lib_exc.InvalidConfiguration(
'The path for the test accounts file: %s '
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index fe648a0..8303caf 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -189,6 +189,25 @@
raise lib_exc.TimeoutException(message)
+def wait_for_volume_retype(client, volume_id, new_volume_type):
+ """Waits for a Volume to have a new volume type."""
+ body = client.show_volume(volume_id)['volume']
+ current_volume_type = body['volume_type']
+ start = int(time.time())
+
+ while current_volume_type != new_volume_type:
+ time.sleep(client.build_interval)
+ body = client.show_volume(volume_id)['volume']
+ current_volume_type = body['volume_type']
+
+ if int(time.time()) - start >= client.build_timeout:
+ message = ('Volume %s failed to reach %s volume type (current %s) '
+ 'within the required time (%s s).' %
+ (volume_id, new_volume_type, current_volume_type,
+ client.build_timeout))
+ raise exceptions.TimeoutException(message)
+
+
def wait_for_snapshot_status(client, snapshot_id, status):
"""Waits for a Snapshot to reach a given status."""
body = client.show_snapshot(snapshot_id)['snapshot']
diff --git a/tempest/config.py b/tempest/config.py
index 68f2667..fe8c175 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -16,7 +16,6 @@
from __future__ import print_function
import functools
-import logging as std_logging
import os
import tempfile
@@ -1199,7 +1198,7 @@
register_opts()
self._set_attrs()
if parse_conf:
- _CONF.log_opt_values(LOG, std_logging.DEBUG)
+ _CONF.log_opt_values(LOG, logging.DEBUG)
class TempestConfigProxy(object):
@@ -1207,14 +1206,14 @@
_path = None
_extra_log_defaults = [
- ('paramiko.transport', std_logging.INFO),
- ('requests.packages.urllib3.connectionpool', std_logging.WARN),
+ ('paramiko.transport', logging.INFO),
+ ('requests.packages.urllib3.connectionpool', logging.WARN),
]
def _fix_log_levels(self):
"""Tweak the oslo log defaults."""
for name, level in self._extra_log_defaults:
- std_logging.getLogger(name).setLevel(level)
+ logging.getLogger(name).logger.setLevel(level)
def __getattr__(self, attr):
if not self._config:
diff --git a/tempest/lib/api_schema/response/compute/v2_1/hosts.py b/tempest/lib/api_schema/response/compute/v2_1/hosts.py
index ae70ff1..cae3435 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/hosts.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/hosts.py
@@ -111,6 +111,9 @@
'status': {'enum': ['enabled', 'disabled']}
},
'additionalProperties': False,
- 'required': ['host', 'maintenance_mode', 'status']
+ 'anyOf': [
+ {'required': ['host', 'status']},
+ {'required': ['host', 'maintenance_mode']}
+ ]
}
}
diff --git a/tempest/lib/api_schema/response/compute/v2_1/servers.py b/tempest/lib/api_schema/response/compute/v2_1/servers.py
index 63e8467..1264416 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/servers.py
@@ -238,14 +238,17 @@
'status_code': [200],
'response_body': {
'type': 'object',
- 'properties': {
- 'adminPass': {'type': 'string'}
- },
'additionalProperties': False,
- 'required': ['adminPass']
}
}
+rescue_server_with_admin_pass = copy.deepcopy(rescue_server)
+rescue_server_with_admin_pass['response_body'].update(
+ {'properties': {'adminPass': {'type': 'string'}}})
+rescue_server_with_admin_pass['response_body'].update(
+ {'required': ['adminPass']})
+
+
list_virtual_interfaces = {
'status_code': [200],
'response_body': {
diff --git a/tempest/lib/cli/base.py b/tempest/lib/cli/base.py
index 5d7fbe3..5468a7b 100644
--- a/tempest/lib/cli/base.py
+++ b/tempest/lib/cli/base.py
@@ -13,11 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-import logging
import os
import shlex
import subprocess
+from oslo_log import log as logging
import six
from tempest.lib import base
diff --git a/tempest/lib/cli/output_parser.py b/tempest/lib/cli/output_parser.py
index c71c7a7..716f374 100644
--- a/tempest/lib/cli/output_parser.py
+++ b/tempest/lib/cli/output_parser.py
@@ -15,9 +15,10 @@
"""Collection of utilities for parsing CLI clients output."""
-import logging
import re
+from oslo_log import log as logging
+
from tempest.lib import exceptions
diff --git a/tempest/lib/cmd/skip_tracker.py b/tempest/lib/cmd/skip_tracker.py
index d95aa46..07b811d 100755
--- a/tempest/lib/cmd/skip_tracker.py
+++ b/tempest/lib/cmd/skip_tracker.py
@@ -21,16 +21,18 @@
"""
import argparse
-import logging
import os
import re
+from oslo_log import log as logging
+
try:
from launchpadlib import launchpad
except ImportError:
launchpad = None
LPCACHEDIR = os.path.expanduser('~/.launchpadlib/cache')
+LOG = logging.getLogger(__name__)
def parse_args():
@@ -40,11 +42,11 @@
def info(msg, *args, **kwargs):
- logging.info(msg, *args, **kwargs)
+ LOG.info(msg, *args, **kwargs)
def debug(msg, *args, **kwargs):
- logging.debug(msg, *args, **kwargs)
+ LOG.debug(msg, *args, **kwargs)
def find_skips(start):
@@ -110,8 +112,6 @@
def main():
- logging.basicConfig(format='%(levelname)s: %(message)s',
- level=logging.INFO)
parser = parse_args()
results = find_skips(parser.test_path)
unique_bugs = sorted(set([bug for (method, bug) in get_results(results)]))
diff --git a/tempest/lib/common/http.py b/tempest/lib/common/http.py
index 86ea26e..8a47d44 100644
--- a/tempest/lib/common/http.py
+++ b/tempest/lib/common/http.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
import urllib3
@@ -39,7 +40,9 @@
class Response(dict):
def __init__(self, info):
for key, value in info.getheaders().items():
- self[key.lower()] = value
+ # We assume HTTP header name to be string, not random
+ # bytes, thus ensure we have string keys.
+ self[six.u(key).lower()] = value
self.status = info.status
self['status'] = str(self.status)
self.reason = info.reason
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index 31d2ba5..2c36f55 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -16,7 +16,6 @@
import collections
import email.utils
-import logging as real_logging
import re
import time
@@ -248,8 +247,8 @@
# NOTE(afazekas): the http status code above 400 is processed by
# the _error_checker method
if read_code < 400:
- pattern = """Unexpected http success status code {0},
- The expected status code is {1}"""
+ pattern = ("Unexpected http success status code {0}, "
+ "The expected status code is {1}")
if ((not isinstance(expected_code, list) and
(read_code != expected_code)) or
(isinstance(expected_code, list) and
@@ -455,7 +454,7 @@
# Also look everything at DEBUG if you want to filter this
# out, don't run at debug.
- if self.LOG.isEnabledFor(real_logging.DEBUG):
+ if self.LOG.isEnabledFor(logging.DEBUG):
self._log_request_full(resp, req_headers, req_body,
resp_body, extra)
diff --git a/tempest/lib/services/clients.py b/tempest/lib/services/clients.py
index ec0aaff..445e8bd 100644
--- a/tempest/lib/services/clients.py
+++ b/tempest/lib/services/clients.py
@@ -17,7 +17,8 @@
import copy
import importlib
import inspect
-import logging
+
+from oslo_log import log as logging
from tempest.lib import auth
from tempest.lib.common.utils import misc
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index 597e815..50ce32e 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -616,7 +616,11 @@
API reference:
http://developer.openstack.org/api-ref-compute-v2.1.html#rescue
"""
- return self.action(server_id, 'rescue', schema.rescue_server, **kwargs)
+ if self.enable_instance_password:
+ rescue_schema = schema.rescue_server_with_admin_pass
+ else:
+ rescue_schema = schema.rescue_server
+ return self.action(server_id, 'rescue', rescue_schema, **kwargs)
def unrescue_server(self, server_id):
"""Unrescue the provided server.
diff --git a/tempest/lib/services/image/v2/__init__.py b/tempest/lib/services/image/v2/__init__.py
index a35ce17..7d973e5 100644
--- a/tempest/lib/services/image/v2/__init__.py
+++ b/tempest/lib/services/image/v2/__init__.py
@@ -19,11 +19,13 @@
NamespaceObjectsClient
from tempest.lib.services.image.v2.namespace_properties_client import \
NamespacePropertiesClient
+from tempest.lib.services.image.v2.namespace_tags_client import \
+ NamespaceTagsClient
from tempest.lib.services.image.v2.namespaces_client import NamespacesClient
from tempest.lib.services.image.v2.resource_types_client import \
ResourceTypesClient
from tempest.lib.services.image.v2.schemas_client import SchemasClient
__all__ = ['ImageMembersClient', 'ImagesClient', 'NamespaceObjectsClient',
- 'NamespacePropertiesClient', 'NamespacesClient',
- 'ResourceTypesClient', 'SchemasClient']
+ 'NamespacePropertiesClient', 'NamespaceTagsClient',
+ 'NamespacesClient', 'ResourceTypesClient', 'SchemasClient']
diff --git a/tempest/lib/services/image/v2/namespace_tags_client.py b/tempest/lib/services/image/v2/namespace_tags_client.py
new file mode 100644
index 0000000..ac8b569
--- /dev/null
+++ b/tempest/lib/services/image/v2/namespace_tags_client.py
@@ -0,0 +1,119 @@
+# Copyright 2016 EasyStack.
+# 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 oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
+
+from tempest.lib.common import rest_client
+
+
+class NamespaceTagsClient(rest_client.RestClient):
+ api_version = "v2"
+
+ def create_namespace_tag(self, namespace, tag_name):
+ """Adds a tag to the list of namespace tag definitions.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-tag-definition
+ """
+ url = 'metadefs/namespaces/%s/tags/%s' % (namespace,
+ tag_name)
+ resp, body = self.post(url, None)
+ self.expected_success(201, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def show_namespace_tag(self, namespace, tag_name):
+ """Gets a definition for a tag.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#get_tag_definition
+ """
+ url = 'metadefs/namespaces/%s/tags/%s' % (namespace,
+ tag_name)
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def update_namespace_tag(self, namespace, tag_name, **kwargs):
+ """Renames a tag definition.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-tag-definition
+ """
+ url = 'metadefs/namespaces/%s/tags/%s' % (namespace,
+ tag_name)
+ data = json.dumps(kwargs)
+ resp, body = self.put(url, data)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_namespace_tag(self, namespace, tag_name):
+ """Deletes a tag definition within a namespace.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-tag-definition
+ """
+ url = 'metadefs/namespaces/%s/tags/%s' % (namespace, tag_name)
+ resp, _ = self.delete(url)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp)
+
+ def create_namespace_tags(self, namespace, **kwargs):
+ """Creates one or more tag definitions in a namespace.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-tags
+ """
+ url = 'metadefs/namespaces/%s/tags' % namespace
+ data = json.dumps(kwargs)
+ resp, body = self.post(url, data)
+ self.expected_success(201, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def list_namespace_tags(self, namespace, **params):
+ """Lists the tag definitions within a namespace.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-tags
+ """
+ url = 'metadefs/namespaces/%s/tags' % namespace
+ if params:
+ url += '?%s' % urllib.urlencode(params)
+ resp, body = self.get(url)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_namespace_tags(self, namespace):
+ """Deletes all tag definitions within a namespace.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-all-tag-definitions
+ """
+ url = 'metadefs/namespaces/%s/tags' % namespace
+ resp, _ = self.delete(url)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 2da2f92..8c930c3 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -248,6 +248,27 @@
volume = self.volumes_client.show_volume(volume['id'])['volume']
return volume
+ def create_volume_type(self, client=None, name=None, backend_name=None):
+ if not client:
+ client = self.admin_volume_types_client
+ if not name:
+ class_name = self.__class__.__name__
+ name = data_utils.rand_name(class_name + '-volume-type')
+ randomized_name = data_utils.rand_name('scenario-type-' + name)
+
+ LOG.debug("Creating a volume type: %s on backend %s",
+ randomized_name, backend_name)
+ extra_specs = {}
+ if backend_name:
+ extra_specs = {"volume_backend_name": backend_name}
+
+ body = client.create_volume_type(name=randomized_name,
+ extra_specs=extra_specs)
+ volume_type = body['volume_type']
+ self.assertIn('id', volume_type)
+ self.addCleanup(client.delete_volume_type, volume_type['id'])
+ return volume_type
+
def _create_loginable_secgroup_rule(self, secgroup_id=None):
_client = self.compute_security_groups_client
_client_rules = self.compute_security_group_rules_client
@@ -529,14 +550,14 @@
caller = test_utils.find_test_caller()
LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
- ' expected result is %(should_succeed)s', **{
+ ' expected result is %(should_succeed)s', {
'caller': caller, 'ip': ip_address, 'timeout': timeout,
'should_succeed':
'reachable' if should_succeed else 'unreachable'
})
result = test_utils.call_until_true(ping, timeout, 1)
LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
- 'ping result is %(result)s', **{
+ 'ping result is %(result)s', {
'caller': caller, 'ip': ip_address, 'timeout': timeout,
'result': 'expected' if result else 'unexpected'
})
@@ -1246,19 +1267,6 @@
cls.admin_encryption_types_client =\
cls.os_adm.encryption_types_client
- def create_volume_type(self, client=None, name=None):
- if not client:
- client = self.admin_volume_types_client
- if not name:
- name = 'generic'
- randomized_name = data_utils.rand_name('scenario-type-' + name)
- LOG.debug("Creating a volume type: %s", randomized_name)
- body = client.create_volume_type(
- name=randomized_name)['volume_type']
- self.assertIn('id', body)
- self.addCleanup(client.delete_volume_type, body['id'])
- return body
-
def create_encryption_type(self, client=None, type_id=None, provider=None,
key_size=None, cipher=None,
control_location=None):
@@ -1326,7 +1334,7 @@
def upload_object_to_container(self, container_name, obj_name=None):
obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
- obj_data = data_utils.arbitrary_string()
+ obj_data = data_utils.random_bytes()
self.object_client.create_object(container_name, obj_name, obj_data)
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.object_client.delete_object,
diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py
new file mode 100644
index 0000000..dfda18d
--- /dev/null
+++ b/tempest/scenario/test_volume_migrate_attached.py
@@ -0,0 +1,128 @@
+# 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 oslo_log import log as logging
+
+from tempest.common import waiters
+from tempest import config
+from tempest.scenario import manager
+from tempest import test
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+class TestVolumeMigrateRetypeAttached(manager.ScenarioTest):
+
+ """This test case attempts to reproduce the following steps:
+
+ * Create 2 volume types representing 2 different backends
+ * Create in Cinder some bootable volume importing a Glance image using
+ * volume_type_1
+ * Boot an instance from the bootable volume
+ * Write to the volume
+ * Perform a cinder retype --on-demand of the volume to type of backend #2
+ * Check written content of migrated volume
+ """
+
+ credentials = ['primary', 'admin']
+
+ @classmethod
+ def setup_clients(cls):
+ super(TestVolumeMigrateRetypeAttached, cls).setup_clients()
+ if CONF.volume_feature_enabled.api_v1:
+ cls.admin_volume_types_client = cls.os_adm.volume_types_client
+ else:
+ cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
+
+ @classmethod
+ def skip_checks(cls):
+ super(TestVolumeMigrateRetypeAttached, cls).skip_checks()
+ if not CONF.volume_feature_enabled.multi_backend:
+ raise cls.skipException("Cinder multi-backend feature disabled")
+
+ if len(set(CONF.volume.backend_names)) < 2:
+ raise cls.skipException("Requires at least two different "
+ "backend names")
+
+ def _boot_instance_from_volume(self, vol_id, keypair, security_group):
+
+ key_name = keypair['name']
+ security_groups = [{'name': security_group['name']}]
+ block_device_mapping = [{'device_name': 'vda', 'volume_id': vol_id,
+ 'delete_on_termination': False}]
+
+ return self.create_server(image_id='', wait_until='ACTIVE',
+ key_name=key_name,
+ security_groups=security_groups,
+ block_device_mapping=block_device_mapping)
+
+ def _create_volume_types(self):
+ backend_names = CONF.volume.backend_names
+
+ backend_source = backend_names[0]
+ backend_dest = backend_names[1]
+
+ source_body = self.create_volume_type(backend_name=backend_source)
+ dest_body = self.create_volume_type(backend_name=backend_dest)
+
+ LOG.info("Created Volume types: %(src)s -> %(src_backend)s, %(dst)s "
+ "-> %(dst_backend)s", {'src': source_body['name'],
+ 'src_backend': backend_source,
+ 'dst': dest_body['name'],
+ 'dst_backend': backend_dest})
+ return source_body['name'], dest_body['name']
+
+ def _volume_retype_with_migration(self, volume_id, new_volume_type):
+ migration_policy = 'on-demand'
+ self.volumes_client.retype_volume(
+ volume_id, new_type=new_volume_type,
+ migration_policy=migration_policy)
+ waiters.wait_for_volume_retype(self.volumes_client,
+ volume_id, new_volume_type)
+
+ @test.idempotent_id('deadd2c2-beef-4dce-98be-f86765ff311b')
+ @test.services('compute', 'volume')
+ def test_volume_migrate_attached(self):
+ LOG.info("Creating keypair and security group")
+ keypair = self.create_keypair()
+ security_group = self._create_security_group()
+
+ # create volume types
+ LOG.info("Creating Volume types")
+ source_type, dest_type = self._create_volume_types()
+
+ # create an instance from volume
+ LOG.info("Booting instance from volume")
+ volume_origin = self.create_volume(imageRef=CONF.compute.image_ref,
+ volume_type=source_type)
+
+ instance = self._boot_instance_from_volume(volume_origin['id'],
+ keypair, security_group)
+
+ # write content to volume on instance
+ LOG.info("Setting timestamp in instance %s", instance['id'])
+ ip_instance = self.get_server_ip(instance)
+ timestamp = self.create_timestamp(ip_instance,
+ private_key=keypair['private_key'])
+
+ # retype volume with migration from backend #1 to backend #2
+ LOG.info("Retyping Volume %s to new type %s", volume_origin['id'],
+ dest_type)
+ self._volume_retype_with_migration(volume_origin['id'], dest_type)
+
+ # check the content of written file
+ LOG.info("Getting timestamp in postmigrated instance %s",
+ instance['id'])
+ timestamp2 = self.get_timestamp(ip_instance,
+ private_key=keypair['private_key'])
+ self.assertEqual(timestamp, timestamp2)
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index 2509156..afedd36 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -140,5 +140,11 @@
body = json.loads(body)
elif params and params.get('format') == 'xml':
body = etree.fromstring(body)
+ # Else the content-type is plain/text
+ else:
+ body = [
+ obj_name for obj_name in body.decode().split('\n') if obj_name
+ ]
+
self.expected_success([200, 204], resp.status)
return resp, body
diff --git a/tempest/test_discover/plugins.py b/tempest/test_discover/plugins.py
index e9f59af..abe2b73 100644
--- a/tempest/test_discover/plugins.py
+++ b/tempest/test_discover/plugins.py
@@ -13,8 +13,8 @@
# under the License.
import abc
-import logging
+from oslo_log import log as logging
import six
import stevedore
diff --git a/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py b/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py
new file mode 100644
index 0000000..2faa5be
--- /dev/null
+++ b/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py
@@ -0,0 +1,126 @@
+# Copyright 2016 EasyStack. 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.lib.services.image.v2 import namespace_tags_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestNamespaceTagsClient(base.BaseServiceTest):
+ FAKE_CREATE_SHOW_TAGS = {
+ "created_at": "2015-05-09T01:12:31Z",
+ "name": "added-sample-tag",
+ "updated_at": "2015-05-09T01:12:31Z"
+ }
+
+ FAKE_LIST_TAGS = {
+ "tags": [
+ {
+ "name": "sample-tag1"
+ },
+ {
+ "name": "sample-tag2"
+ },
+ {
+ "name": "sample-tag3"
+ }
+ ]
+ }
+
+ FAKE_UPDATE_TAGS = {"name": "new-tag-name"}
+
+ def setUp(self):
+ super(TestNamespaceTagsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = namespace_tags_client.NamespaceTagsClient(
+ fake_auth, 'image', 'regionOne')
+
+ def _test_create_namespace_tags(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_namespace_tags,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_SHOW_TAGS,
+ bytes_body, status=201,
+ namespace="OS::Compute::Hypervisor",
+ tags=[{"name": "sample-tag1"},
+ {"name": "sample-tag2"},
+ {"name": "sample-tag3"}])
+
+ def _test_list_namespace_tags(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_namespace_tags,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_TAGS,
+ bytes_body,
+ namespace="OS::Compute::Hypervisor")
+
+ def _test_create_namespace_tag_definition(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_namespace_tag,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_SHOW_TAGS,
+ bytes_body,
+ status=201,
+ namespace="OS::Compute::Hypervisor",
+ tag_name="added-sample-tag")
+
+ def _test_show_namespace_tag_definition(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_namespace_tag,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_CREATE_SHOW_TAGS,
+ bytes_body,
+ namespace="OS::Compute::Hypervisor",
+ tag_name="added-sample-tag")
+
+ def _test_update_namespace_tag_definition(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_namespace_tag,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_UPDATE_OBJECTS,
+ bytes_body,
+ namespace="OS::Compute::Hypervisor",
+ tag_name="added-sample-tag",
+ name="new-tag-name")
+
+ def test_create_namespace_tags_with_str_body(self):
+ self._test_create_namespace_tags()
+
+ def test_create_namespace_tags_with_bytes_body(self):
+ self._test_create_namespace_tags(bytes_body=True)
+
+ def test_list_namespace_tags_with_str_body(self):
+ self._test_list_namespace_tags()
+
+ def test_list_namespace_tags_with_bytes_body(self):
+ self._test_list_namespace_tags(bytes_body=True)
+
+ def test_create_namespace_tag_with_str_body(self):
+ self._test_create_namespace_tag_definition()
+
+ def test_create_namespace_tag_with_bytes_body(self):
+ self._test_create_namespace_tag_definition(bytes_body=True)
+
+ def test_show_namespace_tag_with_str_body(self):
+ self._test_show_namespace_tag_definition()
+
+ def test_show_namespace_tag_with_bytes_body(self):
+ self._test_show_namespace_tag_definition(bytes_body=True)
+
+ def test_delete_all_namespace_tags(self):
+ self.check_service_client_function(
+ self.client.delete_namespace_tags,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {}, status=200,
+ namespace="OS::Compute::Hypervisor")
diff --git a/tools/skip_tracker.py b/tools/skip_tracker.py
index 55f41a6..9735f77 100755
--- a/tools/skip_tracker.py
+++ b/tools/skip_tracker.py
@@ -20,23 +20,25 @@
is fixed but a skip is still in the Tempest test code
"""
-import logging
import os
import re
from launchpadlib import launchpad
+from oslo_log import log as logging
BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
TESTDIR = os.path.join(BASEDIR, 'tempest')
LPCACHEDIR = os.path.expanduser('~/.launchpadlib/cache')
+LOG = logging.getLogger(__name__)
+
def info(msg, *args, **kwargs):
- logging.info(msg, *args, **kwargs)
+ LOG.info(msg, *args, **kwargs)
def debug(msg, *args, **kwargs):
- logging.debug(msg, *args, **kwargs)
+ LOG.debug(msg, *args, **kwargs)
def find_skips(start=TESTDIR):
@@ -102,8 +104,6 @@
if __name__ == '__main__':
- logging.basicConfig(format='%(levelname)s: %(message)s',
- level=logging.INFO)
results = find_skips()
unique_bugs = sorted(set([bug for (method, bug) in get_results(results)]))
unskips = []