Merge "Fix KeyError exc in volumes_client"
diff --git a/.zuul.yaml b/.zuul.yaml
index f7a22ba..9c53ba9 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -180,6 +180,7 @@
USE_PYTHON3: true
FORCE_CONFIG_DRIVE: true
ENABLE_VOLUME_MULTIATTACH: true
+ GLANCE_USE_IMPORT_WORKFLOW: True
devstack_services:
s-account: false
s-container: false
@@ -270,6 +271,7 @@
USE_PYTHON3: true
FORCE_CONFIG_DRIVE: true
ENABLE_VOLUME_MULTIATTACH: true
+ GLANCE_USE_IMPORT_WORKFLOW: True
- job:
name: tempest-integrated-object-storage
diff --git a/releasenotes/notes/image_import_testing_support-22ba4bcb9f2fb848.yaml b/releasenotes/notes/image_import_testing_support-22ba4bcb9f2fb848.yaml
new file mode 100644
index 0000000..b0180cc
--- /dev/null
+++ b/releasenotes/notes/image_import_testing_support-22ba4bcb9f2fb848.yaml
@@ -0,0 +1,17 @@
+---
+features:
+ - |
+ Add glance image import APIs function to v2
+ images_client library.
+
+ * stage_image_file
+ * info_import
+ * info_stores
+ * image_import
+other:
+ - |
+ New configuration options
+ ``CONF.glance.image_feature_enabled.image_import`` has been introduced
+ to enable the image import tests. If your glance deployement support
+ image import functionality then you can enable the image import tests
+ via this flag. Default value of this new config option is false.
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
index d5adfed..7b115ce 100644
--- a/tempest/api/compute/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -49,7 +49,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('86a1cb14-da37-4a70-b056-903fd56dfe29')
def test_aggregate_create_as_user(self):
- # Regular user is not allowed to create an aggregate.
+ """Regular user is not allowed to create an aggregate"""
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
self.assertRaises(lib_exc.Forbidden,
self.aggregates_client.create_aggregate,
@@ -58,7 +58,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('3b8a1929-3793-4e92-bcb4-dfa572ee6c1d')
def test_aggregate_create_aggregate_name_length_less_than_1(self):
- # the length of aggregate name should >= 1 and <=255
+ """The length of aggregate name should >=1"""
self.assertRaises(lib_exc.BadRequest,
self.client.create_aggregate,
name='')
@@ -66,7 +66,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('4c194563-543b-4e70-a719-557bbe947fac')
def test_aggregate_create_aggregate_name_length_exceeds_255(self):
- # the length of aggregate name should >= 1 and <=255
+ """The length of aggregate name should <=255"""
aggregate_name = 'a' * 256
self.assertRaises(lib_exc.BadRequest,
self.client.create_aggregate,
@@ -75,7 +75,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('9c23a291-b0b1-487b-b464-132e061151b3')
def test_aggregate_create_with_existent_aggregate_name(self):
- # creating an aggregate with existent aggregate name is forbidden
+ """Creating an aggregate with existent aggregate name is forbidden"""
aggregate = self._create_test_aggregate()
self.assertRaises(lib_exc.Conflict,
self.client.create_aggregate,
@@ -84,7 +84,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('cd6de795-c15d-45f1-8d9e-813c6bb72a3d')
def test_aggregate_delete_as_user(self):
- # Regular user is not allowed to delete an aggregate.
+ """Regular user is not allowed to delete an aggregate"""
aggregate = self._create_test_aggregate()
self.assertRaises(lib_exc.Forbidden,
self.aggregates_client.delete_aggregate,
@@ -93,14 +93,14 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('b7d475a6-5dcd-4ff4-b70a-cd9de66a6672')
def test_aggregate_list_as_user(self):
- # Regular user is not allowed to list aggregates.
+ """Regular user is not allowed to list aggregates"""
self.assertRaises(lib_exc.Forbidden,
self.aggregates_client.list_aggregates)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('557cad12-34c9-4ff4-95f0-22f0dfbaf7dc')
def test_aggregate_get_details_as_user(self):
- # Regular user is not allowed to get aggregate details.
+ """Regular user is not allowed to get aggregate details"""
aggregate = self._create_test_aggregate()
self.assertRaises(lib_exc.Forbidden,
self.aggregates_client.show_aggregate,
@@ -109,21 +109,21 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('c74f4bf1-4708-4ff2-95a0-f49eaca951bd')
def test_aggregate_delete_with_invalid_id(self):
- # Delete an aggregate with invalid id should raise exceptions.
+ """Delete an aggregate with invalid id should raise exceptions"""
self.assertRaises(lib_exc.NotFound,
self.client.delete_aggregate, -1)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('3c916244-2c46-49a4-9b55-b20bb0ae512c')
def test_aggregate_get_details_with_invalid_id(self):
- # Get aggregate details with invalid id should raise exceptions.
+ """Get aggregate details with invalid id should raise exceptions"""
self.assertRaises(lib_exc.NotFound,
self.client.show_aggregate, -1)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('0ef07828-12b4-45ba-87cc-41425faf5711')
def test_aggregate_add_non_exist_host(self):
- # Adding a non-exist host to an aggregate should raise exceptions.
+ """Adding a non-exist host to an aggregate should fail"""
while True:
non_exist_host = data_utils.rand_name('nonexist_host')
if non_exist_host not in self.hosts:
@@ -135,7 +135,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7324c334-bd13-4c93-8521-5877322c3d51')
def test_aggregate_add_host_as_user(self):
- # Regular user is not allowed to add a host to an aggregate.
+ """Regular user is not allowed to add a host to an aggregate"""
aggregate = self._create_test_aggregate()
self.assertRaises(lib_exc.Forbidden,
self.aggregates_client.add_host,
@@ -144,7 +144,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('19dd44e1-c435-4ee1-a402-88c4f90b5950')
def test_aggregate_add_existent_host(self):
- # Adding already existing host to aggregate should fail.
+ """Adding already existing host to aggregate should fail"""
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate = self._create_test_aggregate()
@@ -158,7 +158,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7a53af20-137a-4e44-a4ae-e19260e626d9')
def test_aggregate_remove_host_as_user(self):
- # Regular user is not allowed to remove a host from an aggregate.
+ """Regular user is not allowed to remove a host from an aggregate"""
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate = self._create_test_aggregate()
@@ -173,7 +173,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('95d6a6fa-8da9-4426-84d0-eec0329f2e4d')
def test_aggregate_remove_nonexistent_host(self):
- # Removing not existing host from aggregate should fail.
+ """Removing not existing host from aggregate should fail"""
aggregate = self._create_test_aggregate()
self.assertRaises(lib_exc.NotFound, self.client.remove_host,
diff --git a/tempest/api/compute/admin/test_create_server.py b/tempest/api/compute/admin/test_create_server.py
index 711b441..c4a8bf5 100644
--- a/tempest/api/compute/admin/test_create_server.py
+++ b/tempest/api/compute/admin/test_create_server.py
@@ -27,6 +27,8 @@
class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest):
+ """Test creating servers with specific flavor"""
+
@classmethod
def setup_credentials(cls):
cls.prepare_instance_network()
@@ -41,7 +43,7 @@
@testtools.skipUnless(CONF.validation.run_validation,
'Instance validation tests are disabled.')
def test_verify_created_server_ephemeral_disk(self):
- # Verify that the ephemeral disk is created when creating server
+ """Verify that the ephemeral disk is created when creating server"""
flavor_base = self.flavors_client.show_flavor(
self.flavor_ref)['flavor']
diff --git a/tempest/api/compute/admin/test_delete_server.py b/tempest/api/compute/admin/test_delete_server.py
index 58cac57..c625939 100644
--- a/tempest/api/compute/admin/test_delete_server.py
+++ b/tempest/api/compute/admin/test_delete_server.py
@@ -19,6 +19,8 @@
class DeleteServersAdminTestJSON(base.BaseV2ComputeAdminTest):
+ """Test deletion of servers"""
+
# NOTE: Server creations of each test class should be under 10
# for preventing "Quota exceeded for instances".
@@ -30,7 +32,7 @@
@decorators.idempotent_id('99774678-e072-49d1-9d2a-49a59bc56063')
def test_delete_server_while_in_error_state(self):
- # Delete a server while it's VM state is error
+ """Delete a server while it's VM state is error"""
server = self.create_test_server(wait_until='ACTIVE')
self.admin_client.reset_state(server['id'], state='error')
# Verify server's state
@@ -43,7 +45,7 @@
@decorators.idempotent_id('73177903-6737-4f27-a60c-379e8ae8cf48')
def test_admin_delete_servers_of_others(self):
- # Administrator can delete servers of others
+ """Administrator can delete servers of others"""
server = self.create_test_server(wait_until='ACTIVE')
self.admin_client.delete_server(server['id'])
waiters.wait_for_server_termination(self.servers_client, server['id'])
diff --git a/tempest/api/compute/servers/test_availability_zone.py b/tempest/api/compute/servers/test_availability_zone.py
index 36828d6..d239149 100644
--- a/tempest/api/compute/servers/test_availability_zone.py
+++ b/tempest/api/compute/servers/test_availability_zone.py
@@ -27,6 +27,6 @@
@decorators.idempotent_id('a8333aa2-205c-449f-a828-d38c2489bf25')
def test_get_availability_zone_list_with_non_admin_user(self):
- # List of availability zone with non-administrator user
+ """List of availability zone with non-administrator user"""
availability_zone = self.client.list_availability_zones()
self.assertNotEmpty(availability_zone['availabilityZoneInfo'])
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 4f0dbad..48f32a8 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -27,6 +27,11 @@
class ServersTestJSON(base.BaseV2ComputeTest):
+ """Test creating server and verifying the server attributes
+
+ This is to create server booted from image and with disk_config 'AUTO'
+ """
+
disk_config = 'AUTO'
volume_backed = False
@@ -62,13 +67,12 @@
disk_config=disk_config,
adminPass=cls.password,
volume_backed=cls.volume_backed)
- cls.server = (cls.client.show_server(server_initial['id'])
- ['server'])
+ cls.server = cls.client.show_server(server_initial['id'])['server']
@decorators.attr(type='smoke')
@decorators.idempotent_id('5de47127-9977-400a-936f-abcfbec1218f')
def test_verify_server_details(self):
- # Verify the specified server attributes are set correctly
+ """Verify the specified server attributes are set correctly"""
self.assertEqual(self.accessIPv4, self.server['accessIPv4'])
# NOTE(maurosr): See http://tools.ietf.org/html/rfc5952 (section 4)
# Here we compare directly with the canonicalized format.
@@ -86,7 +90,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('9a438d88-10c6-4bcd-8b5b-5b6e25e1346f')
def test_list_servers(self):
- # The created server should be in the list of all servers
+ """The created server should be in the list of all servers"""
body = self.client.list_servers()
servers = body['servers']
found = [i for i in servers if i['id'] == self.server['id']]
@@ -94,7 +98,7 @@
@decorators.idempotent_id('585e934c-448e-43c4-acbf-d06a9b899997')
def test_list_servers_with_detail(self):
- # The created server should be in the detailed list of all servers
+ """The created server should be in the detailed list of all servers"""
body = self.client.list_servers(detail=True)
servers = body['servers']
found = [i for i in servers if i['id'] == self.server['id']]
@@ -104,8 +108,11 @@
@testtools.skipUnless(CONF.validation.run_validation,
'Instance validation tests are disabled.')
def test_verify_created_server_vcpus(self):
- # Verify that the number of vcpus reported by the instance matches
- # the amount stated by the flavor
+ """The created server should have the same specification as the flavor
+
+ Verify that the number of vcpus reported by the instance matches
+ the amount stated by the flavor
+ """
flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor']
validation_resources = self.get_class_validation_resources(
self.os_primary)
@@ -123,7 +130,7 @@
@testtools.skipUnless(CONF.validation.run_validation,
'Instance validation tests are disabled.')
def test_host_name_is_same_as_server_name(self):
- # Verify the instance host name is the same as the server name
+ """Verify the instance host name is the same as the server name"""
validation_resources = self.get_class_validation_resources(
self.os_primary)
linux_client = remote_client.RemoteClient(
@@ -145,6 +152,10 @@
class ServersTestManualDisk(ServersTestJSON):
+ """Test creating server and verifying the server attributes
+
+ This is to create server booted from image and with disk_config 'MANUAL'
+ """
disk_config = 'MANUAL'
@classmethod
@@ -156,7 +167,11 @@
class ServersTestBootFromVolume(ServersTestJSON):
- """Run the `ServersTestJSON` tests with a volume backed VM"""
+ """Test creating server and verifying the server attributes
+
+ This is to create server booted from volume and with disk_config 'AUTO'
+ """
+ # Run the `ServersTestJSON` tests with a volume backed VM
volume_backed = True
@classmethod
diff --git a/tempest/api/compute/servers/test_disk_config.py b/tempest/api/compute/servers/test_disk_config.py
index 5b8e7ab..e5e051a 100644
--- a/tempest/api/compute/servers/test_disk_config.py
+++ b/tempest/api/compute/servers/test_disk_config.py
@@ -24,6 +24,8 @@
class ServerDiskConfigTestJSON(base.BaseV2ComputeTest):
+ """Test disk config option of server"""
+
create_default_network = True
@classmethod
@@ -49,7 +51,7 @@
@decorators.idempotent_id('bef56b09-2e8c-4883-a370-4950812f430e')
def test_rebuild_server_with_manual_disk_config(self):
- # A server should be rebuilt using the manual disk config option
+ """A server should be rebuilt using the manual disk config option"""
server = self.create_test_server(wait_until='ACTIVE')
self.addCleanup(self.client.delete_server, server['id'])
self._update_server_with_disk_config(server['id'],
@@ -68,7 +70,7 @@
@decorators.idempotent_id('9c9fae77-4feb-402f-8450-bf1c8b609713')
def test_rebuild_server_with_auto_disk_config(self):
- # A server should be rebuilt using the auto disk config option
+ """A server should be rebuilt using the auto disk config option"""
server = self.create_test_server(wait_until='ACTIVE')
self.addCleanup(self.client.delete_server, server['id'])
self._update_server_with_disk_config(server['id'],
@@ -89,7 +91,7 @@
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
'Resize not available.')
def test_resize_server_from_manual_to_auto(self):
- # A server should be resized from manual to auto disk config
+ """A server should be resized from manual to auto disk config"""
server = self.create_test_server(wait_until='ACTIVE')
self.addCleanup(self.client.delete_server, server['id'])
self._update_server_with_disk_config(server['id'],
@@ -105,7 +107,7 @@
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
'Resize not available.')
def test_resize_server_from_auto_to_manual(self):
- # A server should be resized from auto to manual disk config
+ """A server should be resized from auto to manual disk config"""
server = self.create_test_server(wait_until='ACTIVE')
self.addCleanup(self.client.delete_server, server['id'])
self._update_server_with_disk_config(server['id'],
@@ -119,7 +121,7 @@
@decorators.idempotent_id('5ef18867-358d-4de9-b3c9-94d4ba35742f')
def test_update_server_from_auto_to_manual(self):
- # A server should be updated from auto to manual disk config
+ """A server should be updated from auto to manual disk config"""
server = self.create_test_server(wait_until='ACTIVE')
self.addCleanup(self.client.delete_server, server['id'])
self._update_server_with_disk_config(server['id'],
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 3dffd01..7f62c64 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -26,6 +26,7 @@
class ListServerFiltersTestJSON(base.BaseV2ComputeTest):
+ """Test listing servers filtered by specified attribute"""
@classmethod
def setup_credentials(cls):
@@ -71,7 +72,7 @@
@testtools.skipUnless(CONF.compute.image_ref != CONF.compute.image_ref_alt,
"Need distinct images to run this test")
def test_list_servers_filter_by_image(self):
- # Filter the list of servers by image
+ """Filter the list of servers by image"""
params = {'image': self.image_ref}
body = self.client.list_servers(**params)
servers = body['servers']
@@ -82,7 +83,7 @@
@decorators.idempotent_id('573637f5-7325-47bb-9144-3476d0416908')
def test_list_servers_filter_by_flavor(self):
- # Filter the list of servers by flavor
+ """Filter the list of servers by flavor"""
params = {'flavor': self.flavor_ref_alt}
body = self.client.list_servers(**params)
servers = body['servers']
@@ -93,7 +94,7 @@
@decorators.idempotent_id('9b067a7b-7fee-4f6a-b29c-be43fe18fc5a')
def test_list_servers_filter_by_server_name(self):
- # Filter the list of servers by server name
+ """Filter the list of servers by server name"""
params = {'name': self.s1_name}
body = self.client.list_servers(**params)
servers = body['servers']
@@ -104,7 +105,7 @@
@decorators.idempotent_id('ca78e20e-fddb-4ce6-b7f7-bcbf8605e66e')
def test_list_servers_filter_by_active_status(self):
- # Filter the list of servers by server active status
+ """Filter the list of servers by server active status"""
params = {'status': 'active'}
body = self.client.list_servers(**params)
servers = body['servers']
@@ -115,7 +116,7 @@
@decorators.idempotent_id('451dbbb2-f330-4a9f-b0e1-5f5d2cb0f34c')
def test_list_servers_filter_by_shutoff_status(self):
- # Filter the list of servers by server shutoff status
+ """Filter the list of servers by server shutoff status"""
params = {'status': 'shutoff'}
self.client.stop_server(self.s1['id'])
waiters.wait_for_server_status(self.client, self.s1['id'],
@@ -132,21 +133,30 @@
@decorators.idempotent_id('614cdfc1-d557-4bac-915b-3e67b48eee76')
def test_list_servers_filter_by_limit(self):
- # Verify only the expected number of servers are returned
+ """Filter the list of servers by limit 1
+
+ Verify only the expected number of servers are returned (one server)
+ """
params = {'limit': 1}
servers = self.client.list_servers(**params)
self.assertEqual(1, len([x for x in servers['servers'] if 'id' in x]))
@decorators.idempotent_id('b1495414-2d93-414c-8019-849afe8d319e')
def test_list_servers_filter_by_zero_limit(self):
- # Verify only the expected number of servers are returned
+ """Filter the list of servers by limit 0
+
+ Verify only the expected number of servers are returned (no server)
+ """
params = {'limit': 0}
servers = self.client.list_servers(**params)
self.assertEmpty(servers['servers'])
@decorators.idempotent_id('37791bbd-90c0-4de0-831e-5f38cba9c6b3')
def test_list_servers_filter_by_exceed_limit(self):
- # Verify only the expected number of servers are returned
+ """Filter the list of servers by exceeded limit
+
+ Verify only the expected number of servers are returned (all servers)
+ """
params = {'limit': 100000}
servers = self.client.list_servers(**params)
all_servers = self.client.list_servers()
@@ -157,7 +167,7 @@
@testtools.skipUnless(CONF.compute.image_ref != CONF.compute.image_ref_alt,
"Need distinct images to run this test")
def test_list_servers_detailed_filter_by_image(self):
- # Filter the detailed list of servers by image
+ """"Filter the detailed list of servers by image"""
params = {'image': self.image_ref}
body = self.client.list_servers(detail=True, **params)
servers = body['servers']
@@ -168,7 +178,7 @@
@decorators.idempotent_id('80c574cc-0925-44ba-8602-299028357dd9')
def test_list_servers_detailed_filter_by_flavor(self):
- # Filter the detailed list of servers by flavor
+ """Filter the detailed list of servers by flavor"""
params = {'flavor': self.flavor_ref_alt}
body = self.client.list_servers(detail=True, **params)
servers = body['servers']
@@ -179,7 +189,7 @@
@decorators.idempotent_id('f9eb2b70-735f-416c-b260-9914ac6181e4')
def test_list_servers_detailed_filter_by_server_name(self):
- # Filter the detailed list of servers by server name
+ """Filter the detailed list of servers by server name"""
params = {'name': self.s1_name}
body = self.client.list_servers(detail=True, **params)
servers = body['servers']
@@ -190,7 +200,7 @@
@decorators.idempotent_id('de2612ab-b7dd-4044-b0b1-d2539601911f')
def test_list_servers_detailed_filter_by_server_status(self):
- # Filter the detailed list of servers by server status
+ """Filter the detailed list of servers by server status"""
params = {'status': 'active'}
body = self.client.list_servers(detail=True, **params)
servers = body['servers']
@@ -204,6 +214,7 @@
@decorators.idempotent_id('e9f624ee-92af-4562-8bec-437945a18dcb')
def test_list_servers_filtered_by_name_wildcard(self):
+ """Filter the list of servers by part of server name"""
# List all servers that contains '-instance' in name
params = {'name': '-instance'}
body = self.client.list_servers(**params)
@@ -226,6 +237,7 @@
@decorators.idempotent_id('24a89b0c-0d55-4a28-847f-45075f19b27b')
def test_list_servers_filtered_by_name_regex(self):
+ """Filter the list of servers by server name regular expression"""
# list of regex that should match s1, s2 and s3
regexes = [r'^.*\-instance\-[0-9]+$', r'^.*\-instance\-.*$']
for regex in regexes:
@@ -250,7 +262,7 @@
@decorators.idempotent_id('43a1242e-7b31-48d1-88f2-3f72aa9f2077')
def test_list_servers_filtered_by_ip(self):
- # Filter servers by ip
+ """Filter the list of servers by server ip address"""
# Here should be listed 1 server
if not self.fixed_network_name:
msg = 'fixed_network_name needs to be configured to run this test'
@@ -287,8 +299,7 @@
@decorators.skip_because(bug="1540645")
@decorators.idempotent_id('a905e287-c35e-42f2-b132-d02b09f3654a')
def test_list_servers_filtered_by_ip_regex(self):
- # Filter servers by regex ip
- # List all servers filtered by part of ip address.
+ """Filter the list of servers by part of server ip address"""
# Here should be listed all servers
if not self.fixed_network_name:
msg = 'fixed_network_name needs to be configured to run this test'
@@ -317,7 +328,10 @@
@decorators.idempotent_id('67aec2d0-35fe-4503-9f92-f13272b867ed')
def test_list_servers_detailed_limit_results(self):
- # Verify only the expected number of detailed results are returned
+ """Filter the detailed list of servers by limit 1
+
+ Verify only the expected number of servers are returned (one server)
+ """
params = {'limit': 1}
servers = self.client.list_servers(detail=True, **params)
self.assertEqual(1, len(servers['servers']))
diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
index 68e09e7..7931ca9 100644
--- a/tempest/api/compute/servers/test_novnc.py
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -33,6 +33,8 @@
class NoVNCConsoleTestJSON(base.BaseV2ComputeTest):
+ """Test novnc console"""
+
create_default_network = True
@classmethod
@@ -181,6 +183,7 @@
@decorators.idempotent_id('c640fdff-8ab4-45a4-a5d8-7e6146cbd0dc')
def test_novnc(self):
+ """Test accessing novnc console of server"""
if self.use_get_remote_console:
body = self.client.get_remote_console(
self.server['id'], console_type='novnc',
@@ -200,6 +203,11 @@
@decorators.idempotent_id('f9c79937-addc-4aaa-9e0e-841eef02aeb7')
def test_novnc_bad_token(self):
+ """Test accessing novnc console with bad token
+
+ Do the WebSockify HTTP Request to novnc proxy with a bad token,
+ the novnc proxy should reject the connection and closed it.
+ """
if self.use_get_remote_console:
body = self.client.get_remote_console(
self.server['id'], console_type='novnc',
diff --git a/tempest/api/compute/servers/test_server_addresses_negative.py b/tempest/api/compute/servers/test_server_addresses_negative.py
index f33c6d9..e7444d2 100644
--- a/tempest/api/compute/servers/test_server_addresses_negative.py
+++ b/tempest/api/compute/servers/test_server_addresses_negative.py
@@ -20,6 +20,7 @@
class ServerAddressesNegativeTestJSON(base.BaseV2ComputeTest):
+ """Negative tests of listing server addresses"""
create_default_network = True
@classmethod
@@ -36,7 +37,7 @@
@decorators.idempotent_id('02c3f645-2d2e-4417-8525-68c0407d001b')
@utils.services('network')
def test_list_server_addresses_invalid_server_id(self):
- # List addresses request should fail if server id not in system
+ """List addresses request should fail if server id not in system"""
self.assertRaises(lib_exc.NotFound, self.client.list_addresses,
'999')
@@ -44,7 +45,7 @@
@decorators.idempotent_id('a2ab5144-78c0-4942-a0ed-cc8edccfd9ba')
@utils.services('network')
def test_list_server_addresses_by_network_neg(self):
- # List addresses by network should fail if network name not valid
+ """List addresses by network should fail if network name not valid"""
self.assertRaises(lib_exc.NotFound,
self.client.list_addresses_by_network,
self.server['id'], 'invalid')
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index 4f484e2..ba2adbb 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -28,6 +28,7 @@
class ServerPersonalityTestJSON(base.BaseV2ComputeTest):
+ """Test servers with injected files"""
@classmethod
def setup_credentials(cls):
@@ -51,6 +52,7 @@
@decorators.attr(type='slow')
@decorators.idempotent_id('3cfe87fd-115b-4a02-b942-7dc36a337fdf')
def test_create_server_with_personality(self):
+ """Test creating server with file injection"""
file_contents = 'This is a test file.'
file_path = '/test.txt'
personality = [{'path': file_path,
@@ -85,6 +87,7 @@
@decorators.attr(type='slow')
@decorators.idempotent_id('128966d8-71fc-443c-8cab-08e24114ecc9')
def test_rebuild_server_with_personality(self):
+ """Test injecting file when rebuilding server"""
validation_resources = self.get_test_validation_resources(
self.os_primary)
server = self.create_test_server(
@@ -107,8 +110,11 @@
@decorators.idempotent_id('176cd8c9-b9e8-48ee-a480-180beab292bf')
def test_personality_files_exceed_limit(self):
- # Server creation should fail if greater than the maximum allowed
- # number of files are injected into the server.
+ """Test creating server with injected files over limitation
+
+ Server creation should fail if greater than the maximum allowed
+ number of files are injected into the server.
+ """
file_contents = 'This is a test file.'
personality = []
limits = self.limits_client.show_limits()['limits']
@@ -131,8 +137,11 @@
@decorators.attr(type='slow')
@decorators.idempotent_id('52f12ee8-5180-40cc-b417-31572ea3d555')
def test_can_create_server_with_max_number_personality_files(self):
- # Server should be created successfully if maximum allowed number of
- # files is injected into the server during creation.
+ """Test creating server with maximum allowed number of injected files
+
+ Server should be created successfully if maximum allowed number of
+ files is injected into the server during creation.
+ """
file_contents = 'This is a test file.'
limits = self.limits_client.show_limits()['limits']
max_file_limit = limits['absolute']['maxPersonality']
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index caceb64..9bcf062 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -27,6 +27,7 @@
class ServerRescueNegativeTestJSON(base.BaseV2ComputeTest):
+ """Negative tests of server rescue"""
@classmethod
def skip_checks(cls):
@@ -75,7 +76,7 @@
'Pause is not available.')
@decorators.attr(type=['negative'])
def test_rescue_paused_instance(self):
- # Rescue a paused server
+ """Test rescuing a paused server should fail"""
self.servers_client.pause_server(self.server_id)
self.addCleanup(self._unpause, self.server_id)
waiters.wait_for_server_status(self.servers_client,
@@ -87,13 +88,14 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('db22b618-f157-4566-a317-1b6d467a8094')
def test_rescued_vm_reboot(self):
+ """Test rebooing a rescued server should fail"""
self.assertRaises(lib_exc.Conflict, self.servers_client.reboot_server,
self.rescue_id, type='HARD')
@decorators.attr(type=['negative'])
@decorators.idempotent_id('6dfc0a55-3a77-4564-a144-1587b7971dde')
def test_rescue_non_existent_server(self):
- # Rescue a non-existing server
+ """Test rescuing a non-existing server should fail"""
non_existent_server = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound,
self.servers_client.rescue_server,
@@ -102,6 +104,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('70cdb8a1-89f8-437d-9448-8844fd82bf46')
def test_rescued_vm_rebuild(self):
+ """Test rebuilding a rescued server should fail"""
self.assertRaises(lib_exc.Conflict,
self.servers_client.rebuild_server,
self.rescue_id,
@@ -111,6 +114,7 @@
@utils.services('volume')
@decorators.attr(type=['negative'])
def test_rescued_vm_attach_volume(self):
+ """Test attaching volume to a rescued server should fail"""
volume = self.create_volume()
# Rescue the server
@@ -130,6 +134,7 @@
@utils.services('volume')
@decorators.attr(type=['negative'])
def test_rescued_vm_detach_volume(self):
+ """Test detaching volume from a rescued server should fail"""
volume = self.create_volume()
# Attach the volume to the server
diff --git a/tempest/api/compute/servers/test_server_tags.py b/tempest/api/compute/servers/test_server_tags.py
index 3893b01..619f480 100644
--- a/tempest/api/compute/servers/test_server_tags.py
+++ b/tempest/api/compute/servers/test_server_tags.py
@@ -22,6 +22,7 @@
class ServerTagsTestJSON(base.BaseV2ComputeTest):
+ """Test server tags with compute microversion greater than 2.25"""
min_microversion = '2.26'
max_microversion = 'latest'
@@ -54,6 +55,7 @@
@decorators.idempotent_id('8d95abe2-c658-4c42-9a44-c0258500306b')
def test_create_delete_tag(self):
+ """Test creating and deleting server tag"""
# Check that no tags exist.
fetched_tags = self.client.list_tags(self.server['id'])['tags']
self.assertEmpty(fetched_tags)
@@ -73,6 +75,7 @@
@decorators.idempotent_id('a2c1af8c-127d-417d-974b-8115f7e3d831')
def test_update_all_tags(self):
+ """Test updating all server tags"""
# Add server tags to the server.
tags = [data_utils.rand_name('tag'), data_utils.rand_name('tag')]
self._update_server_tags(self.server['id'], tags)
@@ -89,6 +92,7 @@
@decorators.idempotent_id('a63b2a74-e918-4b7c-bcab-10c855f3a57e')
def test_delete_all_tags(self):
+ """Test deleting all server tags"""
# Add server tags to the server.
assigned_tags = [data_utils.rand_name('tag'),
data_utils.rand_name('tag')]
@@ -101,6 +105,7 @@
@decorators.idempotent_id('81279a66-61c3-4759-b830-a2dbe64cbe08')
def test_check_tag_existence(self):
+ """Test checking server tag existence"""
# Add server tag to the server.
assigned_tag = data_utils.rand_name('tag')
self._update_server_tags(self.server['id'], assigned_tag)
diff --git a/tempest/api/identity/admin/v2/test_services.py b/tempest/api/identity/admin/v2/test_services.py
index 03543ac..182b24c 100644
--- a/tempest/api/identity/admin/v2/test_services.py
+++ b/tempest/api/identity/admin/v2/test_services.py
@@ -20,6 +20,7 @@
class ServicesTestJSON(base.BaseIdentityV2AdminTest):
+ """Test identity services via v2 API"""
def _del_service(self, service_id):
# Deleting the service created in this method
@@ -30,6 +31,7 @@
@decorators.idempotent_id('84521085-c6e6-491c-9a08-ec9f70f90110')
def test_create_get_delete_service(self):
+ """Test verifies the identity service create/get/delete via v2 API"""
# GET Service
# Creating a Service
name = data_utils.rand_name('service')
@@ -64,7 +66,10 @@
@decorators.idempotent_id('5d3252c8-e555-494b-a6c8-e11d7335da42')
def test_create_service_without_description(self):
- # Create a service only with name and type
+ """Test creating identity service without description via v2 API
+
+ Create a service only with name and type.
+ """
name = data_utils.rand_name('service')
s_type = data_utils.rand_name('type')
service = self.services_client.create_service(
@@ -79,7 +84,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('34ea6489-012d-4a86-9038-1287cadd5eca')
def test_list_services(self):
- # Create, List, Verify and Delete Services
+ """Test Create/List/Verify/Delete of identity service via v2 API"""
services = []
for _ in range(3):
name = data_utils.rand_name('service')
diff --git a/tempest/api/identity/admin/v2/test_tenants.py b/tempest/api/identity/admin/v2/test_tenants.py
index f68754e..5f73e1c 100644
--- a/tempest/api/identity/admin/v2/test_tenants.py
+++ b/tempest/api/identity/admin/v2/test_tenants.py
@@ -19,10 +19,14 @@
class TenantsTestJSON(base.BaseIdentityV2AdminTest):
+ """Test identity tenants via v2 API"""
@decorators.idempotent_id('16c6e05c-6112-4b0e-b83f-5e43f221b6b0')
def test_tenant_list_delete(self):
- # Create several tenants and delete them
+ """Test listing and deleting tenants via v2 API
+
+ Create several tenants and delete them
+ """
tenants = []
for _ in range(3):
tenant = self.setup_test_tenant()
@@ -41,7 +45,7 @@
@decorators.idempotent_id('d25e9f24-1310-4d29-b61b-d91299c21d6d')
def test_tenant_create_with_description(self):
- # Create tenant with a description
+ """Test creating tenant with a description via v2 API"""
tenant_desc = data_utils.rand_name(name='desc')
tenant = self.setup_test_tenant(description=tenant_desc)
tenant_id = tenant['id']
@@ -56,7 +60,7 @@
@decorators.idempotent_id('670bdddc-1cd7-41c7-b8e2-751cfb67df50')
def test_tenant_create_enabled(self):
- # Create a tenant that is enabled
+ """Test creating a tenant that is enabled via v2 API"""
tenant = self.setup_test_tenant(enabled=True)
tenant_id = tenant['id']
self.assertTrue(tenant['enabled'], 'Enable should be True in response')
@@ -66,7 +70,7 @@
@decorators.idempotent_id('3be22093-b30f-499d-b772-38340e5e16fb')
def test_tenant_create_not_enabled(self):
- # Create a tenant that is not enabled
+ """Test creating a tenant that is not enabled via v2 API"""
tenant = self.setup_test_tenant(enabled=False)
tenant_id = tenant['id']
self.assertFalse(tenant['enabled'],
@@ -78,7 +82,7 @@
@decorators.idempotent_id('781f2266-d128-47f3-8bdb-f70970add238')
def test_tenant_update_name(self):
- # Update name attribute of a tenant
+ """Test updating name attribute of a tenant via v2 API"""
t_name1 = data_utils.rand_name(name='tenant')
tenant = self.setup_test_tenant(name=t_name1)
t_id = tenant['id']
@@ -100,7 +104,7 @@
@decorators.idempotent_id('859fcfe1-3a03-41ef-86f9-b19a47d1cd87')
def test_tenant_update_desc(self):
- # Update description attribute of a tenant
+ """Test updating description attribute of a tenant via v2 API"""
t_desc = data_utils.rand_name(name='desc')
tenant = self.setup_test_tenant(description=t_desc)
t_id = tenant['id']
@@ -123,7 +127,7 @@
@decorators.idempotent_id('8fc8981f-f12d-4c66-9972-2bdcf2bc2e1a')
def test_tenant_update_enable(self):
- # Update the enabled attribute of a tenant
+ """Test updating the enabled attribute of a tenant via v2 API"""
t_en = False
tenant = self.setup_test_tenant(enabled=t_en)
t_id = tenant['id']
diff --git a/tempest/api/identity/admin/v2/test_users_negative.py b/tempest/api/identity/admin/v2/test_users_negative.py
index 4f47e41..eda1fdd 100644
--- a/tempest/api/identity/admin/v2/test_users_negative.py
+++ b/tempest/api/identity/admin/v2/test_users_negative.py
@@ -20,6 +20,7 @@
class UsersNegativeTestJSON(base.BaseIdentityV2AdminTest):
+ """Negative tests of identity users via v2 API"""
@classmethod
def resource_setup(cls):
@@ -31,7 +32,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('60a1f5fa-5744-4cdf-82bf-60b7de2d29a4')
def test_create_user_by_unauthorized_user(self):
- # Non-administrator should not be authorized to create a user
+ """Non-admin should not be authorized to create a user via v2 API"""
tenant = self.setup_test_tenant()
self.assertRaises(lib_exc.Forbidden,
self.non_admin_users_client.create_user,
@@ -42,7 +43,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d80d0c2f-4514-4d1e-806d-0930dfc5a187')
def test_create_user_with_empty_name(self):
- # User with an empty name should not be created
+ """User with an empty name should not be created via v2 API"""
tenant = self.setup_test_tenant()
self.assertRaises(lib_exc.BadRequest, self.users_client.create_user,
name='', password=self.alt_password,
@@ -52,7 +53,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7704b4f3-3b75-4b82-87cc-931d41c8f780')
def test_create_user_with_name_length_over_255(self):
- # Length of user name filed should be restricted to 255 characters
+ """Length of user name should not exceed 255 via v2 API"""
tenant = self.setup_test_tenant()
self.assertRaises(lib_exc.BadRequest, self.users_client.create_user,
name='a' * 256, password=self.alt_password,
@@ -62,7 +63,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('57ae8558-120c-4723-9308-3751474e7ecf')
def test_create_user_with_duplicate_name(self):
- # Duplicate user should not be created
+ """Duplicate user should not be created via v2 API"""
password = data_utils.rand_password()
user = self.setup_test_user(password)
tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant']
@@ -75,7 +76,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('0132cc22-7c4f-42e1-9e50-ac6aad31d59a')
def test_create_user_for_non_existent_tenant(self):
- # Attempt to create a user in a non-existent tenant should fail
+ """Creating a user in a non-existent tenant via v2 API should fail"""
self.assertRaises(lib_exc.NotFound, self.users_client.create_user,
name=self.alt_user,
password=self.alt_password,
@@ -85,7 +86,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('55bbb103-d1ae-437b-989b-bcdf8175c1f4')
def test_create_user_request_without_a_token(self):
- # Request to create a user without a valid token should fail
+ """Creating a user without a valid token via v2 API should fail"""
tenant = self.setup_test_tenant()
# Get the token of the current client
token = self.client.auth_provider.get_token()
@@ -103,7 +104,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('23a2f3da-4a1a-41da-abdd-632328a861ad')
def test_create_user_with_enabled_non_bool(self):
- # Attempt to create a user with valid enabled para should fail
+ """Creating a user with invalid enabled para via v2 API should fail"""
tenant = self.setup_test_tenant()
name = data_utils.rand_name('test_user')
self.assertRaises(lib_exc.BadRequest, self.users_client.create_user,
@@ -114,7 +115,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('3d07e294-27a0-4144-b780-a2a1bf6fee19')
def test_update_user_for_non_existent_user(self):
- # Attempt to update a user non-existent user should fail
+ """Updating a non-existent user via v2 API should fail"""
user_name = data_utils.rand_name('user')
non_existent_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound, self.users_client.update_user,
@@ -123,7 +124,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('3cc2a64b-83aa-4b02-88f0-d6ab737c4466')
def test_update_user_request_without_a_token(self):
- # Request to update a user without a valid token should fail
+ """Updating a user without a valid token via v2 API should fail"""
# Get the token of the current client
token = self.client.auth_provider.get_token()
@@ -139,7 +140,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('424868d5-18a7-43e1-8903-a64f95ee3aac')
def test_update_user_by_unauthorized_user(self):
- # Non-administrator should not be authorized to update user
+ """Non-admin should not be authorized to update user via v2 API"""
self.assertRaises(lib_exc.Forbidden,
self.non_admin_users_client.update_user,
self.alt_user)
@@ -147,7 +148,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d45195d5-33ed-41b9-a452-7d0d6a00f6e9')
def test_delete_users_by_unauthorized_user(self):
- # Non-administrator user should not be authorized to delete a user
+ """Non-admin should not be authorized to delete a user via v2 API"""
user = self.setup_test_user()
self.assertRaises(lib_exc.Forbidden,
self.non_admin_users_client.delete_user,
@@ -156,14 +157,14 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7cc82f7e-9998-4f89-abae-23df36495867')
def test_delete_non_existent_user(self):
- # Attempt to delete a non-existent user should fail
+ """Attempt to delete a non-existent user via v2 API should fail"""
self.assertRaises(lib_exc.NotFound, self.users_client.delete_user,
'junk12345123')
@decorators.attr(type=['negative'])
@decorators.idempotent_id('57fe1df8-0aa7-46c0-ae9f-c2e785c7504a')
def test_delete_user_request_without_a_token(self):
- # Request to delete a user without a valid token should fail
+ """Deleting a user without a valid token via v2 API should fail"""
# Get the token of the current client
token = self.client.auth_provider.get_token()
@@ -179,7 +180,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('593a4981-f6d4-460a-99a1-57a78bf20829')
def test_authentication_for_disabled_user(self):
- # Disabled user's token should not get authenticated
+ """Disabled user's token should not get authenticated via v2 API"""
password = data_utils.rand_password()
user = self.setup_test_user(password)
tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant']
@@ -192,7 +193,11 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('440a7a8d-9328-4b7b-83e0-d717010495e4')
def test_authentication_when_tenant_is_disabled(self):
- # User's token for a disabled tenant should not be authenticated
+ """Test User's token for a disabled tenant via v2 API
+
+ User's token for a disabled tenant should not be authenticated via
+ v2 API.
+ """
password = data_utils.rand_password()
user = self.setup_test_user(password)
tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant']
@@ -205,7 +210,11 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('921f1ad6-7907-40b8-853f-637e7ee52178')
def test_authentication_with_invalid_tenant(self):
- # User's token for an invalid tenant should not be authenticated
+ """Test User's token for an invalid tenant via v2 API
+
+ User's token for an invalid tenant should not be authenticated via V2
+ API.
+ """
password = data_utils.rand_password()
user = self.setup_test_user(password)
self.assertRaises(lib_exc.Unauthorized, self.token_client.auth,
@@ -216,7 +225,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('bde9aecd-3b1c-4079-858f-beb5deaa5b5e')
def test_authentication_with_invalid_username(self):
- # Non-existent user's token should not get authenticated
+ """Non-existent user's token should not get authorized via v2 API"""
password = data_utils.rand_password()
user = self.setup_test_user(password)
tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant']
@@ -226,7 +235,11 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d5308b33-3574-43c3-8d87-1c090c5e1eca')
def test_authentication_with_invalid_password(self):
- # User's token with invalid password should not be authenticated
+ """Test User's token with invalid password via v2 API
+
+ User's token with invalid password should not be authenticated via V2
+ API.
+ """
user = self.setup_test_user()
tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant']
self.assertRaises(lib_exc.Unauthorized, self.token_client.auth,
@@ -235,14 +248,14 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('284192ce-fb7c-4909-a63b-9a502e0ddd11')
def test_get_users_by_unauthorized_user(self):
- # Non-administrator user should not be authorized to get user list
+ """Non-admin should not be authorized to get user list via v2 API"""
self.assertRaises(lib_exc.Forbidden,
self.non_admin_users_client.list_users)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('a73591ec-1903-4ffe-be42-282b39fefc9d')
def test_get_users_request_without_token(self):
- # Request to get list of users without a valid token should fail
+ """Listing users without a valid token via v2 API should fail"""
token = self.client.auth_provider.get_token()
self.client.delete_token(token)
@@ -254,8 +267,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('f5d39046-fc5f-425c-b29e-bac2632da28e')
def test_list_users_with_invalid_tenant(self):
- # Should not be able to return a list of all
- # users for a non-existent tenant
+ """Listing users for a non-existent tenant via v2 API should fail"""
# Assign invalid tenant ids
invalid_id = list()
invalid_id.append(data_utils.rand_name('999'))
diff --git a/tempest/api/identity/admin/v3/test_application_credentials.py b/tempest/api/identity/admin/v3/test_application_credentials.py
index 7e802c6..c9cafd8 100644
--- a/tempest/api/identity/admin/v3/test_application_credentials.py
+++ b/tempest/api/identity/admin/v3/test_application_credentials.py
@@ -20,9 +20,11 @@
class ApplicationCredentialsV3AdminTest(base.BaseApplicationCredentialsV3Test,
base.BaseIdentityV3AdminTest):
+ """Test keystone application credentials"""
@decorators.idempotent_id('3b3dd48f-3388-406a-a9e6-4d078a552d0e')
def test_create_application_credential_with_roles(self):
+ """Test creating keystone application credential with roles"""
role = self.setup_test_role()
self.os_admin.roles_v3_client.create_user_role_on_project(
self.project_id,
diff --git a/tempest/api/identity/admin/v3/test_credentials.py b/tempest/api/identity/admin/v3/test_credentials.py
index 23fe788..441f10f 100644
--- a/tempest/api/identity/admin/v3/test_credentials.py
+++ b/tempest/api/identity/admin/v3/test_credentials.py
@@ -20,6 +20,8 @@
class CredentialsTestJSON(base.BaseIdentityV3AdminTest):
+ """Test keystone credentials"""
+
# NOTE: force_tenant_isolation is true in the base class by default but
# overridden to false here to allow test execution for clouds using the
# pre-provisioned credentials provider.
@@ -47,6 +49,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('7cd59bf9-bda4-4c72-9467-d21cab278355')
def test_credentials_create_get_update_delete(self):
+ """Test creating, getting, updating, deleting of credentials"""
blob = '{"access": "%s", "secret": "%s"}' % (
data_utils.rand_name('Access'), data_utils.rand_name('Secret'))
cred = self.creds_client.create_credential(
@@ -82,6 +85,7 @@
@decorators.idempotent_id('13202c00-0021-42a1-88d4-81b44d448aab')
def test_credentials_list_delete(self):
+ """Test listing credentials"""
created_cred_ids = list()
fetched_cred_ids = list()
diff --git a/tempest/api/identity/admin/v3/test_domain_configuration.py b/tempest/api/identity/admin/v3/test_domain_configuration.py
index c0b18ca..a246a36 100644
--- a/tempest/api/identity/admin/v3/test_domain_configuration.py
+++ b/tempest/api/identity/admin/v3/test_domain_configuration.py
@@ -21,6 +21,8 @@
class DomainConfigurationTestJSON(base.BaseIdentityV3AdminTest):
+ """Test domain configuration"""
+
# NOTE: force_tenant_isolation is true in the base class by default but
# overridden to false here to allow test execution for clouds using the
# pre-provisioned credentials provider.
@@ -51,10 +53,12 @@
@decorators.idempotent_id('11a02bf0-6f94-4380-b3b0-c8dc18fc0d22')
def test_show_default_group_config_and_options(self):
- # The API supports only the identity and ldap groups. For the ldap
- # group, a valid value is url or user_tree_dn. For the identity group,
- # a valid value is driver.
+ """Test showing default keystone group config and options
+ The API supports only the identity and ldap groups. For the ldap
+ group, a valid value is url or user_tree_dn. For the identity group,
+ a valid value is driver.
+ """
# Check that the default config has the identity and ldap groups.
config = self.client.show_default_config_settings()['config']
self.assertIsInstance(config, dict)
@@ -93,6 +97,7 @@
@decorators.idempotent_id('9e3ff13c-f597-4f01-9377-d6c06c2a1477')
def test_create_domain_config_and_show_config_groups_and_options(self):
+ """Test creating and showing keystone config groups and options"""
domain, created_config = self._create_domain_and_config(
self.custom_config)
@@ -117,6 +122,7 @@
@decorators.idempotent_id('7161023e-5dd0-4612-9da0-1bac6ac30b63')
def test_create_update_and_delete_domain_config(self):
+ """Test creating, updating and deleting keystone domain config"""
domain, created_config = self._create_domain_and_config(
self.custom_config)
@@ -140,6 +146,7 @@
@decorators.idempotent_id('c7510fa2-6661-4170-9c6b-4783a80651e9')
def test_create_update_and_delete_domain_config_groups_and_opts(self):
+ """Test create/update/delete keystone domain config groups and opts"""
domain, _ = self._create_domain_and_config(self.custom_config)
# Check that updating configuration groups work.
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index 07175f4..32ccb9e 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -24,6 +24,7 @@
class DomainsTestJSON(base.BaseIdentityV3AdminTest):
+ """Test identity domains"""
@classmethod
def resource_setup(cls):
@@ -37,7 +38,7 @@
@decorators.idempotent_id('8cf516ef-2114-48f1-907b-d32726c734d4')
def test_list_domains(self):
- # Test to list domains
+ """Test listing domains"""
fetched_ids = list()
# List and Verify Domains
body = self.domains_client.list_domains()['domains']
@@ -49,7 +50,7 @@
@decorators.idempotent_id('c6aee07b-4981-440c-bb0b-eb598f58ffe9')
def test_list_domains_filter_by_name(self):
- # List domains filtering by name
+ """Test listing domains filtering by name"""
params = {'name': self.setup_domains[0]['name']}
fetched_domains = self.domains_client.list_domains(
**params)['domains']
@@ -61,7 +62,7 @@
@decorators.idempotent_id('3fd19840-65c1-43f8-b48c-51bdd066dff9')
def test_list_domains_filter_by_enabled(self):
- # List domains filtering by enabled domains
+ """Test listing domains filtering by enabled domains"""
params = {'enabled': True}
fetched_domains = self.domains_client.list_domains(
**params)['domains']
@@ -74,6 +75,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('f2f5b44a-82e8-4dad-8084-0661ea3b18cf')
def test_create_update_delete_domain(self):
+ """Test creating, updating and deleting domain"""
# Create domain
d_name = data_utils.rand_name('domain')
d_desc = data_utils.rand_name('domain-desc')
@@ -118,6 +120,7 @@
@decorators.idempotent_id('d8d318b7-d1b3-4c37-94c5-3c5ba0b121ea')
def test_domain_delete_cascades_content(self):
+ """Test deleting domain will delete its associated contents"""
# Create a domain with a user and a group in it
domain = self.setup_test_domain()
user = self.create_test_user(domain_id=domain['id'])
@@ -134,6 +137,7 @@
@decorators.idempotent_id('036df86e-bb5d-42c0-a7c2-66b9db3a6046')
def test_create_domain_with_disabled_status(self):
+ """Test creating domain with disabled status"""
# Create domain with enabled status as false
d_name = data_utils.rand_name('domain')
d_desc = data_utils.rand_name('domain-desc')
@@ -146,6 +150,7 @@
@decorators.idempotent_id('2abf8764-309a-4fa9-bc58-201b799817ad')
def test_create_domain_without_description(self):
+ """Test creating domain without description"""
# Create domain only with name
d_name = data_utils.rand_name('domain')
domain = self.domains_client.create_domain(name=d_name)['domain']
diff --git a/tempest/api/identity/admin/v3/test_domains_negative.py b/tempest/api/identity/admin/v3/test_domains_negative.py
index b3c68fb..c90206d 100644
--- a/tempest/api/identity/admin/v3/test_domains_negative.py
+++ b/tempest/api/identity/admin/v3/test_domains_negative.py
@@ -20,6 +20,8 @@
class DomainsNegativeTestJSON(base.BaseIdentityV3AdminTest):
+ """Negative tests of identity domains"""
+
# NOTE: force_tenant_isolation is true in the base class by default but
# overridden to false here to allow test execution for clouds using the
# pre-provisioned credentials provider.
@@ -28,6 +30,7 @@
@decorators.attr(type=['negative', 'gate'])
@decorators.idempotent_id('1f3fbff5-4e44-400d-9ca1-d953f05f609b')
def test_delete_active_domain(self):
+ """Test deleting active domain should fail"""
domain = self.create_domain()
domain_id = domain['id']
@@ -40,14 +43,20 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('9018461d-7d24-408d-b3fe-ae37e8cd5c9e')
def test_create_domain_with_empty_name(self):
- # Domain name should not be empty
+ """Test creating domain with empty name should fail
+
+ Domain name should not be empty
+ """
self.assertRaises(lib_exc.BadRequest,
self.domains_client.create_domain, name='')
@decorators.attr(type=['negative'])
@decorators.idempotent_id('37b1bbf2-d664-4785-9a11-333438586eae')
def test_create_domain_with_name_length_over_64(self):
- # Domain name length should not ne greater than 64 characters
+ """Test creating domain with name over length
+
+ Domain name length should not ne greater than 64 characters
+ """
d_name = 'a' * 65
self.assertRaises(lib_exc.BadRequest,
self.domains_client.create_domain,
@@ -56,13 +65,14 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('43781c07-764f-4cf2-a405-953c1916f605')
def test_delete_non_existent_domain(self):
- # Attempt to delete a non existent domain should fail
+ """Test attempting to delete a non existent domain should fail"""
self.assertRaises(lib_exc.NotFound, self.domains_client.delete_domain,
data_utils.rand_uuid_hex())
@decorators.attr(type=['negative'])
@decorators.idempotent_id('e6f9e4a2-4f36-4be8-bdbc-4e199ae29427')
def test_domain_create_duplicate(self):
+ """Test creating domain with duplicate name should fail"""
domain_name = data_utils.rand_name('domain-dup')
domain = self.domains_client.create_domain(name=domain_name)['domain']
domain_id = domain['id']
diff --git a/tempest/api/identity/admin/v3/test_endpoint_groups.py b/tempest/api/identity/admin/v3/test_endpoint_groups.py
index 7d85dc9..2fa92e3 100644
--- a/tempest/api/identity/admin/v3/test_endpoint_groups.py
+++ b/tempest/api/identity/admin/v3/test_endpoint_groups.py
@@ -20,6 +20,8 @@
class EndPointGroupsTest(base.BaseIdentityV3AdminTest):
+ """Test endpoint groups"""
+
# NOTE: force_tenant_isolation is true in the base class by default but
# overridden to false here to allow test execution for clouds using the
# pre-provisioned credentials provider.
@@ -68,6 +70,7 @@
@decorators.idempotent_id('7c69e7a1-f865-402d-a2ea-44493017315a')
def test_create_list_show_check_delete_endpoint_group(self):
+ """Test create/list/show/check/delete of endpoint group"""
service_id = self._create_service()
self.addCleanup(self.services_client.delete_service, service_id)
name = data_utils.rand_name('service_group')
@@ -127,6 +130,7 @@
@decorators.idempotent_id('51c8fc38-fa84-4e76-b5b6-6fc37770fb26')
def test_update_endpoint_group(self):
+ """Test updating endpoint group"""
# Creating an endpoint group so as to check update endpoint group
# with new values
service1_id = self._create_service()
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index 366d6a0..0199d73 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -20,6 +20,8 @@
class EndPointsTestJSON(base.BaseIdentityV3AdminTest):
+ """Test keystone endpoints"""
+
# NOTE: force_tenant_isolation is true in the base class by default but
# overridden to false here to allow test execution for clouds using the
# pre-provisioned credentials provider.
@@ -71,6 +73,7 @@
@decorators.idempotent_id('c19ecf90-240e-4e23-9966-21cee3f6a618')
def test_list_endpoints(self):
+ """Test listing keystone endpoints by filters"""
# Get the list of all the endpoints.
fetched_endpoints = self.client.list_endpoints()['endpoints']
fetched_endpoint_ids = [e['id'] for e in fetched_endpoints]
@@ -111,6 +114,7 @@
@decorators.idempotent_id('0e2446d2-c1fd-461b-a729-b9e73e3e3b37')
def test_create_list_show_delete_endpoint(self):
+ """Test creating, listing, showing and deleting keystone endpoint"""
region_name = data_utils.rand_name('region')
url = data_utils.rand_url()
interface = 'public'
@@ -152,6 +156,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('37e8f15e-ee7c-4657-a1e7-f6b61e375eff')
def test_update_endpoint(self):
+ """Test updating keystone endpoint"""
# NOTE(zhufl) Service2 should be created before endpoint_for_update
# is created, because Service2 must be deleted after
# endpoint_for_update is deleted, otherwise we will get a 404 error
diff --git a/tempest/api/identity/admin/v3/test_endpoints_negative.py b/tempest/api/identity/admin/v3/test_endpoints_negative.py
index 164b577..9689d87 100644
--- a/tempest/api/identity/admin/v3/test_endpoints_negative.py
+++ b/tempest/api/identity/admin/v3/test_endpoints_negative.py
@@ -20,6 +20,8 @@
class EndpointsNegativeTestJSON(base.BaseIdentityV3AdminTest):
+ """Negative tests of endpoint"""
+
# NOTE: force_tenant_isolation is true in the base class by default but
# overridden to false here to allow test execution for clouds using the
# pre-provisioned credentials provider.
@@ -48,7 +50,10 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('ac6c137e-4d3d-448f-8c83-4f13d0942651')
def test_create_with_enabled_False(self):
- # Enabled should be a boolean, not a string like 'False'
+ """Test creating endpoint with invalid enabled value 'False'
+
+ Enabled should be a boolean, not a string like 'False'
+ """
interface = 'public'
url = data_utils.rand_url()
region = data_utils.rand_name('region')
@@ -59,7 +64,10 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('9c43181e-0627-484a-8c79-923e8a59598b')
def test_create_with_enabled_True(self):
- # Enabled should be a boolean, not a string like 'True'
+ """Test creating endpoint with invalid enabled value 'True'
+
+ Enabled should be a boolean, not a string like 'True'
+ """
interface = 'public'
url = data_utils.rand_url()
region = data_utils.rand_name('region')
@@ -88,11 +96,17 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('65e41f32-5eb7-498f-a92a-a6ccacf7439a')
def test_update_with_enabled_False(self):
- # Enabled should be a boolean, not a string like 'False'
+ """Test updating endpoint with invalid enabled value 'False'
+
+ Enabled should be a boolean, not a string like 'False'
+ """
self._assert_update_raises_bad_request('False')
@decorators.attr(type=['negative'])
@decorators.idempotent_id('faba3587-f066-4757-a48e-b4a3f01803bb')
def test_update_with_enabled_True(self):
- # Enabled should be a boolean, not a string like 'True'
+ """Test updating endpoint with invalid enabled value 'True'
+
+ Enabled should be a boolean, not a string like 'True'
+ """
self._assert_update_raises_bad_request('True')
diff --git a/tempest/api/identity/admin/v3/test_groups.py b/tempest/api/identity/admin/v3/test_groups.py
index 2dd1fe2..b2e3775 100644
--- a/tempest/api/identity/admin/v3/test_groups.py
+++ b/tempest/api/identity/admin/v3/test_groups.py
@@ -23,6 +23,8 @@
class GroupsV3TestJSON(base.BaseIdentityV3AdminTest):
+ """Test keystone groups"""
+
# NOTE: force_tenant_isolation is true in the base class by default but
# overridden to false here to allow test execution for clouds using the
# pre-provisioned credentials provider.
@@ -35,6 +37,7 @@
@decorators.idempotent_id('2e80343b-6c81-4ac3-88c7-452f3e9d5129')
def test_group_create_update_get(self):
+ """Test creating, updating and getting keystone group"""
# Verify group creation works.
name = data_utils.rand_name('Group')
description = data_utils.rand_name('Description')
@@ -78,6 +81,7 @@
'immutable user source and solely '
'provides read-only access to users.')
def test_group_users_add_list_delete(self):
+ """Test adding/listing/deleting group users"""
group = self.setup_test_group(domain_id=self.domain['id'])
# add user into group
users = []
@@ -104,6 +108,7 @@
'immutable user source and solely '
'provides read-only access to users.')
def test_list_user_groups(self):
+ """Test listing user groups when the user is in two groups"""
# create a user
user = self.create_test_user()
# create two groups, and add user into them
@@ -127,7 +132,7 @@
@decorators.idempotent_id('cc9a57a5-a9ed-4f2d-a29f-4f979a06ec71')
def test_list_groups(self):
- # Test to list groups
+ """Test listing groups"""
group_ids = list()
fetched_ids = list()
for _ in range(3):
diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py
index 2672f71..cababc6 100644
--- a/tempest/api/identity/admin/v3/test_inherits.py
+++ b/tempest/api/identity/admin/v3/test_inherits.py
@@ -21,6 +21,8 @@
class InheritsV3TestJSON(base.BaseIdentityV3AdminTest):
+ """Test keystone inherits"""
+
# NOTE: force_tenant_isolation is true in the base class by default but
# overridden to false here to allow test execution for clouds using the
# pre-provisioned credentials provider.
@@ -72,6 +74,7 @@
'Skipped because environment has an immutable user '
'source and solely provides read-only access to users.')
def test_inherit_assign_list_check_revoke_roles_on_domains_user(self):
+ """Test assign/list/check/revoke inherited role on domain user"""
# Create role
src_role = self.setup_test_role()
# Assign role on domains user
@@ -96,6 +99,7 @@
@decorators.idempotent_id('c7a8dda2-be50-4fb4-9a9c-e830771078b1')
def test_inherit_assign_list_check_revoke_roles_on_domains_group(self):
+ """Test assign/list/check/revoke inherited role on domain group"""
# Create role
src_role = self.setup_test_role()
# Assign role on domains group
@@ -123,6 +127,7 @@
'Skipped because environment has an immutable user '
'source and solely provides read-only access to users.')
def test_inherit_assign_check_revoke_roles_on_projects_user(self):
+ """Test assign/list/check/revoke inherited role on project user"""
# Create role
src_role = self.setup_test_role()
# Assign role on projects user
@@ -138,6 +143,7 @@
@decorators.idempotent_id('26021436-d5a4-4256-943c-ded01e0d4b45')
def test_inherit_assign_check_revoke_roles_on_projects_group(self):
+ """Test assign/list/check/revoke inherited role on project group"""
# Create role
src_role = self.setup_test_role()
# Assign role on projects group
@@ -157,6 +163,7 @@
'Skipped because environment has an immutable user '
'source and solely provides read-only access to users.')
def test_inherit_assign_list_revoke_user_roles_on_domain(self):
+ """Test assign/list/check/revoke inherited role on domain"""
# Create role
src_role = self.setup_test_role()
@@ -204,6 +211,7 @@
'Skipped because environment has an immutable user '
'source and solely provides read-only access to users.')
def test_inherit_assign_list_revoke_user_roles_on_project_tree(self):
+ """Test assign/list/check/revoke inherited role on project tree"""
# Create role
src_role = self.setup_test_role()
diff --git a/tempest/api/identity/admin/v3/test_list_projects.py b/tempest/api/identity/admin/v3/test_list_projects.py
index cb8ea11..b33d8bd 100644
--- a/tempest/api/identity/admin/v3/test_list_projects.py
+++ b/tempest/api/identity/admin/v3/test_list_projects.py
@@ -40,6 +40,7 @@
class ListProjectsTestJSON(BaseListProjectsTestJSON):
+ """Test listing projects"""
@classmethod
def resource_setup(cls):
@@ -65,13 +66,13 @@
@decorators.idempotent_id('0fe7a334-675a-4509-b00e-1c4b95d5dae8')
def test_list_projects_with_enabled(self):
- # List the projects with enabled
+ """Test listing the projects with enabled"""
self._list_projects_with_params(
[self.p1], [self.p2, self.p3], {'enabled': False}, 'enabled')
@decorators.idempotent_id('6edc66f5-2941-4a17-9526-4073311c1fac')
def test_list_projects_with_parent(self):
- # List projects with parent
+ """Test listing projects with parent"""
params = {'parent_id': self.p3['parent_id']}
fetched_projects = self.projects_client.list_projects(
params)['projects']
@@ -81,6 +82,11 @@
class ListProjectsStaticTestJSON(BaseListProjectsTestJSON):
+ """Test listing projects
+
+ These tests can be executed in clouds using the pre-provisioned users
+ """
+
# NOTE: force_tenant_isolation is true in the base class by default but
# overridden to false here to allow test execution for clouds using the
# pre-provisioned credentials provider.
@@ -102,7 +108,7 @@
@decorators.idempotent_id('1d830662-22ad-427c-8c3e-4ec854b0af44')
def test_list_projects(self):
- # List projects
+ """Test listing projects"""
list_projects = self.projects_client.list_projects()['projects']
for p in [self.p1, self.p2]:
@@ -112,13 +118,13 @@
@decorators.idempotent_id('fa178524-4e6d-4925-907c-7ab9f42c7e26')
def test_list_projects_with_name(self):
- # List projects with name
+ """Test listing projects filtered by name"""
self._list_projects_with_params(
[self.p1], [self.p2], {'name': self.p1['name']}, 'name')
@decorators.idempotent_id('fab13f3c-f6a6-4b9f-829b-d32fd44fdf10')
def test_list_projects_with_domains(self):
- # Verify project list filtered by domain
+ """Test listing projects filtered by domain"""
key = 'domain_id'
for p in [self.p1, self.p2]:
params = {key: p[key]}
diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py
index e46145d..be1216a 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -23,6 +23,8 @@
class ProjectsTestJSON(base.BaseIdentityV3AdminTest):
+ """Test identity projects"""
+
# NOTE: force_tenant_isolation is true in the base class by default but
# overridden to false here to allow test execution for clouds using the
# pre-provisioned credentials provider.
@@ -30,7 +32,7 @@
@decorators.idempotent_id('0ecf465c-0dc4-4532-ab53-91ffeb74d12d')
def test_project_create_with_description(self):
- # Create project with a description
+ """Test creating project with a description"""
project_desc = data_utils.rand_name('desc')
project = self.setup_test_project(description=project_desc)
project_id = project['id']
@@ -44,7 +46,7 @@
@decorators.idempotent_id('5f50fe07-8166-430b-a882-3b2ee0abe26f')
def test_project_create_with_domain(self):
- # Create project with a domain
+ """Test creating project with a domain"""
domain = self.setup_test_domain()
project_name = data_utils.rand_name('project')
project = self.setup_test_project(
@@ -58,7 +60,7 @@
@decorators.idempotent_id('1854f9c0-70bc-4d11-a08a-1c789d339e3d')
def test_project_create_with_parent(self):
- # Create root project without providing a parent_id
+ """Test creating root project without providing a parent_id"""
domain = self.setup_test_domain()
domain_id = domain['id']
@@ -83,6 +85,7 @@
@decorators.idempotent_id('a7eb9416-6f9b-4dbb-b71b-7f73aaef59d5')
def test_create_is_domain_project(self):
+ """Test creating is_domain project"""
project = self.setup_test_project(domain_id=None, is_domain=True)
# To delete a domain, we need to disable it first
self.addCleanup(self.projects_client.update_project, project['id'],
@@ -103,7 +106,7 @@
@decorators.idempotent_id('1f66dc76-50cc-4741-a200-af984509e480')
def test_project_create_enabled(self):
- # Create a project that is enabled
+ """Test creating a project that is enabled"""
project = self.setup_test_project(enabled=True)
project_id = project['id']
self.assertTrue(project['enabled'],
@@ -113,7 +116,7 @@
@decorators.idempotent_id('78f96a9c-e0e0-4ee6-a3ba-fbf6dfd03207')
def test_project_create_not_enabled(self):
- # Create a project that is not enabled
+ """Test creating a project that is not enabled"""
project = self.setup_test_project(enabled=False)
self.assertFalse(project['enabled'],
'Enable should be False in response')
@@ -123,7 +126,7 @@
@decorators.idempotent_id('f608f368-048c-496b-ad63-d286c26dab6b')
def test_project_update_name(self):
- # Update name attribute of a project
+ """Test updating name attribute of a project"""
p_name1 = data_utils.rand_name('project')
project = self.setup_test_project(name=p_name1)
@@ -144,7 +147,7 @@
@decorators.idempotent_id('f138b715-255e-4a7d-871d-351e1ef2e153')
def test_project_update_desc(self):
- # Update description attribute of a project
+ """Test updating description attribute of a project"""
p_desc = data_utils.rand_name('desc')
project = self.setup_test_project(description=p_desc)
resp1_desc = project['description']
@@ -164,7 +167,7 @@
@decorators.idempotent_id('b6b25683-c97f-474d-a595-55d410b68100')
def test_project_update_enable(self):
- # Update the enabled attribute of a project
+ """Test updating the enabled attribute of a project"""
p_en = False
project = self.setup_test_project(enabled=p_en)
@@ -189,7 +192,7 @@
'immutable user source and solely '
'provides read-only access to users.')
def test_associate_user_to_project(self):
- # Associate a user to a project
+ """Test associating a user to a project"""
# Create a Project
project = self.setup_test_project()
@@ -215,6 +218,7 @@
@decorators.idempotent_id('d1db68b6-aebe-4fa0-b79d-d724d2e21162')
def test_project_get_equals_list(self):
+ """Test the result of getting project equals that of listing"""
fields = ['parent_id', 'is_domain', 'description', 'links',
'name', 'enabled', 'domain_id', 'id', 'tags']
diff --git a/tempest/api/identity/admin/v3/test_projects_negative.py b/tempest/api/identity/admin/v3/test_projects_negative.py
index 12f1d4a..79e3d29 100644
--- a/tempest/api/identity/admin/v3/test_projects_negative.py
+++ b/tempest/api/identity/admin/v3/test_projects_negative.py
@@ -20,11 +20,12 @@
class ProjectsNegativeTestJSON(base.BaseIdentityV3AdminTest):
+ """Negative tests of projects"""
@decorators.attr(type=['negative'])
@decorators.idempotent_id('8d68c012-89e0-4394-8d6b-ccd7196def97')
def test_project_delete_by_unauthorized_user(self):
- # Non-admin user should not be able to delete a project
+ """Non-admin user should not be able to delete a project"""
project = self.setup_test_project()
self.assertRaises(
lib_exc.Forbidden, self.non_admin_projects_client.delete_project,
@@ -32,6 +33,11 @@
class ProjectsNegativeStaticTestJSON(base.BaseIdentityV3AdminTest):
+ """Negative tests of projects
+
+ These tests can be executed in clouds using the pre-provisioned users
+ """
+
# NOTE: force_tenant_isolation is true in the base class by default but
# overridden to false here to allow test execution for clouds using the
# pre-provisioned credentials provider.
@@ -40,14 +46,14 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('24c49279-45dd-4155-887a-cb738c2385aa')
def test_list_projects_by_unauthorized_user(self):
- # Non-admin user should not be able to list projects
+ """Non-admin user should not be able to list projects"""
self.assertRaises(lib_exc.Forbidden,
self.non_admin_projects_client.list_projects)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('874c3e84-d174-4348-a16b-8c01f599561b')
def test_project_create_duplicate(self):
- # Project names should be unique
+ """Project names should be unique"""
project_name = data_utils.rand_name('project-dup')
self.setup_test_project(name=project_name)
@@ -57,7 +63,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('8fba9de2-3e1f-4e77-812a-60cb68f8df13')
def test_create_project_by_unauthorized_user(self):
- # Non-admin user should not be authorized to create a project
+ """Non-admin user should not be authorized to create a project"""
project_name = data_utils.rand_name('project')
self.assertRaises(
lib_exc.Forbidden, self.non_admin_projects_client.create_project,
@@ -66,14 +72,14 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7828db17-95e5-475b-9432-9a51b4aa79a9')
def test_create_project_with_empty_name(self):
- # Project name should not be empty
+ """Project name should not be empty"""
self.assertRaises(lib_exc.BadRequest,
self.projects_client.create_project, name='')
@decorators.attr(type=['negative'])
@decorators.idempotent_id('502b6ceb-b0c8-4422-bf53-f08fdb21e2f0')
def test_create_projects_name_length_over_64(self):
- # Project name length should not be greater than 64 characters
+ """Project name length should not be greater than 64 characters"""
project_name = 'a' * 65
self.assertRaises(lib_exc.BadRequest,
self.projects_client.create_project, project_name)
@@ -81,7 +87,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7965b581-60c1-43b7-8169-95d4ab7fc6fb')
def test_delete_non_existent_project(self):
- # Attempt to delete a non existent project should fail
+ """Attempt to delete a non existent project should fail"""
self.assertRaises(lib_exc.NotFound,
self.projects_client.delete_project,
data_utils.rand_uuid_hex())
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index 78e3cce..580e304 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -27,6 +27,7 @@
class TrustsV3TestJSON(base.BaseIdentityV3AdminTest):
+ """Test keystone trusts"""
@classmethod
def skip_checks(cls):
@@ -195,8 +196,11 @@
@decorators.idempotent_id('5a0a91a4-baef-4a14-baba-59bf4d7fcace')
def test_trust_impersonate(self):
- # Test case to check we can create, get and delete a trust
- # updates are not supported for trusts
+ """Test keystone trust with impersonation enabled
+
+ To check we can create, get and delete a trust.
+ Updates are not supported for trusts
+ """
trust = self.create_trust()
self.validate_trust(trust)
@@ -207,8 +211,11 @@
@decorators.idempotent_id('ed2a8779-a7ac-49dc-afd7-30f32f936ed2')
def test_trust_noimpersonate(self):
- # Test case to check we can create, get and delete a trust
- # with impersonation=False
+ """Test keystone trust with impersonation disabled
+
+ To check we can create, get and delete a trust
+ with impersonation=False
+ """
trust = self.create_trust(impersonate=False)
self.validate_trust(trust, impersonate=False)
@@ -219,8 +226,11 @@
@decorators.idempotent_id('0ed14b66-cefd-4b5c-a964-65759453e292')
def test_trust_expire(self):
- # Test case to check we can create, get and delete a trust
- # with an expiry specified
+ """Test expire attribute of keystone trust
+
+ To check we can create, get and delete a trust
+ with an expiry specified
+ """
expires_at = timeutils.utcnow() + datetime.timedelta(hours=1)
# NOTE(ylobankov) In some cases the expiry time may be rounded up
# because of microseconds. In fact, it depends on database and its
@@ -246,8 +256,10 @@
@decorators.idempotent_id('3e48f95d-e660-4fa9-85e0-5a3d85594384')
def test_trust_expire_invalid(self):
- # Test case to check we can check an invalid expiry time
- # is rejected with the correct error
+ """Test invalid expire attribute of a keystone trust
+
+ To check an invalid expiry time is rejected with the correct error
+ """
# with an expiry specified
expires_str = 'bad.123Z'
self.assertRaises(lib_exc.BadRequest,
@@ -256,6 +268,7 @@
@decorators.idempotent_id('6268b345-87ca-47c0-9ce3-37792b43403a')
def test_get_trusts_query(self):
+ """Test getting keystone trusts"""
self.create_trust()
trusts_get = self.trustor_client.list_trusts(
trustor_user_id=self.trustor_user_id)['trusts']
@@ -265,7 +278,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('4773ebd5-ecbf-4255-b8d8-b63e6f72b65d')
def test_get_trusts_all(self):
-
+ """Test getting all keystone trusts"""
# Simple function that can be used for cleanup
def set_scope(auth_provider, scope):
auth_provider.scope = scope
diff --git a/tempest/api/identity/admin/v3/test_users_negative.py b/tempest/api/identity/admin/v3/test_users_negative.py
index 11dcdb0..1cba945 100644
--- a/tempest/api/identity/admin/v3/test_users_negative.py
+++ b/tempest/api/identity/admin/v3/test_users_negative.py
@@ -23,11 +23,12 @@
class UsersNegativeTest(base.BaseIdentityV3AdminTest):
+ """Negative tests of keystone users"""
@decorators.attr(type=['negative'])
@decorators.idempotent_id('e75f006c-89cc-477b-874d-588e4eab4b17')
def test_create_user_for_non_existent_domain(self):
- # Attempt to create a user in a non-existent domain should fail
+ """Attempt to create a user in a non-existent domain should fail"""
u_name = data_utils.rand_name('user')
u_email = u_name + '@testmail.tm'
u_password = data_utils.rand_password()
@@ -39,7 +40,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('b3c9fccc-4134-46f5-b600-1da6fb0a3b1f')
def test_authentication_for_disabled_user(self):
- # Attempt to authenticate for disabled user should fail
+ """Attempt to authenticate for disabled user should fail"""
password = data_utils.rand_password()
user = self.setup_test_user(password)
self.disable_user(user['name'], user['domain_id'])
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index c4a3e0e..3e72b34 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -29,6 +29,64 @@
LOG = logging.getLogger(__name__)
+class ImportImagesTest(base.BaseV2ImageTest):
+ """Here we test the import operations for image"""
+
+ @classmethod
+ def skip_checks(cls):
+ super(ImportImagesTest, cls).skip_checks()
+ if not CONF.image_feature_enabled.import_image:
+ skip_msg = (
+ "%s skipped as image import is not available" % cls.__name__)
+ raise cls.skipException(skip_msg)
+
+ @decorators.idempotent_id('32ca0c20-e16f-44ac-8590-07869c9b4cc2')
+ def test_image_import(self):
+ """Here we test these functionalities
+
+ Create image, stage image data, import image and verify
+ that import succeeded.
+ """
+
+ body = self.client.info_import()
+ if 'glance-direct' not in body['import-methods']['value']:
+ raise self.skipException('Server does not support '
+ 'glance-direct import method')
+
+ # Create image
+ uuid = '00000000-1111-2222-3333-444455556666'
+ image_name = data_utils.rand_name('image')
+ container_format = CONF.image.container_formats[0]
+ disk_format = CONF.image.disk_formats[0]
+ image = self.create_image(name=image_name,
+ container_format=container_format,
+ disk_format=disk_format,
+ visibility='private',
+ ramdisk_id=uuid)
+ self.assertIn('name', image)
+ self.assertEqual(image_name, image['name'])
+ self.assertIn('visibility', image)
+ self.assertEqual('private', image['visibility'])
+ self.assertIn('status', image)
+ self.assertEqual('queued', image['status'])
+
+ # Stage image data
+ file_content = data_utils.random_bytes()
+ image_file = six.BytesIO(file_content)
+ self.client.stage_image_file(image['id'], image_file)
+
+ # Now try to get image details
+ body = self.client.show_image(image['id'])
+ self.assertEqual(image['id'], body['id'])
+ self.assertEqual(image_name, body['name'])
+ self.assertEqual(uuid, body['ramdisk_id'])
+ self.assertEqual('uploading', body['status'])
+
+ # import image from staging to backend
+ self.client.image_import(image['id'])
+ self.client.wait_for_resource_activation(image['id'])
+
+
class BasicOperationsImagesTest(base.BaseV2ImageTest):
"""Here we test the basic operations of images"""
diff --git a/tempest/api/network/admin/test_dhcp_agent_scheduler.py b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
index 4631ea9..2506185 100644
--- a/tempest/api/network/admin/test_dhcp_agent_scheduler.py
+++ b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
@@ -18,6 +18,7 @@
class DHCPAgentSchedulersTestJSON(base.BaseAdminNetworkTest):
+ """Test network DHCP agent scheduler extension"""
@classmethod
def skip_checks(cls):
@@ -37,11 +38,13 @@
@decorators.idempotent_id('5032b1fe-eb42-4a64-8f3b-6e189d8b5c7d')
def test_list_dhcp_agent_hosting_network(self):
+ """Test Listing DHCP agents hosting a network"""
self.admin_networks_client.list_dhcp_agents_on_hosting_network(
self.network['id'])
@decorators.idempotent_id('30c48f98-e45d-4ffb-841c-b8aad57c7587')
def test_list_networks_hosted_by_one_dhcp(self):
+ """Test Listing networks hosted by a DHCP agent"""
body = self.admin_networks_client.list_dhcp_agents_on_hosting_network(
self.network['id'])
agents = body['agents']
@@ -61,6 +64,7 @@
@decorators.idempotent_id('a0856713-6549-470c-a656-e97c8df9a14d')
def test_add_remove_network_from_dhcp_agent(self):
+ """Test adding and removing network from a DHCP agent"""
# The agent is now bound to the network, we can free the port
self.ports_client.delete_port(self.port['id'])
agent = dict()
diff --git a/tempest/api/network/admin/test_external_network_extension.py b/tempest/api/network/admin/test_external_network_extension.py
index 5bd3fce..0cec316 100644
--- a/tempest/api/network/admin/test_external_network_extension.py
+++ b/tempest/api/network/admin/test_external_network_extension.py
@@ -23,6 +23,7 @@
class ExternalNetworksTestJSON(base.BaseAdminNetworkTest):
+ """Test external networks"""
@classmethod
def resource_setup(cls):
@@ -42,8 +43,11 @@
@decorators.idempotent_id('462be770-b310-4df9-9c42-773217e4c8b1')
def test_create_external_network(self):
- # Create a network as an admin user specifying the
- # external network extension attribute
+ """Test creating external network
+
+ Create a network as an admin user specifying the
+ external network extension attribute
+ """
ext_network = self._create_network()
# Verifies router:external parameter
self.assertIsNotNone(ext_network['id'])
@@ -51,8 +55,11 @@
@decorators.idempotent_id('4db5417a-e11c-474d-a361-af00ebef57c5')
def test_update_external_network(self):
- # Update a network as an admin user specifying the
- # external network extension attribute
+ """Test updating external network
+
+ Update a network as an admin user specifying the
+ external network extension attribute
+ """
network = self._create_network(external=False)
self.assertFalse(network.get('router:external', False))
update_body = {'router:external': True}
@@ -64,6 +71,7 @@
@decorators.idempotent_id('39be4c9b-a57e-4ff9-b7c7-b218e209dfcc')
def test_list_external_networks(self):
+ """Test listing external networks"""
# Create external_net
external_network = self._create_network()
# List networks as a normal user and confirm the external
@@ -81,6 +89,7 @@
@decorators.idempotent_id('2ac50ab2-7ebd-4e27-b3ce-a9e399faaea2')
def test_show_external_networks_attribute(self):
+ """Test showing external network attribute"""
# Create external_net
external_network = self._create_network()
# Show an external network as a normal user and confirm the
@@ -101,9 +110,11 @@
@testtools.skipUnless(CONF.network_feature_enabled.floating_ips,
'Floating ips are not availabled')
def test_delete_external_networks_with_floating_ip(self):
- # Verifies external network can be deleted while still holding
- # (unassociated) floating IPs
+ """Test deleting external network with unassociated floating ips
+ Verifies external network can be deleted while still holding
+ (unassociated) floating IPs
+ """
body = self.admin_networks_client.create_network(
**{'router:external': True})
external_network = body['network']
diff --git a/tempest/api/network/admin/test_external_networks_negative.py b/tempest/api/network/admin/test_external_networks_negative.py
index da32f2d..92731f6 100644
--- a/tempest/api/network/admin/test_external_networks_negative.py
+++ b/tempest/api/network/admin/test_external_networks_negative.py
@@ -25,16 +25,19 @@
class ExternalNetworksAdminNegativeTestJSON(base.BaseAdminNetworkTest):
+ """Negative tests of external network"""
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d402ae6c-0be0-4d8e-833b-a738895d98d0')
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_create_port_with_precreated_floatingip_as_fixed_ip(self):
- # NOTE: External networks can be used to create both floating-ip as
- # well as instance-ip. So, creating an instance-ip with a value of a
- # pre-created floating-ip should be denied.
+ """Test creating port with precreated floating ip as fixed ip
+ NOTE: External networks can be used to create both floating-ip as
+ well as instance-ip. So, creating an instance-ip with a value of a
+ pre-created floating-ip should be denied.
+ """
# create a floating ip
body = self.admin_floating_ips_client.create_floatingip(
floating_network_id=CONF.network.public_network_id)
diff --git a/tempest/api/network/admin/test_floating_ips_admin_actions.py b/tempest/api/network/admin/test_floating_ips_admin_actions.py
index 7d41019..ad7dfb3 100644
--- a/tempest/api/network/admin/test_floating_ips_admin_actions.py
+++ b/tempest/api/network/admin/test_floating_ips_admin_actions.py
@@ -23,6 +23,8 @@
class FloatingIPAdminTestJSON(base.BaseAdminNetworkTest):
+ """Test floating ips"""
+
credentials = ['primary', 'alt', 'admin']
@classmethod
@@ -55,6 +57,13 @@
@decorators.idempotent_id('64f2100b-5471-4ded-b46c-ddeeeb4f231b')
def test_list_floating_ips_from_admin_and_nonadmin(self):
+ """Test listing floating ips from admin and non admin users
+
+ This test performs below operations:
+ 1. Create couple floating ips for admin and non-admin users.
+ 2. Verify if admin can access all floating ips including other user
+ and non-admin user can only access its own floating ips.
+ """
# Create floating ip from admin user
floating_ip_admin = self.admin_floating_ips_client.create_floatingip(
floating_network_id=self.ext_net_id)
@@ -90,6 +99,7 @@
@decorators.idempotent_id('32727cc3-abe2-4485-a16e-48f2d54c14f2')
def test_create_list_show_floating_ip_with_tenant_id_by_admin(self):
+ """Verify if admin can create/list/show floating ip with tenant id"""
# Creates a floating IP
body = self.admin_floating_ips_client.create_floatingip(
floating_network_id=self.ext_net_id,
diff --git a/tempest/api/network/admin/test_metering_extensions.py b/tempest/api/network/admin/test_metering_extensions.py
index 942b66c..a60cd48 100644
--- a/tempest/api/network/admin/test_metering_extensions.py
+++ b/tempest/api/network/admin/test_metering_extensions.py
@@ -92,13 +92,14 @@
@decorators.idempotent_id('e2fb2f8c-45bf-429a-9f17-171c70444612')
def test_list_metering_labels(self):
- # Verify label filtering
+ """Verify listing metering labels"""
body = self.admin_metering_labels_client.list_metering_labels(id=33)
metering_labels = body['metering_labels']
self.assertEmpty(metering_labels)
@decorators.idempotent_id('ec8e15ff-95d0-433b-b8a6-b466bddb1e50')
def test_create_delete_metering_label_with_filters(self):
+ """Verifies creating and deleting metering label with filters"""
# Creates a label
name = data_utils.rand_name('metering-label-')
description = "label created by tempest"
@@ -115,7 +116,7 @@
@decorators.idempotent_id('30abb445-0eea-472e-bd02-8649f54a5968')
def test_show_metering_label(self):
- # Verifies the details of a label
+ """Verifies the details of a metering label"""
body = self.admin_metering_labels_client.show_metering_label(
self.metering_label['id'])
metering_label = body['metering_label']
@@ -128,6 +129,7 @@
@decorators.idempotent_id('cc832399-6681-493b-9d79-0202831a1281')
def test_list_metering_label_rules(self):
+ """Verifies listing metering label rules"""
client = self.admin_metering_label_rules_client
# Verify rule filtering
body = client.list_metering_label_rules(id=33)
@@ -136,6 +138,7 @@
@decorators.idempotent_id('f4d547cd-3aee-408f-bf36-454f8825e045')
def test_create_delete_metering_label_rule_with_filters(self):
+ """Verifies creating and deleting metering label rule with filters"""
# Creates a rule
remote_ip_prefix = ("10.0.1.0/24" if self._ip_version == 4
else "fd03::/64")
@@ -154,7 +157,7 @@
@decorators.idempotent_id('b7354489-96ea-41f3-9452-bace120fb4a7')
def test_show_metering_label_rule(self):
- # Verifies the details of a rule
+ """Verifies the metering details of a rule"""
client = self.admin_metering_label_rules_client
body = (client.show_metering_label_rule(
self.metering_label_rule['id']))
diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py
index 3562d6f..190d9e3 100644
--- a/tempest/api/network/admin/test_negative_quotas.py
+++ b/tempest/api/network/admin/test_negative_quotas.py
@@ -53,6 +53,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('644f4e1b-1bf9-4af0-9fd8-eb56ac0f51cf')
def test_network_quota_exceeding(self):
+ """Test creating network when exceeding network quota will fail"""
# Set the network quota to two
self.admin_quotas_client.update_quotas(self.project['id'], network=2)
diff --git a/tempest/api/network/admin/test_ports.py b/tempest/api/network/admin/test_ports.py
index 289e577..51f2857 100644
--- a/tempest/api/network/admin/test_ports.py
+++ b/tempest/api/network/admin/test_ports.py
@@ -24,6 +24,7 @@
class PortsAdminExtendedAttrsTestJSON(base.BaseAdminNetworkTest):
+ """Test extended attributes of ports"""
@classmethod
def setup_clients(cls):
@@ -41,6 +42,7 @@
@decorators.idempotent_id('8e8569c1-9ac7-44db-8bc1-f5fb2814f29b')
@utils.services('compute')
def test_create_port_binding_ext_attr(self):
+ """Test creating port with extended attribute"""
post_body = {"network_id": self.network['id'],
"binding:host_id": self.host_id,
"name": data_utils.rand_name(self.__class__.__name__)}
@@ -56,6 +58,7 @@
@decorators.idempotent_id('6f6c412c-711f-444d-8502-0ac30fbf5dd5')
@utils.services('compute')
def test_update_port_binding_ext_attr(self):
+ """Test updating port's extended attribute"""
post_body = {"network_id": self.network['id'],
"name": data_utils.rand_name(self.__class__.__name__)}
body = self.admin_ports_client.create_port(**post_body)
@@ -73,6 +76,7 @@
@decorators.idempotent_id('1c82a44a-6c6e-48ff-89e1-abe7eaf8f9f8')
@utils.services('compute')
def test_list_ports_binding_ext_attr(self):
+ """Test updating and listing port's extended attribute"""
# Create a new port
post_body = {"network_id": self.network['id'],
"name": data_utils.rand_name(self.__class__.__name__)}
@@ -101,6 +105,7 @@
@decorators.idempotent_id('b54ac0ff-35fc-4c79-9ca3-c7dbd4ea4f13')
def test_show_port_binding_ext_attr(self):
+ """Test showing port's extended attribute"""
body = self.admin_ports_client.create_port(
name=data_utils.rand_name(self.__class__.__name__),
network_id=self.network['id'])
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 8b7bfb1..d8db298 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -89,6 +89,7 @@
@decorators.idempotent_id('2390f766-836d-40ef-9aeb-e810d78207fb')
def test_quotas(self):
+ """Test update/list/show/reset of network quotas"""
new_quotas = {'network': 0, 'port': 0}
self._check_quotas(new_quotas)
@@ -96,6 +97,7 @@
'quota_details', 'network'), 'Quota details extension not enabled.')
@decorators.idempotent_id('7b05ec5f-bf44-43cb-b28f-ddd72a824288')
def test_show_quota_details(self):
+ """Test showing network quota details"""
# Show quota details for an existing project
quota_details = self.admin_quotas_client.show_quota_details(
self.admin_quotas_client.tenant_id)['quota']
diff --git a/tempest/api/network/admin/test_routers.py b/tempest/api/network/admin/test_routers.py
index 417eb70..90e0917 100644
--- a/tempest/api/network/admin/test_routers.py
+++ b/tempest/api/network/admin/test_routers.py
@@ -27,6 +27,8 @@
class RoutersAdminTest(base.BaseAdminNetworkTest):
+ """Test routers operation supported by admin"""
+
# NOTE(salv-orlando): This class inherits from BaseAdminNetworkTest
# as some router operations, such as enabling or disabling SNAT
# require admin credentials by default
@@ -52,7 +54,7 @@
@decorators.idempotent_id('e54dd3a3-4352-4921-b09d-44369ae17397')
def test_create_router_setting_project_id(self):
- # Test creating router from admin user setting project_id.
+ """Test creating router from admin user setting project_id."""
project = data_utils.rand_name('test_tenant_')
description = data_utils.rand_name('desc_')
project = identity.identity_utils(self.os_admin).create_project(
@@ -74,7 +76,7 @@
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_create_router_with_default_snat_value(self):
- # Create a router with default snat rule
+ """Create a router with default snat rule"""
router = self._create_router(
external_network_id=CONF.network.public_network_id)
self._verify_router_gateway(
@@ -86,6 +88,7 @@
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_create_router_with_snat_explicit(self):
+ """Test creating router with specified enable_snat value"""
name = data_utils.rand_name('snat-router')
# Create a router enabling snat attributes
enable_snat_states = [False, True]
@@ -134,6 +137,7 @@
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_update_router_set_gateway(self):
+ """Test updating router's gateway info"""
router = self._create_router()
self.routers_client.update_router(
router['id'],
@@ -150,6 +154,7 @@
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_update_router_set_gateway_with_snat_explicit(self):
+ """Test setting router's gateway with snat enabled"""
router = self._create_router()
self.admin_routers_client.update_router(
router['id'],
@@ -167,6 +172,7 @@
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_update_router_set_gateway_without_snat(self):
+ """Test setting router's gateway with snat not enabled"""
router = self._create_router()
self.admin_routers_client.update_router(
router['id'],
@@ -183,6 +189,7 @@
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_update_router_unset_gateway(self):
+ """Test unsetting router's gateway"""
router = self._create_router(
external_network_id=CONF.network.public_network_id)
self.routers_client.update_router(router['id'],
@@ -199,6 +206,7 @@
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_update_router_reset_gateway_without_snat(self):
+ """Test updating router's gateway to be with snat not enabled"""
router = self._create_router(
external_network_id=CONF.network.public_network_id)
self.admin_routers_client.update_router(
@@ -215,6 +223,7 @@
@decorators.idempotent_id('cbe42f84-04c2-11e7-8adb-fa163e4fa634')
@utils.requires_ext(extension='ext-gw-mode', service='network')
def test_create_router_set_gateway_with_fixed_ip(self):
+ """Test creating router setting gateway with fixed ip"""
# At first create an external network and then use that
# to create address and delete
network_name = data_utils.rand_name(self.__class__.__name__)
diff --git a/tempest/api/network/admin/test_routers_negative.py b/tempest/api/network/admin/test_routers_negative.py
index f605945..914c046 100644
--- a/tempest/api/network/admin/test_routers_negative.py
+++ b/tempest/api/network/admin/test_routers_negative.py
@@ -27,6 +27,7 @@
class RoutersAdminNegativeTest(base.BaseAdminNetworkTest):
+ """Admin negative tests of routers"""
@classmethod
def skip_checks(cls):
@@ -41,6 +42,7 @@
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_router_set_gateway_used_ip_returns_409(self):
+ """Test creating router with gateway set to used ip should fail"""
# At first create a address from public_network_id
port = self.admin_ports_client.create_port(
name=data_utils.rand_name(self.__class__.__name__),
diff --git a/tempest/api/network/test_allowed_address_pair.py b/tempest/api/network/test_allowed_address_pair.py
index 639defb..ff5026b 100644
--- a/tempest/api/network/test_allowed_address_pair.py
+++ b/tempest/api/network/test_allowed_address_pair.py
@@ -57,7 +57,7 @@
@decorators.idempotent_id('86c3529b-1231-40de-803c-00e40882f043')
def test_create_list_port_with_address_pair(self):
- # Create port with allowed address pair attribute
+ """Create and list port with allowed address pair attribute"""
allowed_address_pairs = [{'ip_address': self.ip_address,
'mac_address': self.mac_address}]
body = self.ports_client.create_port(
@@ -100,17 +100,17 @@
@decorators.idempotent_id('9599b337-272c-47fd-b3cf-509414414ac4')
def test_update_port_with_address_pair(self):
- # Update port with allowed address pair
+ """Update port with allowed address pair"""
self._update_port_with_address(self.ip_address)
@decorators.idempotent_id('4d6d178f-34f6-4bff-a01c-0a2f8fe909e4')
def test_update_port_with_cidr_address_pair(self):
- # Update allowed address pair with cidr
+ """Update allowed address pair with cidr"""
self._update_port_with_address(str(self.cidr))
@decorators.idempotent_id('b3f20091-6cd5-472b-8487-3516137df933')
def test_update_port_with_multiple_ip_mac_address_pair(self):
- # Create an ip _address and mac_address through port create
+ """Update allowed address pair port with multiple ip and mac"""
resp = self.ports_client.create_port(
network_id=self.network['id'],
name=data_utils.rand_name(self.__class__.__name__))
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index eb31ed3..fee6af5 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -104,9 +104,12 @@
@decorators.idempotent_id('e5517e62-6f16-430d-a672-f80875493d4c')
def test_dhcpv6_stateless_eui64(self):
- # NOTE: When subnets configured with RAs SLAAC (AOM=100) and DHCP
- # stateless (AOM=110) both for radvd and dnsmasq, port shall receive
- # IP address calculated from its MAC.
+ """Test eui64 ip when setting slaac and statelss for subnet
+
+ NOTE: When subnets configured with RAs SLAAC (AOM=100) and DHCP
+ stateless (AOM=110) both for radvd and dnsmasq, port shall receive
+ IP address calculated from its MAC.
+ """
for ra_mode, add_mode in (
('slaac', 'slaac'),
('dhcpv6-stateless', 'dhcpv6-stateless'),
@@ -122,9 +125,12 @@
@decorators.idempotent_id('ae2f4a5d-03ff-4c42-a3b0-ce2fcb7ea832')
def test_dhcpv6_stateless_no_ra(self):
- # NOTE: When subnets configured with dnsmasq SLAAC and DHCP stateless
- # and there is no radvd, port shall receive IP address calculated
- # from its MAC and mask of subnet.
+ """Test eui64 ip when setting stateless and no radvd for subnets
+
+ NOTE: When subnets configured with dnsmasq SLAAC and DHCP stateless
+ and there is no radvd, port shall receive IP address calculated
+ from its MAC and mask of subnet.
+ """
for ra_mode, add_mode in (
(None, 'slaac'),
(None, 'dhcpv6-stateless'),
@@ -161,8 +167,11 @@
@decorators.idempotent_id('21635b6f-165a-4d42-bf49-7d195e47342f')
def test_dhcpv6_stateless_no_ra_no_dhcp(self):
- # NOTE: If no radvd option and no dnsmasq option is configured
- # port shall receive IP from fixed IPs list of subnet.
+ """Test eui64 ip when setting no radvd and no dnsmasq for subnets
+
+ NOTE: If no radvd option and no dnsmasq option is configured
+ port shall receive IP from fixed IPs list of subnet.
+ """
real_ip, eui_ip = self._get_ips_from_subnet()
self._clean_network()
self.assertNotEqual(eui_ip, real_ip,
@@ -173,10 +182,13 @@
@decorators.idempotent_id('4544adf7-bb5f-4bdc-b769-b3e77026cef2')
def test_dhcpv6_two_subnets(self):
- # NOTE: When one IPv6 subnet configured with dnsmasq SLAAC or DHCP
- # stateless and other IPv6 is with DHCP stateful, port shall receive
- # EUI-64 IP addresses from first subnet and DHCP address from second
- # one. Order of subnet creating should be unimportant.
+ """Test eui64 ip when creating port under network with two subnets
+
+ NOTE: When one IPv6 subnet configured with dnsmasq SLAAC or DHCP
+ stateless and other IPv6 is with DHCP stateful, port shall receive
+ EUI-64 IP addresses from first subnet and DHCP address from second
+ one. Order of subnet creating should be unimportant.
+ """
for order in ("slaac_first", "dhcp_first"):
for ra_mode, add_mode in (
('slaac', 'slaac'),
@@ -225,10 +237,13 @@
@decorators.idempotent_id('4256c61d-c538-41ea-9147-3c450c36669e')
def test_dhcpv6_64_subnets(self):
- # NOTE: When one IPv6 subnet configured with dnsmasq SLAAC or DHCP
- # stateless and other IPv4 is with DHCP of IPv4, port shall receive
- # EUI-64 IP addresses from first subnet and IPv4 DHCP address from
- # second one. Order of subnet creating should be unimportant.
+ """Test eui64 ip when setting slaac and stateless for subnets
+
+ NOTE: When one IPv6 subnet configured with dnsmasq SLAAC or DHCP
+ stateless and other IPv4 is with DHCP of IPv4, port shall receive
+ EUI-64 IP addresses from first subnet and IPv4 DHCP address from
+ second one. Order of subnet creating should be unimportant.
+ """
for order in ("slaac_first", "dhcp_first"):
for ra_mode, add_mode in (
('slaac', 'slaac'),
@@ -271,8 +286,11 @@
@decorators.idempotent_id('4ab211a0-276f-4552-9070-51e27f58fecf')
def test_dhcp_stateful(self):
- # NOTE: With all options below, DHCPv6 shall allocate address from
- # subnet pool to port.
+ """Test creating port when setting stateful for subnets
+
+ NOTE: With all options below, DHCPv6 shall allocate address from
+ subnet pool to port.
+ """
for ra_mode, add_mode in (
('dhcpv6-stateful', 'dhcpv6-stateful'),
('dhcpv6-stateful', None),
@@ -294,9 +312,12 @@
@decorators.idempotent_id('51a5e97f-f02e-4e4e-9a17-a69811d300e3')
def test_dhcp_stateful_fixedips(self):
- # NOTE: With all options below, port shall be able to get
- # requested IP from fixed IP range not depending on
- # DHCP stateful (not SLAAC!) settings configured.
+ """Test creating port with fixed ip when setting stateful for subnets
+
+ NOTE: With all options below, port shall be able to get
+ requested IP from fixed IP range not depending on
+ DHCP stateful (not SLAAC!) settings configured.
+ """
for ra_mode, add_mode in (
('dhcpv6-stateful', 'dhcpv6-stateful'),
('dhcpv6-stateful', None),
@@ -324,8 +345,11 @@
@decorators.idempotent_id('98244d88-d990-4570-91d4-6b25d70d08af')
def test_dhcp_stateful_fixedips_outrange(self):
- # NOTE: When port gets IP address from fixed IP range it
- # shall be checked if it's from subnets range.
+ """Test creating port with fixed ip that is not in the range
+
+ NOTE: When port gets IP address from fixed IP range it
+ shall be checked if it's from subnets range.
+ """
kwargs = {'ipv6_ra_mode': 'dhcpv6-stateful',
'ipv6_address_mode': 'dhcpv6-stateful'}
subnet = self.create_subnet(self.network, **kwargs)
@@ -342,8 +366,11 @@
@decorators.idempotent_id('57b8302b-cba9-4fbb-8835-9168df029051')
def test_dhcp_stateful_fixedips_duplicate(self):
- # NOTE: When port gets IP address from fixed IP range it
- # shall be checked if it's not duplicate.
+ """Test creating port with duplicate fixed ip
+
+ NOTE: When port gets IP address from fixed IP range it
+ shall be checked if it's not duplicate.
+ """
kwargs = {'ipv6_ra_mode': 'dhcpv6-stateful',
'ipv6_address_mode': 'dhcpv6-stateful'}
subnet = self.create_subnet(self.network, **kwargs)
@@ -376,8 +403,11 @@
@decorators.idempotent_id('e98f65db-68f4-4330-9fea-abd8c5192d4d')
def test_dhcp_stateful_router(self):
- # NOTE: With all options below the router interface shall
- # receive DHCPv6 IP address from allocation pool.
+ """Test creating router with dhcp stateful
+
+ NOTE: With all options below the router interface shall
+ receive DHCPv6 IP address from allocation pool.
+ """
for ra_mode, add_mode in (
('dhcpv6-stateful', 'dhcpv6-stateful'),
('dhcpv6-stateful', None),
diff --git a/tempest/api/network/test_extensions.py b/tempest/api/network/test_extensions.py
index 4804ada..e116d7c 100644
--- a/tempest/api/network/test_extensions.py
+++ b/tempest/api/network/test_extensions.py
@@ -32,7 +32,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('ef28c7e6-e646-4979-9d67-deb207bc5564')
def test_list_show_extensions(self):
- # List available extensions for the project
+ """List available extensions and show the detail of each extension"""
expected_alias = ['security-group', 'l3_agent_scheduler',
'ext-gw-mode', 'binding', 'quotas',
'agent', 'dhcp_agent_scheduler', 'provider',
diff --git a/tempest/api/network/test_extra_dhcp_options.py b/tempest/api/network/test_extra_dhcp_options.py
index d363081..bc6418a 100644
--- a/tempest/api/network/test_extra_dhcp_options.py
+++ b/tempest/api/network/test_extra_dhcp_options.py
@@ -58,7 +58,7 @@
@decorators.idempotent_id('d2c17063-3767-4a24-be4f-a23dbfa133c9')
def test_create_list_port_with_extra_dhcp_options(self):
- # Create a port with Extra DHCP Options
+ """Test creating a port with Extra DHCP Options and list those"""
body = self.ports_client.create_port(
network_id=self.network['id'],
name=data_utils.rand_name(self.__class__.__name__),
@@ -76,7 +76,7 @@
@decorators.idempotent_id('9a6aebf4-86ee-4f47-b07a-7f7232c55607')
def test_update_show_port_with_extra_dhcp_options(self):
- # Update port with extra dhcp options
+ """Test updating port with extra DHCP options and show that port"""
name = data_utils.rand_name('new-port-name')
self.ports_client.update_port(
self.port['id'],
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index abcbbf7..c32d3c1 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -73,6 +73,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('62595970-ab1c-4b7f-8fcc-fddfe55e8718')
def test_create_list_show_update_delete_floating_ip(self):
+ """Test create/list/show/update/delete floating ip"""
# Creates a floating IP
body = self.floating_ips_client.create_floatingip(
floating_network_id=self.ext_net_id,
@@ -133,6 +134,14 @@
@decorators.idempotent_id('e1f6bffd-442f-4668-b30e-df13f2705e77')
def test_floating_ip_delete_port(self):
+ """Test deleting floating ip's port
+
+ 1. Create a floating ip
+ 2. Create a port
+ 3. Update the floating ip's port_id to the created port
+ 4. Delete the port
+ 5. Verify that the port details are cleared from the floating ip
+ """
# Create a floating IP
body = self.floating_ips_client.create_floatingip(
floating_network_id=self.ext_net_id)
@@ -163,6 +172,7 @@
@decorators.idempotent_id('1bb2f731-fe5a-4b8c-8409-799ade1bed4d')
def test_floating_ip_update_different_router(self):
+ """Test associating a floating ip to a port on different router"""
# Associate a floating IP to a port on a router
body = self.floating_ips_client.create_floatingip(
floating_network_id=self.ext_net_id,
@@ -211,6 +221,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('36de4bd0-f09c-43e3-a8e1-1decc1ffd3a5')
def test_create_floating_ip_specifying_a_fixed_ip_address(self):
+ """Test creating floating ip with specified fixed ip"""
body = self.floating_ips_client.create_floatingip(
floating_network_id=self.ext_net_id,
port_id=self.ports[1]['id'],
@@ -230,6 +241,12 @@
@decorators.idempotent_id('45c4c683-ea97-41ef-9c51-5e9802f2f3d7')
def test_create_update_floatingip_with_port_multiple_ip_address(self):
+ """Test updating floating ip's fixed_ips to another ip of same port
+
+ First we create a port with 2 fixed ips, then we create a floating ip
+ with one of the fixed ips, and then we update the floating ip to
+ another fixed ip of that port.
+ """
# Find out ips that can be used for tests
list_ips = net_utils.get_unused_ip_addresses(
self.ports_client,
diff --git a/tempest/api/network/test_floating_ips_negative.py b/tempest/api/network/test_floating_ips_negative.py
index 1688c9d..80df5d6 100644
--- a/tempest/api/network/test_floating_ips_negative.py
+++ b/tempest/api/network/test_floating_ips_negative.py
@@ -58,6 +58,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('22996ea8-4a81-4b27-b6e1-fa5df92fa5e8')
def test_create_floatingip_with_port_ext_net_unreachable(self):
+ """Creating floating ip when port's external network is unreachable"""
self.assertRaises(
lib_exc.NotFound, self.floating_ips_client.create_floatingip,
floating_network_id=self.ext_net_id, port_id=self.port['id'],
@@ -67,6 +68,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('50b9aeb4-9f0b-48ee-aa31-fa955a48ff54')
def test_create_floatingip_in_private_network(self):
+ """Test creating floating in private network"""
self.assertRaises(lib_exc.BadRequest,
self.floating_ips_client.create_floatingip,
floating_network_id=self.network['id'],
@@ -77,6 +79,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('6b3b8797-6d43-4191-985c-c48b773eb429')
def test_associate_floatingip_port_ext_net_unreachable(self):
+ """Associate floating ip to port with unreachable external network"""
# Create floating ip
body = self.floating_ips_client.create_floatingip(
floating_network_id=self.ext_net_id)
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index eba1f6c..7646b63 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -29,6 +29,7 @@
class BaseNetworkTestResources(base.BaseNetworkTest):
+ """Test networks"""
@classmethod
def resource_setup(cls):
@@ -158,6 +159,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('0e269138-0da6-4efc-a46d-578161e7b221')
def test_create_update_delete_network_subnet(self):
+ """Verify creating, updating and deleting network subnet"""
# Create a network
network = self.create_network()
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
@@ -183,7 +185,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('2bf13842-c93f-4a69-83ed-717d2ec3b44e')
def test_show_network(self):
- # Verify the details of a network
+ """Verify the details of a network"""
body = self.networks_client.show_network(self.network['id'])
network = body['network']
for key in ['id', 'name']:
@@ -191,7 +193,7 @@
@decorators.idempotent_id('867819bb-c4b6-45f7-acf9-90edcf70aa5e')
def test_show_network_fields(self):
- # Verify specific fields of a network
+ """Verify specific fields of a network"""
fields = ['id', 'name']
if utils.is_extension_enabled('net-mtu', 'network'):
fields.append('mtu')
@@ -207,7 +209,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('f7ffdeda-e200-4a7a-bcbe-05716e86bf43')
def test_list_networks(self):
- # Verify the network exists in the list of all networks
+ """Verify the network exists in the list of all networks"""
body = self.networks_client.list_networks()
networks = [network['id'] for network in body['networks']
if network['id'] == self.network['id']]
@@ -215,7 +217,7 @@
@decorators.idempotent_id('6ae6d24f-9194-4869-9c85-c313cb20e080')
def test_list_networks_fields(self):
- # Verify specific fields of the networks
+ """Verify specific fields of the networks"""
fields = ['id', 'name']
if utils.is_extension_enabled('net-mtu', 'network'):
fields.append('mtu')
@@ -228,7 +230,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('bd635d81-6030-4dd1-b3b9-31ba0cfdf6cc')
def test_show_subnet(self):
- # Verify the details of a subnet
+ """Verify the details of a subnet"""
body = self.subnets_client.show_subnet(self.subnet['id'])
subnet = body['subnet']
self.assertNotEmpty(subnet, "Subnet returned has no fields")
@@ -238,7 +240,7 @@
@decorators.idempotent_id('270fff0b-8bfc-411f-a184-1e8fd35286f0')
def test_show_subnet_fields(self):
- # Verify specific fields of a subnet
+ """Verify specific fields of a subnet"""
fields = ['id', 'network_id']
body = self.subnets_client.show_subnet(self.subnet['id'],
fields=fields)
@@ -250,7 +252,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('db68ba48-f4ea-49e9-81d1-e367f6d0b20a')
def test_list_subnets(self):
- # Verify the subnet exists in the list of all subnets
+ """Verify the subnet exists in the list of all subnets"""
body = self.subnets_client.list_subnets()
subnets = [subnet['id'] for subnet in body['subnets']
if subnet['id'] == self.subnet['id']]
@@ -258,7 +260,7 @@
@decorators.idempotent_id('842589e3-9663-46b0-85e4-7f01273b0412')
def test_list_subnets_fields(self):
- # Verify specific fields of subnets
+ """Verify specific fields of subnets"""
fields = ['id', 'network_id']
body = self.subnets_client.list_subnets(fields=fields)
subnets = body['subnets']
@@ -268,6 +270,7 @@
@decorators.idempotent_id('f04f61a9-b7f3-4194-90b2-9bcf660d1bfe')
def test_delete_network_with_subnet(self):
+ """Verify deleting network with subnet"""
# Creates a network
network = self.create_network()
net_id = network['id']
@@ -287,34 +290,41 @@
@decorators.idempotent_id('d2d596e2-8e76-47a9-ac51-d4648009f4d3')
def test_create_delete_subnet_without_gateway(self):
+ """Verify creating and deleting subnet without gateway"""
self._create_verify_delete_subnet()
@decorators.idempotent_id('9393b468-186d-496d-aa36-732348cd76e7')
def test_create_delete_subnet_with_gw(self):
+ """Verify creating and deleting subnet with gateway"""
self._create_verify_delete_subnet(
**self.subnet_dict(['gateway']))
@decorators.idempotent_id('bec949c4-3147-4ba6-af5f-cd2306118404')
def test_create_delete_subnet_with_allocation_pools(self):
+ """Verify creating and deleting subnet with allocation pools"""
self._create_verify_delete_subnet(
**self.subnet_dict(['allocation_pools']))
@decorators.idempotent_id('8217a149-0c6c-4cfb-93db-0486f707d13f')
def test_create_delete_subnet_with_gw_and_allocation_pools(self):
+ """Verify create/delete subnet with gateway and allocation pools"""
self._create_verify_delete_subnet(**self.subnet_dict(
['gateway', 'allocation_pools']))
@decorators.idempotent_id('d830de0a-be47-468f-8f02-1fd996118289')
def test_create_delete_subnet_with_host_routes_and_dns_nameservers(self):
+ """Verify create/delete subnet with host routes and name servers"""
self._create_verify_delete_subnet(
**self.subnet_dict(['host_routes', 'dns_nameservers']))
@decorators.idempotent_id('94ce038d-ff0a-4a4c-a56b-09da3ca0b55d')
def test_create_delete_subnet_with_dhcp_enabled(self):
+ """Verify create/delete subnet with dhcp enabled"""
self._create_verify_delete_subnet(enable_dhcp=True)
@decorators.idempotent_id('3d3852eb-3009-49ec-97ac-5ce83b73010a')
def test_update_subnet_gw_dns_host_routes_dhcp(self):
+ """Verify updating subnet's gateway/nameserver/routes/dhcp"""
network = self.create_network()
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.networks_client.delete_network, network['id'])
@@ -349,6 +359,7 @@
@decorators.idempotent_id('a4d9ec4c-0306-4111-a75c-db01a709030b')
def test_create_delete_subnet_all_attributes(self):
+ """Verify create/delete subnet's all attributes"""
self._create_verify_delete_subnet(
enable_dhcp=True,
**self.subnet_dict(['gateway', 'host_routes', 'dns_nameservers']))
@@ -359,6 +370,7 @@
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_external_network_visibility(self):
+ """Verify external network's visibility"""
public_network_id = CONF.network.public_network_id
# find external network matching public_network_id
@@ -394,6 +406,7 @@
@utils.requires_ext(extension="standard-attr-description",
service="network")
def test_create_update_network_description(self):
+ """Verify creating and updating network's description"""
body = self.create_network(description='d1')
self.assertEqual('d1', body['description'])
net_id = body['id']
@@ -454,6 +467,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('d4f9024d-1e28-4fc1-a6b1-25dbc6fa11e2')
def test_bulk_create_delete_network(self):
+ """Verify creating and deleting multiple networks in one request"""
# Creates 2 networks in one request
network_list = [{'name': data_utils.rand_name('network-')},
{'name': data_utils.rand_name('network-')}]
@@ -470,6 +484,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('8936533b-c0aa-4f29-8e53-6cc873aec489')
def test_bulk_create_delete_subnet(self):
+ """Verify creating and deleting multiple subnets in one request"""
networks = [self.create_network(), self.create_network()]
# Creates 2 subnets in one request
cidrs = [subnet_cidr
@@ -499,6 +514,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('48037ff2-e889-4c3b-b86a-8e3f34d2d060')
def test_bulk_create_delete_port(self):
+ """Verify creating and deleting multiple ports in one request"""
networks = [self.create_network(), self.create_network()]
# Creates 2 ports in one request
names = [data_utils.rand_name('port-') for i in range(len(networks))]
@@ -532,6 +548,7 @@
@decorators.idempotent_id('e41a4888-65a6-418c-a095-f7c2ef4ad59a')
def test_create_delete_subnet_with_gw(self):
+ """Verify creating and deleting subnet with gateway"""
net = netaddr.IPNetwork(CONF.network.project_network_v6_cidr)
gateway = str(netaddr.IPAddress(net.first + 2))
network = self.create_network()
@@ -541,6 +558,7 @@
@decorators.idempotent_id('ebb4fd95-524f-46af-83c1-0305b239338f')
def test_create_delete_subnet_with_default_gw(self):
+ """Verify creating and deleting subnet without specified gateway"""
net = netaddr.IPNetwork(CONF.network.project_network_v6_cidr)
gateway_ip = str(netaddr.IPAddress(net.first + 1))
network = self.create_network()
@@ -550,6 +568,12 @@
@decorators.idempotent_id('a9653883-b2a4-469b-8c3c-4518430a7e55')
def test_create_list_subnet_with_no_gw64_one_network(self):
+ """Verify subnets with and without gateway are in one network
+
+ First we create a network, then we create one ipv6 subnet with
+ gateway and one ipv4 subnet without gateway, the two subnets
+ should be in the same network
+ """
network = self.create_network()
ipv6_gateway = self.subnet_dict(['gateway'])['gateway']
subnet1 = self.create_subnet(network,
@@ -589,6 +613,7 @@
@decorators.idempotent_id('da40cd1b-a833-4354-9a85-cd9b8a3b74ca')
def test_create_delete_subnet_with_v6_attributes_stateful(self):
+ """Test create/delete subnet with ipv6 attributes stateful"""
self._create_verify_delete_subnet(
gateway=self._subnet_data[self._ip_version]['gateway'],
ipv6_ra_mode='dhcpv6-stateful',
@@ -596,12 +621,14 @@
@decorators.idempotent_id('176b030f-a923-4040-a755-9dc94329e60c')
def test_create_delete_subnet_with_v6_attributes_slaac(self):
+ """Test create/delete subnet with ipv6 attributes slaac"""
self._create_verify_delete_subnet(
ipv6_ra_mode='slaac',
ipv6_address_mode='slaac')
@decorators.idempotent_id('7d410310-8c86-4902-adf9-865d08e31adb')
def test_create_delete_subnet_with_v6_attributes_stateless(self):
+ """Test create/delete subnet with ipv6 attributes stateless"""
self._create_verify_delete_subnet(
ipv6_ra_mode='dhcpv6-stateless',
ipv6_address_mode='dhcpv6-stateless')
diff --git a/tempest/api/network/test_networks_negative.py b/tempest/api/network/test_networks_negative.py
index 3af67dd..0525484 100644
--- a/tempest/api/network/test_networks_negative.py
+++ b/tempest/api/network/test_networks_negative.py
@@ -21,10 +21,12 @@
class NetworksNegativeTestJSON(base.BaseNetworkTest):
+ """Negative tests of network"""
@decorators.attr(type=['negative'])
@decorators.idempotent_id('9293e937-824d-42d2-8d5b-e985ea67002a')
def test_show_non_existent_network(self):
+ """Test showing non existent network"""
non_exist_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound, self.networks_client.show_network,
non_exist_id)
@@ -32,6 +34,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d746b40c-5e09-4043-99f7-cba1be8b70df')
def test_show_non_existent_subnet(self):
+ """Test showing non existent subnet"""
non_exist_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound, self.subnets_client.show_subnet,
non_exist_id)
@@ -39,6 +42,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('a954861d-cbfd-44e8-b0a9-7fab111f235d')
def test_show_non_existent_port(self):
+ """Test showing non existent port"""
non_exist_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound, self.ports_client.show_port,
non_exist_id)
@@ -46,6 +50,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('98bfe4e3-574e-4012-8b17-b2647063de87')
def test_update_non_existent_network(self):
+ """Test updating non existent network"""
non_exist_id = data_utils.rand_uuid()
self.assertRaises(
lib_exc.NotFound, self.networks_client.update_network,
@@ -54,6 +59,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('03795047-4a94-4120-a0a1-bd376e36fd4e')
def test_delete_non_existent_network(self):
+ """Test deleting non existent network"""
non_exist_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound,
self.networks_client.delete_network,
@@ -62,6 +68,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('1cc47884-ac52-4415-a31c-e7ce5474a868')
def test_update_non_existent_subnet(self):
+ """Test updating non existent subnet"""
non_exist_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound, self.subnets_client.update_subnet,
non_exist_id, name='new_name')
@@ -69,6 +76,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('a176c859-99fb-42ec-a208-8a85b552a239')
def test_delete_non_existent_subnet(self):
+ """Test deleting non existent subnet"""
non_exist_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound,
self.subnets_client.delete_subnet, non_exist_id)
@@ -76,6 +84,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('13d3b106-47e6-4b9b-8d53-dae947f092fe')
def test_create_port_on_non_existent_network(self):
+ """Test creating port on non existent network"""
non_exist_net_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound,
self.ports_client.create_port,
@@ -85,6 +94,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('cf8eef21-4351-4f53-adcd-cc5cb1e76b92')
def test_update_non_existent_port(self):
+ """Test updating non existent port"""
non_exist_port_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound, self.ports_client.update_port,
non_exist_port_id, name='new_name')
@@ -92,6 +102,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('49ec2bbd-ac2e-46fd-8054-798e679ff894')
def test_delete_non_existent_port(self):
+ """Test deleting non existent port"""
non_exist_port_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound,
self.ports_client.delete_port, non_exist_port_id)
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index c4ad720..c6d049a 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -70,6 +70,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('c72c1c0c-2193-4aca-aaa4-b1442640f51c')
def test_create_update_delete_port(self):
+ """Test creating, updating and deleting port"""
# Verify port creation
body = self.ports_client.create_port(
network_id=self.network['id'],
@@ -89,6 +90,7 @@
@decorators.idempotent_id('67f1b811-f8db-43e2-86bd-72c074d4a42c')
def test_create_bulk_port(self):
+ """Test creating multiple ports in a single request"""
network1 = self.network
network2 = self._create_network()
network_list = [network1['id'], network2['id']]
@@ -107,6 +109,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('0435f278-40ae-48cb-a404-b8a087bc09b1')
def test_create_port_in_allowed_allocation_pools(self):
+ """Test creating port in allowed allocation pools"""
network = self._create_network()
net_id = network['id']
address = self.cidr
@@ -136,7 +139,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('c9a685bd-e83f-499c-939f-9f7863ca259f')
def test_show_port(self):
- # Verify the details of port
+ """Verify the details of port"""
body = self.ports_client.show_port(self.port['id'])
port = body['port']
self.assertIn('id', port)
@@ -152,7 +155,7 @@
@decorators.idempotent_id('45fcdaf2-dab0-4c13-ac6c-fcddfb579dbd')
def test_show_port_fields(self):
- # Verify specific fields of a port
+ """Verify specific fields of a port"""
fields = ['id', 'mac_address']
body = self.ports_client.show_port(self.port['id'],
fields=fields)
@@ -164,7 +167,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('cf95b358-3e92-4a29-a148-52445e1ac50e')
def test_list_ports(self):
- # Verify the port exists in the list of all ports
+ """Verify the port exists in the list of all ports"""
body = self.ports_client.list_ports()
ports = [port['id'] for port in body['ports']
if port['id'] == self.port['id']]
@@ -172,6 +175,7 @@
@decorators.idempotent_id('e7fe260b-1e79-4dd3-86d9-bec6a7959fc5')
def test_port_list_filter_by_ip(self):
+ """Test listing ports filtered by ip"""
# Create network and subnet
network = self._create_network()
self._create_subnet(network)
@@ -211,6 +215,7 @@
utils.is_extension_enabled('ip-substring-filtering', 'network'),
'ip-substring-filtering extension not enabled.')
def test_port_list_filter_by_ip_substr(self):
+ """Test listing ports filtered by part of ip address string"""
# Create network and subnet
network = self._create_network()
subnet = self._create_subnet(network)
@@ -289,6 +294,7 @@
@decorators.idempotent_id('5ad01ed0-0e6e-4c5d-8194-232801b15c72')
def test_port_list_filter_by_router_id(self):
+ """Test listing ports filtered by router id"""
# Create a router
network = self._create_network()
self._create_subnet(network)
@@ -313,7 +319,7 @@
@decorators.idempotent_id('ff7f117f-f034-4e0e-abff-ccef05c454b4')
def test_list_ports_fields(self):
- # Verify specific fields of ports
+ """Verify specific fields of ports"""
fields = ['id', 'mac_address']
body = self.ports_client.list_ports(fields=fields)
ports = body['ports']
@@ -324,6 +330,7 @@
@decorators.idempotent_id('63aeadd4-3b49-427f-a3b1-19ca81f06270')
def test_create_update_port_with_second_ip(self):
+ """Test updating port from 2 fixed ips to 1 fixed ip and vice versa"""
# Create a network with two subnets
network = self._create_network()
subnet_1 = self._create_subnet(network)
@@ -410,6 +417,12 @@
utils.is_extension_enabled('security-group', 'network'),
'security-group extension not enabled.')
def test_update_port_with_security_group_and_extra_attributes(self):
+ """Test updating port's security_group along with extra attributes
+
+ First we create a port with one security group, and then we update the
+ port's security_group, in the same update request we also change
+ the port's fixed ips.
+ """
self._update_port_with_security_groups(
[data_utils.rand_name('secgroup')])
@@ -418,12 +431,19 @@
utils.is_extension_enabled('security-group', 'network'),
'security-group extension not enabled.')
def test_update_port_with_two_security_groups_and_extra_attributes(self):
+ """Test updating port with two security_groups and extra attributes
+
+ First we create a port with one security group, and then we update the
+ port to two security_groups, in the same update request we also change
+ the port's fixed ips.
+ """
self._update_port_with_security_groups(
[data_utils.rand_name('secgroup'),
data_utils.rand_name('secgroup')])
@decorators.idempotent_id('13e95171-6cbd-489c-9d7c-3f9c58215c18')
def test_create_show_delete_port_user_defined_mac(self):
+ """Test creating port with user defined mac address"""
# Create a port for a legal mac
body = self.ports_client.create_port(
network_id=self.network['id'],
@@ -450,6 +470,7 @@
utils.is_extension_enabled('security-group', 'network'),
'security-group extension not enabled.')
def test_create_port_with_no_securitygroups(self):
+ """Test creating port without security groups"""
network = self._create_network()
self._create_subnet(network)
port = self.create_port(network, security_groups=[])
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 30423e3..c03a8a2 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -27,6 +27,7 @@
class RoutersTest(base.BaseNetworkTest):
+ """Test routers"""
def _add_router_interface_with_subnet_id(self, router_id, subnet_id):
interface = self.routers_client.add_router_interface(
@@ -53,6 +54,7 @@
@testtools.skipUnless(CONF.network.public_network_id,
'The public_network_id option must be specified.')
def test_create_show_list_update_delete_router(self):
+ """Test create/show/list/update/delete of a router"""
# Create a router
router_name = data_utils.rand_name(self.__class__.__name__ + '-router')
router = self.create_router(
@@ -87,6 +89,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('b42e6e39-2e37-49cc-a6f4-8467e940900a')
def test_add_remove_router_interface_with_subnet_id(self):
+ """Test adding and removing router interface with subnet id"""
network_name = data_utils.rand_name(self.__class__.__name__)
network = self.networks_client.create_network(
name=network_name)['network']
@@ -113,6 +116,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('2b7d2f37-6748-4d78-92e5-1d590234f0d5')
def test_add_remove_router_interface_with_port_id(self):
+ """Test adding and removing router interface with port id"""
network_name = data_utils.rand_name(self.__class__.__name__)
network = self.networks_client.create_network(
name=network_name)['network']
@@ -145,6 +149,7 @@
@decorators.idempotent_id('c86ac3a8-50bd-4b00-a6b8-62af84a0765c')
@utils.requires_ext(extension='extraroute', service='network')
def test_update_delete_extra_route(self):
+ """Test updating and deleting router with extra route"""
# Create different cidr for each subnet to avoid cidr duplicate
# The cidr starts from project_cidr
next_cidr = self.cidr
@@ -215,6 +220,7 @@
@decorators.idempotent_id('a8902683-c788-4246-95c7-ad9c6d63a4d9')
def test_update_router_admin_state(self):
+ """Test updating router's admin state"""
router = self.create_router()
self.addCleanup(self.delete_router, router)
self.assertFalse(router['admin_state_up'])
@@ -228,6 +234,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('802c73c9-c937-4cef-824b-2191e24a6aab')
def test_add_multiple_router_interfaces(self):
+ """Test adding multiple router interfaces"""
network_name = data_utils.rand_name(self.__class__.__name__)
network01 = self.networks_client.create_network(
name=network_name)['network']
@@ -258,6 +265,7 @@
@decorators.idempotent_id('96522edf-b4b5-45d9-8443-fa11c26e6eff')
def test_router_interface_port_update_with_fixed_ip(self):
+ """Test updating router interface port's fixed ip"""
network_name = data_utils.rand_name(self.__class__.__name__)
network = self.networks_client.create_network(
name=network_name)['network']
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index 0b61860..10a2706 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -21,6 +21,7 @@
class RoutersNegativeTest(base.BaseNetworkTest):
+ """Negative tests of routers"""
@classmethod
def skip_checks(cls):
@@ -39,6 +40,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('37a94fc0-a834-45b9-bd23-9a81d2fd1e22')
def test_router_add_gateway_invalid_network_returns_404(self):
+ """Test adding gateway with invalid network for router"""
self.assertRaises(lib_exc.NotFound,
self.routers_client.update_router,
self.router['id'],
@@ -48,6 +50,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('11836a18-0b15-4327-a50b-f0d9dc66bddd')
def test_router_add_gateway_net_not_external_returns_400(self):
+ """Test adding gateway with not external network for router"""
alt_network = self.create_network()
sub_cidr = self.cidr.next()
self.create_subnet(alt_network, cidr=sub_cidr)
@@ -60,6 +63,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('957751a3-3c68-4fa2-93b6-eb52ea10db6e')
def test_add_router_interfaces_on_overlapping_subnets_returns_400(self):
+ """Test adding router interface which is on overlapping subnets"""
network01 = self.create_network(
network_name=data_utils.rand_name('router-network01-'))
network02 = self.create_network(
@@ -79,6 +83,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('04df80f9-224d-47f5-837a-bf23e33d1c20')
def test_router_remove_interface_in_use_returns_409(self):
+ """Test removing in-use interface from router"""
self.routers_client.add_router_interface(self.router['id'],
subnet_id=self.subnet['id'])
self.addCleanup(self.routers_client.remove_router_interface,
@@ -90,6 +95,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('c2a70d72-8826-43a7-8208-0209e6360c47')
def test_show_non_existent_router_returns_404(self):
+ """Test showing non existent router"""
router = data_utils.rand_name('non_exist_router')
self.assertRaises(lib_exc.NotFound, self.routers_client.show_router,
router)
@@ -97,6 +103,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('b23d1569-8b0c-4169-8d4b-6abd34fad5c7')
def test_update_non_existent_router_returns_404(self):
+ """Test updating non existent router"""
router = data_utils.rand_name('non_exist_router')
self.assertRaises(lib_exc.NotFound, self.routers_client.update_router,
router, name="new_name")
@@ -104,6 +111,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('c7edc5ad-d09d-41e6-a344-5c0c31e2e3e4')
def test_delete_non_existent_router_returns_404(self):
+ """Test deleting non existent router"""
router = data_utils.rand_name('non_exist_router')
self.assertRaises(lib_exc.NotFound, self.routers_client.delete_router,
router)
@@ -114,6 +122,7 @@
class DvrRoutersNegativeTest(base.BaseNetworkTest):
+ """Negative tests of DVR router"""
@classmethod
def skip_checks(cls):
@@ -125,5 +134,6 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('4990b055-8fc7-48ab-bba7-aa28beaad0b9')
def test_router_create_tenant_distributed_returns_forbidden(self):
+ """Non admin user is not allowed to create distributed router"""
self.assertRaises(lib_exc.Forbidden, self.create_router,
distributed=True)
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index ef19122..d75acfc 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -21,6 +21,7 @@
class SecGroupTest(base.BaseSecGroupTest):
+ """Test security groups"""
@classmethod
def skip_checks(cls):
@@ -67,7 +68,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('e30abd17-fef9-4739-8617-dc26da88e686')
def test_list_security_groups(self):
- # Verify the security group belonging to project exist in list
+ """Verify that default security group exist"""
body = self.security_groups_client.list_security_groups()
security_groups = body['security_groups']
found = None
@@ -80,6 +81,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('bfd128e5-3c92-44b6-9d66-7fe29d22c802')
def test_create_list_update_show_delete_security_group(self):
+ """Verify create/list/update/show/delete of security group"""
group_create_body, _ = self._create_security_group()
# List security groups and verify if created group is there in response
@@ -111,6 +113,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('cfb99e0e-7410-4a3d-8a0c-959a63ee77e9')
def test_create_show_delete_security_group_rule(self):
+ """Test create/show/delete of security group rule"""
group_create_body, _ = self._create_security_group()
# Create rules for each protocol
@@ -191,7 +194,7 @@
@decorators.idempotent_id('c2ed2deb-7a0c-44d8-8b4c-a5825b5c310b')
def test_create_security_group_rule_with_remote_group_id(self):
- # Verify creating security group rule with remote_group_id works
+ """Verify creating security group rule with remote_group_id works"""
sg1_body, _ = self._create_security_group()
sg2_body, _ = self._create_security_group()
@@ -209,7 +212,7 @@
@decorators.idempotent_id('16459776-5da2-4634-bce4-4b55ee3ec188')
def test_create_security_group_rule_with_remote_ip_prefix(self):
- # Verify creating security group rule with remote_ip_prefix works
+ """Verify creating security group rule with remote_ip_prefix works"""
sg1_body, _ = self._create_security_group()
sg_id = sg1_body['security_group']['id']
@@ -226,9 +229,10 @@
@decorators.idempotent_id('0a307599-6655-4220-bebc-fd70c64f2290')
def test_create_security_group_rule_with_protocol_integer_value(self):
- # Verify creating security group rule with the
- # protocol as integer value
- # arguments : "protocol": 17
+ """Verify creating security group rule with the integer protocol value
+
+ arguments : "protocol": 17
+ """
group_create_body, _ = self._create_security_group()
direction = 'ingress'
protocol = 17
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index d054865..beaeb20 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -24,6 +24,7 @@
class NegativeSecGroupTest(base.BaseSecGroupTest):
+ """Negative tests of security groups"""
@classmethod
def skip_checks(cls):
@@ -35,6 +36,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('424fd5c3-9ddc-486a-b45f-39bf0c820fc6')
def test_show_non_existent_security_group(self):
+ """Test showing non existent security group"""
non_exist_id = data_utils.rand_uuid()
self.assertRaises(
lib_exc.NotFound, self.security_groups_client.show_security_group,
@@ -43,6 +45,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('4c094c09-000b-4e41-8100-9617600c02a6')
def test_show_non_existent_security_group_rule(self):
+ """Test showing non existent security group rule"""
non_exist_id = data_utils.rand_uuid()
self.assertRaises(
lib_exc.NotFound,
@@ -52,6 +55,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('1f1bb89d-5664-4956-9fcd-83ee0fa603df')
def test_delete_non_existent_security_group(self):
+ """Test deleting non existent security group"""
non_exist_id = data_utils.rand_uuid()
self.assertRaises(lib_exc.NotFound,
self.security_groups_client.delete_security_group,
@@ -61,6 +65,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('981bdc22-ce48-41ed-900a-73148b583958')
def test_create_security_group_rule_with_bad_protocol(self):
+ """Test creating security group rule with bad protocol"""
group_create_body, _ = self._create_security_group()
# Create rule with bad protocol name
@@ -74,6 +79,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('5f8daf69-3c5f-4aaa-88c9-db1d66f68679')
def test_create_security_group_rule_with_bad_remote_ip_prefix(self):
+ """Test creating security group rule with bad remote ip prefix"""
group_create_body, _ = self._create_security_group()
# Create rule with bad remote_ip_prefix
@@ -89,6 +95,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('4bf786fd-2f02-443c-9716-5b98e159a49a')
def test_create_security_group_rule_with_non_existent_remote_groupid(self):
+ """Creating security group rule with non existent remote group id"""
group_create_body, _ = self._create_security_group()
non_exist_id = data_utils.rand_uuid()
@@ -105,6 +112,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('b5c4b247-6b02-435b-b088-d10d45650881')
def test_create_security_group_rule_with_remote_ip_and_group(self):
+ """Test creating security group rule with remote ip and group"""
sg1_body, _ = self._create_security_group()
sg2_body, _ = self._create_security_group()
@@ -121,6 +129,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('5666968c-fff3-40d6-9efc-df1c8bd01abb')
def test_create_security_group_rule_with_bad_ethertype(self):
+ """Test creating security group rule with bad bad ethertype"""
group_create_body, _ = self._create_security_group()
# Create rule with bad ethertype
@@ -134,6 +143,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('0d9c7791-f2ad-4e2f-ac73-abf2373b0d2d')
def test_create_security_group_rule_with_invalid_ports(self):
+ """Test creating security group rule with invalid ports"""
group_create_body, _ = self._create_security_group()
# Create rule for tcp protocol with invalid ports
@@ -168,7 +178,10 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('2323061e-9fbf-4eb0-b547-7e8fafc90849')
def test_create_additional_default_security_group_fails(self):
- # Create security group named 'default', it should be failed.
+ """Test creating additional default security group
+
+ Create security group named 'default', it should be failed.
+ """
name = 'default'
self.assertRaises(lib_exc.Conflict,
self.security_groups_client.create_security_group,
@@ -177,7 +190,10 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('966e2b96-023a-11e7-a9e4-fa163e4fa634')
def test_create_security_group_update_name_default(self):
- # Update security group name to 'default', it should be failed.
+ """Test updating security group's name to default
+
+ Update security group name to 'default', it should be failed.
+ """
group_create_body, _ = self._create_security_group()
self.assertRaises(lib_exc.Conflict,
self.security_groups_client.update_security_group,
@@ -187,7 +203,10 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('8fde898f-ce88-493b-adc9-4e4692879fc5')
def test_create_duplicate_security_group_rule_fails(self):
- # Create duplicate security group rule, it should fail.
+ """Test creating duplicate security group rule
+
+ Create duplicate security group rule, it should fail.
+ """
body, _ = self._create_security_group()
min_port = 66
@@ -213,7 +232,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('be308db6-a7cf-4d5c-9baf-71bafd73f35e')
def test_create_security_group_rule_with_non_existent_security_group(self):
- # Create security group rules with not existing security group.
+ """Creating security group rules with not existing security group"""
non_existent_sg = data_utils.rand_uuid()
self.assertRaises(
lib_exc.NotFound,
@@ -228,6 +247,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('7607439c-af73-499e-bf64-f687fd12a842')
def test_create_security_group_rule_wrong_ip_prefix_version(self):
+ """Test creating security group rule with wrong ip prefix version"""
group_create_body, _ = self._create_security_group()
# Create rule with bad remote_ip_prefix
diff --git a/tempest/api/network/test_service_providers.py b/tempest/api/network/test_service_providers.py
index 9ebcd89..5af5244 100644
--- a/tempest/api/network/test_service_providers.py
+++ b/tempest/api/network/test_service_providers.py
@@ -18,12 +18,14 @@
class ServiceProvidersTest(base.BaseNetworkTest):
+ """Test network service providers"""
@decorators.idempotent_id('2cbbeea9-f010-40f6-8df5-4eaa0c918ea6')
@testtools.skipUnless(
utils.is_extension_enabled('service-type', 'network'),
'service-type extension not enabled.')
def test_service_providers_list(self):
+ """Test listing network service providers"""
body = self.service_providers_client.list_service_providers()
self.assertIn('service_providers', body)
self.assertIsInstance(body['service_providers'], list)
diff --git a/tempest/api/network/test_subnetpools_extensions.py b/tempest/api/network/test_subnetpools_extensions.py
index bfc2609..48603ed 100644
--- a/tempest/api/network/test_subnetpools_extensions.py
+++ b/tempest/api/network/test_subnetpools_extensions.py
@@ -49,6 +49,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('62595970-ab1c-4b7f-8fcc-fddfe55e9811')
def test_create_list_show_update_delete_subnetpools(self):
+ """Test create/list/show/update/delete of subnet pools"""
subnetpool_name = data_utils.rand_name('subnetpools')
# create subnet pool
prefix = CONF.network.default_network
diff --git a/tempest/api/network/test_tags.py b/tempest/api/network/test_tags.py
index 2b9719a..5219c34 100644
--- a/tempest/api/network/test_tags.py
+++ b/tempest/api/network/test_tags.py
@@ -51,7 +51,7 @@
@decorators.idempotent_id('ee76bfaf-ac94-4d74-9ecc-4bbd4c583cb1')
def test_create_list_show_update_delete_tags(self):
- # Validate that creating a tag on a network resource works.
+ """Validate that creating a tag on a network resource works"""
tag_name = data_utils.rand_name(self.__class__.__name__ + '-Tag')
self.tags_client.create_tag('networks', self.network['id'], tag_name)
self.addCleanup(self.tags_client.delete_all_tags, 'networks',
@@ -158,6 +158,7 @@
@decorators.idempotent_id('c6231efa-9a89-4adf-b050-2a3156b8a1d9')
def test_create_check_list_and_delete_tags(self):
+ """Test tag operations on subnets/ports/routers/subnetpools"""
tag_names = self._create_tags_for_each_resource()
for i, resource in enumerate(self.SUPPORTED_RESOURCES):
@@ -181,6 +182,7 @@
@decorators.idempotent_id('663a90f5-f334-4b44-afe0-c5fc1d408791')
def test_update_and_delete_all_tags(self):
+ """Test update/delete all tags on subnets/ports/routers/subnetpools"""
self._create_tags_for_each_resource()
for resource in self.SUPPORTED_RESOURCES:
diff --git a/tempest/api/volume/admin/test_groups.py b/tempest/api/volume/admin/test_groups.py
index 2f6eb6b..e67b985 100644
--- a/tempest/api/volume/admin/test_groups.py
+++ b/tempest/api/volume/admin/test_groups.py
@@ -23,12 +23,15 @@
class GroupsTest(base.BaseVolumeAdminTest):
+ """Tests of volume groups with microversion greater than 3.12"""
+
_api_version = 3
min_microversion = '3.13'
max_microversion = 'latest'
@decorators.idempotent_id('4b111d28-b73d-4908-9bd2-03dc2992e4d4')
def test_group_create_show_list_delete(self):
+ """Test creating, showing, listing and deleting of volume group"""
# Create volume type
volume_type = self.create_volume_type()
@@ -95,6 +98,7 @@
@decorators.idempotent_id('4a8a6fd2-8b3b-4641-8f54-6a6f99320006')
def test_group_update(self):
+ """Test updating volume group"""
# Create volume type
volume_type = self.create_volume_type()
@@ -150,12 +154,15 @@
class GroupsV314Test(base.BaseVolumeAdminTest):
+ """Tests of volume groups with microversion greater than 3.13"""
+
_api_version = 3
min_microversion = '3.14'
max_microversion = 'latest'
@decorators.idempotent_id('2424af8c-7851-4888-986a-794b10c3210e')
def test_create_group_from_group(self):
+ """Test creating volume group from volume group"""
# Create volume type
volume_type = self.create_volume_type()
@@ -185,12 +192,15 @@
class GroupsV320Test(base.BaseVolumeAdminTest):
+ """Tests of volume groups with microversion greater than 3.19"""
+
_api_version = 3
min_microversion = '3.20'
max_microversion = 'latest'
@decorators.idempotent_id('b20c696b-0cbc-49a5-8b3a-b1fb9338f45c')
def test_reset_group_status(self):
+ """Test resetting volume group status to creating/available/error"""
# Create volume type
volume_type = self.create_volume_type()
diff --git a/tempest/api/volume/admin/test_snapshot_manage.py b/tempest/api/volume/admin/test_snapshot_manage.py
index 37a47ec..ab0aa38 100644
--- a/tempest/api/volume/admin/test_snapshot_manage.py
+++ b/tempest/api/volume/admin/test_snapshot_manage.py
@@ -48,6 +48,7 @@
@decorators.idempotent_id('0132f42d-0147-4b45-8501-cc504bbf7810')
def test_unmanage_manage_snapshot(self):
+ """Test unmanaging and managing volume snapshot"""
# Create a volume
volume = self.create_volume()
diff --git a/tempest/api/volume/admin/test_user_messages.py b/tempest/api/volume/admin/test_user_messages.py
index 8048017..096709c 100644
--- a/tempest/api/volume/admin/test_user_messages.py
+++ b/tempest/api/volume/admin/test_user_messages.py
@@ -22,6 +22,8 @@
class UserMessagesTest(base.BaseVolumeAdminTest):
+ """Test volume messages with microversion greater than 3.2"""
+
_api_version = 3
min_microversion = '3.3'
max_microversion = 'latest'
@@ -51,6 +53,7 @@
@decorators.idempotent_id('50f29e6e-f363-42e1-8ad1-f67ae7fd4d5a')
def test_list_show_messages(self):
+ """Test listing and showing volume messages"""
message_id = self._create_user_message()
self.addCleanup(self.messages_client.delete_message, message_id)
@@ -62,6 +65,7 @@
@decorators.idempotent_id('c6eb6901-cdcc-490f-b735-4fe251842aed')
def test_delete_message(self):
+ """Test deleting volume messages"""
message_id = self._create_user_message()
self.messages_client.delete_message(message_id)
self.messages_client.wait_for_resource_deletion(message_id)
diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
index 83c27e1..e4e15c5 100644
--- a/tempest/api/volume/admin/test_volume_hosts.py
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -18,9 +18,11 @@
class VolumeHostsAdminTestsJSON(base.BaseVolumeAdminTest):
+ """Test fetching volume hosts info by admin users"""
@decorators.idempotent_id('d5f3efa2-6684-4190-9ced-1c2f526352ad')
def test_list_hosts(self):
+ """Test listing volume hosts"""
hosts = self.admin_hosts_client.list_hosts()['hosts']
self.assertGreaterEqual(len(hosts), 2,
"The count of volume hosts is < 2, "
@@ -28,6 +30,7 @@
@decorators.idempotent_id('21168d57-b373-4b71-a3ac-f2c88f0c5d31')
def test_show_host(self):
+ """Test getting volume host details"""
hosts = self.admin_hosts_client.list_hosts()['hosts']
self.assertGreaterEqual(len(hosts), 2,
"The count of volume hosts is < 2, "
diff --git a/tempest/api/volume/admin/test_volume_manage.py b/tempest/api/volume/admin/test_volume_manage.py
index 4b352e0..1e4e7cb 100644
--- a/tempest/api/volume/admin/test_volume_manage.py
+++ b/tempest/api/volume/admin/test_volume_manage.py
@@ -24,6 +24,7 @@
class VolumeManageAdminTest(base.BaseVolumeAdminTest):
+ """Test volume manage by admin users"""
@classmethod
def skip_checks(cls):
@@ -39,6 +40,7 @@
@decorators.idempotent_id('70076c71-0ce1-4208-a8ff-36a66e65cc1e')
def test_unmanage_manage_volume(self):
+ """Test unmanaging and managing volume"""
# Create original volume
org_vol_id = self.create_volume()['id']
org_vol_info = self.admin_volume_client.show_volume(
diff --git a/tempest/api/volume/admin/test_volume_pools.py b/tempest/api/volume/admin/test_volume_pools.py
index 744bc01..9424994 100644
--- a/tempest/api/volume/admin/test_volume_pools.py
+++ b/tempest/api/volume/admin/test_volume_pools.py
@@ -21,6 +21,8 @@
class VolumePoolsAdminTestsJSON(base.BaseVolumeAdminTest):
+ """Test getting volume pools by admin users"""
+
def _assert_pools(self, with_detail=False):
cinder_pools = self.admin_scheduler_stats_client.list_pools(
detail=with_detail)['pools']
@@ -33,8 +35,10 @@
@decorators.idempotent_id('0248a46c-e226-4933-be10-ad6fca8227e7')
def test_get_pools_without_details(self):
+ """Test getting volume pools without detail"""
self._assert_pools()
@decorators.idempotent_id('d4bb61f7-762d-4437-b8a4-5785759a0ced')
def test_get_pools_with_details(self):
+ """Test getting volume pools with detail"""
self._assert_pools(with_detail=True)
diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py
index 5c7ab15..937d28b 100644
--- a/tempest/api/volume/admin/test_volume_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_quotas_negative.py
@@ -24,6 +24,7 @@
class VolumeQuotasNegativeTestJSON(base.BaseVolumeAdminTest):
+ """Negative tests of volume quotas"""
@classmethod
def setup_credentials(cls):
@@ -52,6 +53,7 @@
@decorators.attr(type='negative')
@decorators.idempotent_id('bf544854-d62a-47f2-a681-90f7a47d86b6')
def test_quota_volumes(self):
+ """Creating more volume than allowed quota will fail"""
self.admin_quotas_client.update_quota_set(self.demo_tenant_id,
volumes=1, gigabytes=-1)
self.assertRaises(lib_exc.OverLimit,
@@ -61,6 +63,7 @@
@decorators.attr(type='negative')
@decorators.idempotent_id('2dc27eee-8659-4298-b900-169d71a91374')
def test_quota_volume_gigabytes(self):
+ """Creating volume with size larger than allowed quota will fail"""
self.admin_quotas_client.update_quota_set(
self.demo_tenant_id, gigabytes=CONF.volume.volume_size, volumes=-1)
self.assertRaises(lib_exc.OverLimit,
@@ -70,6 +73,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('d321dc21-d8c6-401f-95fe-49f4845f1a6d')
def test_volume_extend_gigabytes_quota_deviation(self):
+ """Extending volume with size larger than allowed quota will fail"""
self.admin_quotas_client.update_quota_set(
self.demo_tenant_id, gigabytes=CONF.volume.volume_size)
self.assertRaises(lib_exc.OverLimit,
diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py
index ae29049..174cf9e 100644
--- a/tempest/api/volume/admin/test_volume_types_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_negative.py
@@ -20,11 +20,12 @@
class VolumeTypesNegativeTest(base.BaseVolumeAdminTest):
+ """Negative tests of volume type"""
@decorators.attr(type=['negative'])
@decorators.idempotent_id('878b4e57-faa2-4659-b0d1-ce740a06ae81')
def test_create_with_empty_name(self):
- # Should not be able to create volume type with an empty name.
+ """Test creating volume type with an empty name will fail"""
self.assertRaises(
lib_exc.BadRequest,
self.admin_volume_types_client.create_volume_type, name='')
@@ -32,7 +33,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('994610d6-0476-4018-a644-a2602ef5d4aa')
def test_get_nonexistent_type_id(self):
- # Should not be able to get volume type with nonexistent type id.
+ """Test getting volume type with nonexistent type id will fail"""
self.assertRaises(lib_exc.NotFound,
self.admin_volume_types_client.show_volume_type,
data_utils.rand_uuid())
@@ -40,7 +41,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('6b3926d2-7d73-4896-bc3d-e42dfd11a9f6')
def test_delete_nonexistent_type_id(self):
- # Should not be able to delete volume type with nonexistent type id.
+ """Test deleting volume type with nonexistent type id will fail"""
self.assertRaises(lib_exc.NotFound,
self.admin_volume_types_client.delete_volume_type,
data_utils.rand_uuid())
@@ -48,7 +49,7 @@
@decorators.attr(type=['negative'])
@decorators.idempotent_id('8c09f849-f225-4d78-ba87-bffd9a5e0c6f')
def test_create_volume_with_private_volume_type(self):
- # Should not be able to create volume with private volume type.
+ """Test creating volume with private volume type will fail"""
params = {'os-volume-type-access:is_public': False}
volume_type = self.create_volume_type(**params)
self.assertRaises(lib_exc.NotFound,
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index 5bac3d8..33e503f 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -23,6 +23,8 @@
class VolumesActionsTest(base.BaseVolumeAdminTest):
+ """Test volume actions"""
+
create_default_network = True
def _create_reset_and_force_delete_temp_volume(self, status=None):
@@ -38,7 +40,10 @@
@decorators.idempotent_id('d063f96e-a2e0-4f34-8b8a-395c42de1845')
def test_volume_reset_status(self):
- # test volume reset status : available->error->available->maintenance
+ """Test resetting volume status
+
+ Reset volume status to available->error->available->maintenance
+ """
volume = self.create_volume()
self.addCleanup(waiters.wait_for_volume_resource_status,
self.volumes_client, volume['id'], 'available')
@@ -52,27 +57,28 @@
@decorators.idempotent_id('21737d5a-92f2-46d7-b009-a0cc0ee7a570')
def test_volume_force_delete_when_volume_is_creating(self):
- # test force delete when status of volume is creating
+ """Test force deleting volume when its status is creating"""
self._create_reset_and_force_delete_temp_volume('creating')
@decorators.idempotent_id('db8d607a-aa2e-4beb-b51d-d4005c232011')
def test_volume_force_delete_when_volume_is_attaching(self):
- # test force delete when status of volume is attaching
+ """Test force deleting volume when its status is attaching"""
self._create_reset_and_force_delete_temp_volume('attaching')
@decorators.idempotent_id('3e33a8a8-afd4-4d64-a86b-c27a185c5a4a')
def test_volume_force_delete_when_volume_is_error(self):
- # test force delete when status of volume is error
+ """Test force deleting volume when its status is error"""
self._create_reset_and_force_delete_temp_volume('error')
@decorators.idempotent_id('b957cabd-1486-4e21-90cf-a9ed3c39dfb2')
def test_volume_force_delete_when_volume_is_maintenance(self):
- # test force delete when status of volume is maintenance
+ """Test force deleting volume when its status is maintenance"""
self._create_reset_and_force_delete_temp_volume('maintenance')
@decorators.idempotent_id('d38285d9-929d-478f-96a5-00e66a115b81')
@utils.services('compute')
def test_force_detach_volume(self):
+ """Test force detaching volume when its status is error"""
# Create a server and a volume
server_id = self.create_server()['id']
volume_id = self.create_volume()['id']
diff --git a/tempest/config.py b/tempest/config.py
index 11f9426..eca2023 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from __future__ import print_function
-
import os
import tempfile
@@ -658,6 +656,12 @@
'are current one. In future, Tempest will '
'test v2 APIs only so this config option '
'will be removed.'),
+ # Image import feature is setup in devstack victoria onwards.
+ # Once all stable branches setup the same via glance standalone
+ # mode or with uwsgi, we can remove this config option.
+ cfg.BoolOpt('import_image',
+ default=False,
+ help="Is image import feature enabled"),
]
network_group = cfg.OptGroup(name='network',
diff --git a/tempest/lib/api_schema/response/volume/group_types.py b/tempest/lib/api_schema/response/volume/group_types.py
index bcfa32e..4fc9ae8 100644
--- a/tempest/lib/api_schema/response/volume/group_types.py
+++ b/tempest/lib/api_schema/response/volume/group_types.py
@@ -73,6 +73,18 @@
}
}
+show_default_group_type = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'group_type': common_show_group_type
+ },
+ 'additionalProperties': False,
+ 'required': ['group_type']
+ }
+}
+
update_group_type = {
'status_code': [200],
'response_body': {
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index 1d524f0..0513e90 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -914,12 +914,44 @@
raise exceptions.TimeoutException(message)
time.sleep(self.build_interval)
+ def wait_for_resource_activation(self, id):
+ """Waits for a resource to become active
+
+ This method will loop over is_resource_active until either
+ is_resource_active returns True or the build timeout is reached. This
+ depends on is_resource_active being implemented
+
+ :param str id: The id of the resource to check
+ :raises TimeoutException: If the build_timeout has elapsed and the
+ resource still hasn't been active
+ """
+ start_time = int(time.time())
+ while True:
+ if self.is_resource_active(id):
+ return
+ if int(time.time()) - start_time >= self.build_timeout:
+ message = ('Failed to reach active state %(resource_type)s '
+ '%(id)s within the required time (%(timeout)s s).' %
+ {'resource_type': self.resource_type, 'id': id,
+ 'timeout': self.build_timeout})
+ caller = test_utils.find_test_caller()
+ if caller:
+ message = '(%s) %s' % (caller, message)
+ raise exceptions.TimeoutException(message)
+ time.sleep(self.build_interval)
+
def is_resource_deleted(self, id):
"""Subclasses override with specific deletion detection."""
message = ('"%s" does not implement is_resource_deleted'
% self.__class__.__name__)
raise NotImplementedError(message)
+ def is_resource_active(self, id):
+ """Subclasses override with specific active detection."""
+ message = ('"%s" does not implement is_resource_active'
+ % self.__class__.__name__)
+ raise NotImplementedError(message)
+
@property
def resource_type(self):
"""Returns the primary type of resource this client works with."""
diff --git a/tempest/lib/common/thread.py b/tempest/lib/common/thread.py
index 510fc36..b47d40d 100644
--- a/tempest/lib/common/thread.py
+++ b/tempest/lib/common/thread.py
@@ -13,10 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-# This make disable relative module import
-from __future__ import absolute_import
-
-
import six
if six.PY2:
diff --git a/tempest/lib/services/image/v2/images_client.py b/tempest/lib/services/image/v2/images_client.py
index 90778da..b9c5776 100644
--- a/tempest/lib/services/image/v2/images_client.py
+++ b/tempest/lib/services/image/v2/images_client.py
@@ -128,6 +128,15 @@
return True
return False
+ def is_resource_active(self, id):
+ try:
+ image = self.show_image(id)
+ if image['status'] != 'active':
+ return False
+ except lib_exc.NotFound:
+ return False
+ return True
+
@property
def resource_type(self):
"""Returns the primary type of resource this client works with."""
@@ -152,6 +161,80 @@
self.expected_success(204, resp.status)
return rest_client.ResponseBody(resp, body)
+ def stage_image_file(self, image_id, data):
+ """Upload binary image data to staging area.
+
+ For a full list of available parameters, please refer to the official
+ API reference (stage API:
+ https://docs.openstack.org/api-ref/image/v2/#interoperable-image-import
+ """
+ url = 'images/%s/stage' % image_id
+
+ # We are going to do chunked transfer, so split the input data
+ # info fixed-sized chunks.
+ headers = {'Content-Type': 'application/octet-stream'}
+ data = iter(functools.partial(data.read, CHUNKSIZE), b'')
+
+ resp, body = self.request('PUT', url, headers=headers,
+ body=data, chunked=True)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
+ def info_import(self):
+ """Return information about server-supported import methods."""
+ url = 'info/import'
+ resp, body = self.get(url)
+
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def info_stores(self):
+ """Return information about server-supported stores."""
+ url = 'info/stores'
+ resp, body = self.get(url)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def image_import(self, image_id, method='glance-direct',
+ all_stores_must_succeed=None, all_stores=True,
+ stores=None):
+ """Import data from staging area to glance store.
+
+ For a full list of available parameters, please refer to the official
+ API reference (stage API:
+ https://docs.openstack.org/api-ref/image/v2/#interoperable-image-import
+
+ :param method: The import method (i.e. glance-direct) to use
+ :param all_stores_must_succeed: Boolean indicating if all store imports
+ must succeed for the import to be
+ considered successful. Must be None if
+ server does not support multistore.
+ :param all_stores: Boolean indicating if image should be imported to
+ all available stores (incompatible with stores)
+ :param stores: A list of destination store names for the import. Must
+ be None if server does not support multistore.
+ """
+ url = 'images/%s/import' % image_id
+ data = {
+ "method": {
+ "name": method
+ },
+ }
+ if stores is not None:
+ data["stores"] = stores
+ else:
+ data["all_stores"] = all_stores
+
+ if all_stores_must_succeed is not None:
+ data['all_stores_must_succeed'] = all_stores_must_succeed
+ data = json.dumps(data)
+ headers = {'Content-Type': 'application/json'}
+ resp, _ = self.post(url, data, headers=headers)
+
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp)
+
def show_image_file(self, image_id):
"""Download binary image data.
diff --git a/tempest/lib/services/volume/v3/group_types_client.py b/tempest/lib/services/volume/v3/group_types_client.py
index e0bf5e2..1dcd508 100644
--- a/tempest/lib/services/volume/v3/group_types_client.py
+++ b/tempest/lib/services/volume/v3/group_types_client.py
@@ -73,7 +73,7 @@
url = 'group_types/default'
resp, body = self.get(url)
body = json.loads(body)
- self.expected_success(200, resp.status)
+ self.validate_response(schema.show_default_group_type, resp, body)
return rest_client.ResponseBody(resp, body)
def show_group_type(self, group_type_id):