Merge "Added tests for Nova microversion v2.47"
diff --git a/doc/source/conf.py b/doc/source/conf.py
index f11d96a..b9e22b5 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -155,8 +155,7 @@
git_cmd = ["git", "log", "--pretty=format:'%ad, commit %h'", "--date=local",
"-n1"]
try:
- html_last_updated_fmt = str(
- subprocess.Popen(git_cmd, stdout=subprocess.PIPE).communicate()[0])
+ html_last_updated_fmt = subprocess.check_output(git_cmd).decode('utf-8')
except Exception:
warnings.warn('Cannot get last updated time from git repository. '
'Not setting "html_last_updated_fmt".')
diff --git a/doc/source/index.rst b/doc/source/index.rst
index c4affd2..f562850 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -24,8 +24,8 @@
field_guide/scenario
field_guide/unit_tests
-For users
-=========
+Users Guide
+===========
Tempest Configuration Guide
---------------------------
@@ -48,8 +48,8 @@
workspace
run
-For developers
-==============
+Developers Guide
+================
Development
-----------
diff --git a/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-endpoint-groups-3518a90bbb731d0f.yaml b/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-endpoint-groups-3518a90bbb731d0f.yaml
new file mode 100644
index 0000000..1dc33aa
--- /dev/null
+++ b/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-endpoint-groups-3518a90bbb731d0f.yaml
@@ -0,0 +1,7 @@
+---
+features:
+ - |
+ Defines the identity v3 OS-EP-FILTER EndPoint Groups API client.
+ This client manages Create, Get, Update, Check, List, and Delete
+ of EndPoint Group.
+
diff --git a/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml b/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml
new file mode 100644
index 0000000..bc7bcc8
--- /dev/null
+++ b/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml
@@ -0,0 +1,7 @@
+---
+features:
+ - |
+ A new config option 'manage_snapshot_ref' is added in the volume section,
+ to specify snapshot ref parameter for different storage backend drivers
+ when managing an existing snapshot. By default it is set to fit the LVM
+ driver.
diff --git a/releasenotes/notes/identity-token-client-8aaef74b1d61090a.yaml b/releasenotes/notes/identity-token-client-8aaef74b1d61090a.yaml
new file mode 100644
index 0000000..d94de3e
--- /dev/null
+++ b/releasenotes/notes/identity-token-client-8aaef74b1d61090a.yaml
@@ -0,0 +1,6 @@
+---
+features:
+ - |
+ Add additional API endpoints to the identity v2 client token API:
+ - list_endpoints_for_token
+ - check_token_existence
diff --git a/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml b/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml
new file mode 100644
index 0000000..9af57b1
--- /dev/null
+++ b/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml
@@ -0,0 +1,8 @@
+---
+features:
+ - |
+ Define v2.0 ``tags_client`` for the network service as a library
+ interface, allowing other projects to use this module as a stable
+ library without maintenance changes.
+
+ * tags_client(v2.0)
diff --git a/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml b/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml
new file mode 100644
index 0000000..afb6006
--- /dev/null
+++ b/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+ - |
+ When receiving nullable list as a response body, tempest.lib
+ rest_client module raised an exception without valid json
+ deserialization. A new release fixes this bug.
diff --git a/requirements.txt b/requirements.txt
index 26e1f02..259a4cf 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,7 +9,7 @@
netaddr!=0.7.16,>=0.7.13 # BSD
testrepository>=0.0.18 # Apache-2.0/BSD
oslo.concurrency>=3.8.0 # Apache-2.0
-oslo.config>=3.22.0 # Apache-2.0
+oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0
oslo.log>=3.22.0 # Apache-2.0
oslo.serialization>=1.10.0 # Apache-2.0
oslo.utils>=3.20.0 # Apache-2.0
@@ -20,6 +20,6 @@
stevedore>=1.20.0 # Apache-2.0
PrettyTable<0.8,>=0.7.1 # BSD
os-testr>=0.8.0 # Apache-2.0
-urllib3>=1.15.1 # MIT
+urllib3>=1.21.1 # MIT
debtcollector>=1.2.0 # Apache-2.0
unittest2 # BSD
diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py
index 31976ec..69cbfb5 100644
--- a/tempest/api/compute/admin/test_agents.py
+++ b/tempest/api/compute/admin/test_agents.py
@@ -86,8 +86,7 @@
body = self.client.create_agent(**self.params_agent)['agent']
self.addCleanup(self.client.delete_agent, body['agent_id'])
agents = self.client.list_agents()['agents']
- self.assertGreater(len(agents), 0,
- 'Cannot get any agents.(%s)' % agents)
+ self.assertNotEmpty(agents, 'Cannot get any agents.(%s)' % agents)
self.assertIn(body['agent_id'], map(lambda x: x['agent_id'], agents))
@decorators.idempotent_id('eabadde4-3cd7-4ec4-a4b5-5a936d2d4408')
@@ -105,8 +104,7 @@
agent_id_xen = agent_xen['agent_id']
agents = (self.client.list_agents(hypervisor=agent_xen['hypervisor'])
['agents'])
- self.assertGreater(len(agents), 0,
- 'Cannot get any agents.(%s)' % agents)
+ self.assertNotEmpty(agents, 'Cannot get any agents.(%s)' % agents)
self.assertIn(agent_id_xen, map(lambda x: x['agent_id'], agents))
self.assertNotIn(body['agent_id'], map(lambda x: x['agent_id'],
agents))
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index 50dec28..bbd39b6 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -29,10 +29,10 @@
def test_get_availability_zone_list(self):
# List of availability zone
availability_zone = self.client.list_availability_zones()
- self.assertGreater(len(availability_zone['availabilityZoneInfo']), 0)
+ self.assertNotEmpty(availability_zone['availabilityZoneInfo'])
@decorators.idempotent_id('ef726c58-530f-44c2-968c-c7bed22d5b8c')
def test_get_availability_zone_list_detail(self):
# List of availability zones and available services
availability_zone = self.client.list_availability_zones(detail=True)
- self.assertGreater(len(availability_zone['availabilityZoneInfo']), 0)
+ self.assertNotEmpty(availability_zone['availabilityZoneInfo'])
diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index 5a38acc..2c236ec 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -50,7 +50,7 @@
flavor_access = (self.admin_flavors_client.list_flavor_access(
flavor['id'])['flavor_access'])
- self.assertEqual(len(flavor_access), 0, str(flavor_access))
+ self.assertEmpty(flavor_access)
@decorators.idempotent_id('59e622f6-bdf6-45e3-8ba8-fedad905a6b4')
def test_flavor_access_add_remove(self):
diff --git a/tempest/api/compute/admin/test_floating_ips_bulk.py b/tempest/api/compute/admin/test_floating_ips_bulk.py
index 056b4bd..496f119 100644
--- a/tempest/api/compute/admin/test_floating_ips_bulk.py
+++ b/tempest/api/compute/admin/test_floating_ips_bulk.py
@@ -73,7 +73,7 @@
self.client.delete_floating_ips_bulk, self.ip_range)
self.assertEqual(self.ip_range, body['ip_range'])
ips_list = self.client.list_floating_ips_bulk()['floating_ip_info']
- self.assertNotEqual(0, len(ips_list))
+ self.assertNotEmpty(ips_list)
for ip in netaddr.IPNetwork(self.ip_range).iter_hosts():
self.assertIn(str(ip), map(lambda x: x['address'], ips_list))
body = (self.client.delete_floating_ips_bulk(self.ip_range)
diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py
index 8e2f6ed..0e1e7ed 100644
--- a/tempest/api/compute/admin/test_hosts.py
+++ b/tempest/api/compute/admin/test_hosts.py
@@ -36,7 +36,7 @@
hosts = self.client.list_hosts()['hosts']
host = hosts[0]
hosts = self.client.list_hosts(zone=host['zone'])['hosts']
- self.assertGreaterEqual(len(hosts), 1)
+ self.assertNotEmpty(hosts)
self.assertIn(host, hosts)
@decorators.idempotent_id('9af3c171-fbf4-4150-a624-22109733c2a6')
@@ -44,26 +44,26 @@
# If send the request with a blank zone, the request will be successful
# and it will return all the hosts list
hosts = self.client.list_hosts(zone='')['hosts']
- self.assertNotEqual(0, len(hosts))
+ self.assertNotEmpty(hosts)
@decorators.idempotent_id('c6ddbadb-c94e-4500-b12f-8ffc43843ff8')
def test_list_hosts_with_nonexistent_zone(self):
# If send the request with a nonexistent zone, the request will be
# successful and no hosts will be returned
hosts = self.client.list_hosts(zone='xxx')['hosts']
- self.assertEqual(0, len(hosts))
+ self.assertEmpty(hosts)
@decorators.idempotent_id('38adbb12-aee2-4498-8aec-329c72423aa4')
def test_show_host_detail(self):
hosts = self.client.list_hosts()['hosts']
hosts = [host for host in hosts if host['service'] == 'compute']
- self.assertGreaterEqual(len(hosts), 1)
+ self.assertNotEmpty(hosts)
for host in hosts:
hostname = host['host_name']
resources = self.client.show_host(hostname)['host']
- self.assertGreaterEqual(len(resources), 1)
+ self.assertNotEmpty(resources)
host_resource = resources[0]['resource']
self.assertIsNotNone(host_resource)
self.assertIsNotNone(host_resource['cpu'])
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index 4544267..0db802c 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -31,7 +31,7 @@
return hypers
def assertHypervisors(self, hypers):
- self.assertGreater(len(hypers), 0, "No hypervisors found: %s" % hypers)
+ self.assertNotEmpty(hypers, "No hypervisors found: %s" % hypers)
@decorators.idempotent_id('7f0ceacd-c64d-4e96-b8ee-d02943142cc5')
def test_get_hypervisor_list(self):
@@ -52,7 +52,7 @@
self.assertHypervisors(hypers)
details = self.client.show_hypervisor(hypers[0]['id'])['hypervisor']
- self.assertGreater(len(details), 0)
+ self.assertNotEmpty(details)
self.assertEqual(details['hypervisor_hostname'],
hypers[0]['hypervisor_hostname'])
@@ -65,14 +65,14 @@
hostname = hypers[0]['hypervisor_hostname']
hypervisors = (self.client.list_servers_on_hypervisor(hostname)
['hypervisors'])
- self.assertGreater(len(hypervisors), 0)
+ self.assertNotEmpty(hypervisors)
@decorators.idempotent_id('797e4f28-b6e0-454d-a548-80cc77c00816')
def test_get_hypervisor_stats(self):
# Verify the stats of the all hypervisor
stats = (self.client.show_hypervisor_statistics()
['hypervisor_statistics'])
- self.assertGreater(len(stats), 0)
+ self.assertNotEmpty(stats)
@decorators.idempotent_id('91a50d7d-1c2b-4f24-b55a-a1fe20efca70')
def test_get_hypervisor_uptime(self):
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index af87287..431e823 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -47,7 +47,7 @@
@decorators.idempotent_id('51e663d0-6b89-4817-a465-20aca0667d03')
def test_show_hypervisor_with_non_admin_user(self):
hypers = self._list_hypervisors()
- self.assertGreater(len(hypers), 0)
+ self.assertNotEmpty(hypers)
self.assertRaises(
lib_exc.Forbidden,
@@ -58,7 +58,7 @@
@decorators.idempotent_id('2a0a3938-832e-4859-95bf-1c57c236b924')
def test_show_servers_with_non_admin_user(self):
hypers = self._list_hypervisors()
- self.assertGreater(len(hypers), 0)
+ self.assertNotEmpty(hypers)
self.assertRaises(
lib_exc.Forbidden,
@@ -96,7 +96,7 @@
@decorators.idempotent_id('6c3461f9-c04c-4e2a-bebb-71dc9cb47df2')
def test_get_hypervisor_uptime_with_non_admin_user(self):
hypers = self._list_hypervisors()
- self.assertGreater(len(hypers), 0)
+ self.assertNotEmpty(hypers)
self.assertRaises(
lib_exc.Forbidden,
@@ -131,7 +131,7 @@
@decorators.idempotent_id('5b6a6c79-5dc1-4fa5-9c58-9c8085948e74')
def test_search_hypervisor_with_non_admin_user(self):
hypers = self._list_hypervisors()
- self.assertGreater(len(hypers), 0)
+ self.assertNotEmpty(hypers)
self.assertRaises(
lib_exc.Forbidden,
diff --git a/tempest/api/compute/admin/test_networks.py b/tempest/api/compute/admin/test_networks.py
index 0ea0a78..acb0d90 100644
--- a/tempest/api/compute/admin/test_networks.py
+++ b/tempest/api/compute/admin/test_networks.py
@@ -62,4 +62,4 @@
self.assertIn(configured_network, [x['label'] for x in networks])
else:
network_labels = [x['label'] for x in networks]
- self.assertGreaterEqual(len(network_labels), 1)
+ self.assertNotEmpty(network_labels)
diff --git a/tempest/api/compute/admin/test_security_group_default_rules.py b/tempest/api/compute/admin/test_security_group_default_rules.py
index 6c7cde2..f2f3b57 100644
--- a/tempest/api/compute/admin/test_security_group_default_rules.py
+++ b/tempest/api/compute/admin/test_security_group_default_rules.py
@@ -111,7 +111,7 @@
rule['id'])
rules = (self.adm_client.list_security_group_default_rules()
['security_group_default_rules'])
- self.assertNotEqual(0, len(rules))
+ self.assertNotEmpty(rules)
self.assertIn(rule, rules)
@decorators.idempotent_id('15cbb349-86b4-4f71-a048-04b7ef3f150b')
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index 1dfc13e..f3eb597 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -29,13 +29,13 @@
@decorators.idempotent_id('5be41ef4-53d1-41cc-8839-5c2a48a1b283')
def test_list_services(self):
services = self.client.list_services()['services']
- self.assertNotEqual(0, len(services))
+ self.assertNotEmpty(services)
@decorators.idempotent_id('f345b1ec-bc6e-4c38-a527-3ca2bc00bef5')
def test_get_service_by_service_binary_name(self):
binary_name = 'nova-compute'
services = self.client.list_services(binary=binary_name)['services']
- self.assertNotEqual(0, len(services))
+ self.assertNotEmpty(services)
for service in services:
self.assertEqual(binary_name, service['binary'])
diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py
index 38bb5ec..201670a 100644
--- a/tempest/api/compute/admin/test_services_negative.py
+++ b/tempest/api/compute/admin/test_services_negative.py
@@ -48,7 +48,7 @@
host_name = services[0]['host']
services = self.client.list_services(host=host_name,
binary='xxx')['services']
- self.assertEqual(0, len(services))
+ self.assertEmpty(services)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('64e7e7fb-69e8-4cb6-a71d-8d5eb0c98655')
@@ -57,4 +57,4 @@
binary_name = services[0]['binary']
services = self.client.list_services(host='xxx',
binary=binary_name)['services']
- self.assertEqual(0, len(services))
+ self.assertEmpty(services)
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index 74d2dc4..913b992 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -58,7 +58,7 @@
# Positive test:Should return the list of floating IPs
body = self.client.list_floating_ips()['floating_ips']
floating_ips = body
- self.assertNotEqual(0, len(floating_ips),
+ self.assertNotEmpty(floating_ips,
"Expected floating IPs. Got zero.")
for i in range(3):
self.assertIn(self.floating_ip[i], floating_ips)
@@ -90,5 +90,5 @@
def test_list_floating_ip_pools(self):
# Positive test:Should return the list of floating IP Pools
floating_ip_pools = self.pools_client.list_floating_ip_pools()
- self.assertNotEqual(0, len(floating_ip_pools['floating_ip_pools']),
+ self.assertNotEmpty(floating_ip_pools['floating_ip_pools'],
"Expected floating IP Pools. Got zero.")
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 83447b6..5987d39 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -80,11 +80,11 @@
@decorators.idempotent_id('3b7c6fe4-dfe7-477c-9243-b06359db51e6')
def test_create_image_specify_multibyte_character_image_name(self):
# prefix character is:
- # http://www.fileformat.info/info/unicode/char/1F4A9/index.htm
+ # http://unicode.org/cldr/utility/character.jsp?a=20A1
- # We use a string with 3 byte utf-8 character due to bug
- # #1370954 in glance which will 500 if mysql is used as the
- # backend and it attempts to store a 4 byte utf-8 character
+ # We use a string with 3 byte utf-8 character due to nova/glance which
+ # will return 400(Bad Request) if we attempt to send a name which has
+ # 4 byte utf-8 character.
utf8_name = data_utils.rand_name(b'\xe2\x82\xa1'.decode('utf-8'))
body = self.client.create_image(self.server_id, name=utf8_name)
image_id = data_utils.parse_image_id(body.response['location'])
diff --git a/tempest/api/compute/limits/test_absolute_limits.py b/tempest/api/compute/limits/test_absolute_limits.py
index 58352bd..0585fec 100644
--- a/tempest/api/compute/limits/test_absolute_limits.py
+++ b/tempest/api/compute/limits/test_absolute_limits.py
@@ -42,6 +42,6 @@
# check whether all expected elements exist
missing_elements =\
[ele for ele in expected_elements if ele not in absolute_limits]
- self.assertEqual(0, len(missing_elements),
+ self.assertEmpty(missing_elements,
"Failed to find element %s in absolute limits list"
% ', '.join(ele for ele in missing_elements))
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 3378ef8..b568f7d 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -186,4 +186,4 @@
rules = (self.security_groups_client.show_security_group(sg1_id)
['security_group']['rules'])
# The group1 has no rules because group2 has deleted
- self.assertEqual(0, len(rules))
+ self.assertEmpty(rules)
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 6c5cc79..65d5042 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -49,7 +49,6 @@
cls.subnets_client = cls.os_primary.subnets_client
cls.ports_client = cls.os_primary.ports_client
- # TODO(mriedem): move this into a common waiters utility module
def wait_for_port_detach(self, port_id):
"""Waits for the port's device_id to be unset.
diff --git a/tempest/api/compute/servers/test_availability_zone.py b/tempest/api/compute/servers/test_availability_zone.py
index 82e74ed..36828d6 100644
--- a/tempest/api/compute/servers/test_availability_zone.py
+++ b/tempest/api/compute/servers/test_availability_zone.py
@@ -29,4 +29,4 @@
def test_get_availability_zone_list_with_non_admin_user(self):
# List of availability zone with non-administrator user
availability_zone = self.client.list_availability_zones()
- self.assertGreater(len(availability_zone['availabilityZoneInfo']), 0)
+ self.assertNotEmpty(availability_zone['availabilityZoneInfo'])
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 1ad153a..921b7da 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -142,7 +142,7 @@
# Verify only the expected number of servers are returned
params = {'limit': 0}
servers = self.client.list_servers(**params)
- self.assertEqual(0, len(servers['servers']))
+ self.assertEmpty(servers['servers'])
@decorators.idempotent_id('37791bbd-90c0-4de0-831e-5f38cba9c6b3')
def test_list_servers_filter_by_exceed_limit(self):
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index 0c40240..6c9b287 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -122,7 +122,7 @@
# Return an empty list when a date in the future is passed
changes_since = {'changes-since': '2051-01-01T12:34:00Z'}
body = self.client.list_servers(**changes_since)
- self.assertEqual(0, len(body['servers']))
+ self.assertEmpty(body['servers'])
@decorators.attr(type=['negative'])
@decorators.idempotent_id('93055106-2d34-46fe-af68-d9ddbf7ee570')
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index 92b1ff1..022ceba 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -48,9 +48,9 @@
# We do not know the exact network configuration, but an instance
# should at least have a single public or private address
- self.assertGreaterEqual(len(addresses), 1)
+ self.assertNotEmpty(addresses)
for network_addresses in addresses.values():
- self.assertGreaterEqual(len(network_addresses), 1)
+ self.assertNotEmpty(network_addresses)
for address in network_addresses:
self.assertTrue(address['addr'])
self.assertTrue(address['version'])
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index 610121b..6b625d9 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -58,7 +58,7 @@
output = self.client.list_virtual_interfaces(self.server['id'])
self.assertIsNotNone(output)
virt_ifaces = output
- self.assertNotEqual(0, len(virt_ifaces['virtual_interfaces']),
+ self.assertNotEmpty(virt_ifaces['virtual_interfaces'],
'Expected virtual interfaces, got 0 '
'interfaces.')
for virt_iface in virt_ifaces['virtual_interfaces']:
diff --git a/tempest/api/identity/admin/v2/test_endpoints.py b/tempest/api/identity/admin/v2/test_endpoints.py
index db32f5a..59fc4d8 100644
--- a/tempest/api/identity/admin/v2/test_endpoints.py
+++ b/tempest/api/identity/admin/v2/test_endpoints.py
@@ -62,7 +62,7 @@
# Asserting LIST endpoints
missing_endpoints =\
[e for e in self.setup_endpoints if e not in fetched_endpoints]
- self.assertEqual(0, len(missing_endpoints),
+ self.assertEmpty(missing_endpoints,
"Failed to find endpoint %s in fetched list" %
', '.join(str(e) for e in missing_endpoints))
diff --git a/tempest/api/identity/admin/v2/test_roles_negative.py b/tempest/api/identity/admin/v2/test_roles_negative.py
index 86d06e2..f3b7494 100644
--- a/tempest/api/identity/admin/v2/test_roles_negative.py
+++ b/tempest/api/identity/admin/v2/test_roles_negative.py
@@ -143,7 +143,7 @@
@decorators.idempotent_id('99b297f6-2b5d-47c7-97a9-8b6bb4f91042')
def test_assign_user_role_for_non_existent_role(self):
# Attempt to assign a non existent role to user should fail
- (user, tenant, role) = self._get_role_params()
+ (user, tenant, _) = self._get_role_params()
non_existent_role = data_utils.rand_uuid_hex()
self.assertRaises(lib_exc.NotFound,
self.roles_client.create_user_role_on_project,
@@ -153,7 +153,7 @@
@decorators.idempotent_id('b2285aaa-9e76-4704-93a9-7a8acd0a6c8f')
def test_assign_user_role_for_non_existent_tenant(self):
# Attempt to assign a role on a non existent tenant should fail
- (user, tenant, role) = self._get_role_params()
+ (user, _, role) = self._get_role_params()
non_existent_tenant = data_utils.rand_uuid_hex()
self.assertRaises(lib_exc.NotFound,
self.roles_client.create_user_role_on_project,
@@ -244,7 +244,7 @@
@decorators.idempotent_id('682adfb2-fd5f-4b0a-a9ca-322e9bebb907')
def test_list_user_roles_request_without_token(self):
# Request to list user's roles without a valid token should fail
- (user, tenant, role) = self._get_role_params()
+ (user, tenant, _) = self._get_role_params()
token = self.client.auth_provider.get_token()
self.client.delete_token(token)
try:
diff --git a/tempest/api/identity/admin/v2/test_tokens.py b/tempest/api/identity/admin/v2/test_tokens.py
index b4c9389..6b30d23 100644
--- a/tempest/api/identity/admin/v2/test_tokens.py
+++ b/tempest/api/identity/admin/v2/test_tokens.py
@@ -14,14 +14,18 @@
# under the License.
from tempest.api.identity import base
+from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+CONF = config.CONF
class TokensTestJSON(base.BaseIdentityV2AdminTest):
@decorators.idempotent_id('453ad4d5-e486-4b2f-be72-cffc8149e586')
- def test_create_get_delete_token(self):
+ def test_create_check_get_delete_token(self):
# get a token by username and password
user_name = data_utils.rand_name(name='user')
user_password = data_utils.rand_password()
@@ -40,6 +44,7 @@
tenant['name'])
# Perform GET Token
token_id = body['token']['id']
+ self.client.check_token_existence(token_id)
token_details = self.client.show_token(token_id)['access']
self.assertEqual(token_id, token_details['token']['id'])
self.assertEqual(user['id'], token_details['user']['id'])
@@ -48,6 +53,9 @@
token_details['token']['tenant']['name'])
# then delete the token
self.client.delete_token(token_id)
+ self.assertRaises(lib_exc.NotFound,
+ self.client.check_token_existence,
+ token_id)
@decorators.idempotent_id('25ba82ee-8a32-4ceb-8f50-8b8c71e8765e')
def test_rescope_token(self):
@@ -101,3 +109,25 @@
# Use the unscoped token to get a token scoped to tenant2
body = self.token_client.auth_token(token_id,
tenant=tenant2_name)
+
+ @decorators.idempotent_id('ca3ea6f7-ed08-4a61-adbd-96906456ad31')
+ def test_list_endpoints_for_token(self):
+ # get a token for the user
+ creds = self.os_primary.credentials
+ username = creds.username
+ password = creds.password
+ tenant_name = creds.tenant_name
+ token = self.token_client.auth(username,
+ password,
+ tenant_name)['token']
+ endpoints = self.client.list_endpoints_for_token(
+ token['id'])['endpoints']
+ self.assertIsInstance(endpoints, list)
+ # Store list of service names
+ service_names = [e['name'] for e in endpoints]
+ # Get the list of available services.
+ available_services = [s[0] for s in list(
+ CONF.service_available.items()) if s[1] is True]
+ # Verify that all available services are present.
+ for service in available_services:
+ self.assertIn(service, service_names)
diff --git a/tempest/api/identity/admin/v2/test_tokens_negative.py b/tempest/api/identity/admin/v2/test_tokens_negative.py
new file mode 100644
index 0000000..eb3e365
--- /dev/null
+++ b/tempest/api/identity/admin/v2/test_tokens_negative.py
@@ -0,0 +1,38 @@
+# Copyright 2017 AT&T Corporation
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.identity import base
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+
+class TokensAdminTestNegative(base.BaseIdentityV2AdminTest):
+
+ credentials = ['primary', 'admin', 'alt']
+
+ @decorators.attr(type=['negative'])
+ @decorators.idempotent_id('a0a0a600-4292-4364-99c5-922c834fdf05')
+ def test_check_token_existence_negative(self):
+ creds = self.os_primary.credentials
+ creds_alt = self.os_alt.credentials
+ username = creds.username
+ password = creds.password
+ tenant_name = creds.tenant_name
+ alt_tenant_name = creds_alt.tenant_name
+ body = self.token_client.auth(username, password, tenant_name)
+ self.assertRaises(lib_exc.Unauthorized,
+ self.client.check_token_existence,
+ body['token']['id'],
+ belongsTo=alt_tenant_name)
diff --git a/tempest/api/identity/admin/v2/test_users.py b/tempest/api/identity/admin/v2/test_users.py
index 2711a2d..0d98af5 100644
--- a/tempest/api/identity/admin/v2/test_users.py
+++ b/tempest/api/identity/admin/v2/test_users.py
@@ -141,7 +141,7 @@
# verifying the user Id in the list
missing_users =\
[user for user in user_ids if user not in fetched_user_ids]
- self.assertEqual(0, len(missing_users),
+ self.assertEmpty(missing_users,
"Failed to find user %s in fetched list" %
', '.join(m_user for m_user in missing_users))
@@ -169,7 +169,7 @@
# verifying the user Id in the list
missing_users = [missing_user for missing_user in user_ids
if missing_user not in fetched_user_ids]
- self.assertEqual(0, len(missing_users),
+ self.assertEmpty(missing_users,
"Failed to find user %s in fetched list" %
', '.join(m_user for m_user in missing_users))
diff --git a/tempest/api/identity/admin/v3/test_credentials.py b/tempest/api/identity/admin/v3/test_credentials.py
index 75e877a..15b2008 100644
--- a/tempest/api/identity/admin/v3/test_credentials.py
+++ b/tempest/api/identity/admin/v3/test_credentials.py
@@ -107,6 +107,6 @@
fetched_cred_ids.append(i['id'])
missing_creds = [c for c in created_cred_ids
if c not in fetched_cred_ids]
- self.assertEqual(0, len(missing_creds),
+ self.assertEmpty(missing_creds,
"Failed to find cred %s in fetched list" %
', '.join(m_cred for m_cred in missing_creds))
diff --git a/tempest/api/identity/admin/v3/test_default_project_id.py b/tempest/api/identity/admin/v3/test_default_project_id.py
index ac2faa9..302a0e5 100644
--- a/tempest/api/identity/admin/v3/test_default_project_id.py
+++ b/tempest/api/identity/admin/v3/test_default_project_id.py
@@ -79,7 +79,7 @@
admin_client = clients.Manager(credentials=creds)
# verify the user's token and see that it is scoped to the project
- token, auth_data = admin_client.auth_provider.get_auth()
+ token, _ = admin_client.auth_provider.get_auth()
result = admin_client.identity_v3_client.show_token(token)['token']
self.assertEqual(result['project']['domain']['id'], dom_id)
self.assertEqual(result['project']['id'], proj_id)
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index cddba53..9fe978c 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -57,7 +57,7 @@
fetched_ids.append(d['id'])
missing_doms = [d for d in self.setup_domains
if d['id'] not in fetched_ids]
- self.assertEqual(0, len(missing_doms))
+ self.assertEmpty(missing_doms)
@decorators.idempotent_id('c6aee07b-4981-440c-bb0b-eb598f58ffe9')
def test_list_domains_filter_by_name(self):
diff --git a/tempest/api/identity/admin/v3/test_endpoint_groups.py b/tempest/api/identity/admin/v3/test_endpoint_groups.py
new file mode 100644
index 0000000..5cd456c
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_endpoint_groups.py
@@ -0,0 +1,157 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.identity import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+
+
+class EndPointGroupsTest(base.BaseIdentityV3AdminTest):
+
+ @classmethod
+ def setup_clients(cls):
+ super(EndPointGroupsTest, cls).setup_clients()
+ cls.client = cls.endpoint_groups_client
+
+ @classmethod
+ def resource_setup(cls):
+ super(EndPointGroupsTest, cls).resource_setup()
+ cls.service_ids = list()
+ cls.endpoint_groups = list()
+
+ # Create endpoint group so as to use it for LIST test
+ service_id = cls._create_service()
+
+ name = data_utils.rand_name('service_group')
+ description = data_utils.rand_name('description')
+ filters = {'service_id': service_id}
+
+ endpoint_group = cls.client.create_endpoint_group(
+ name=name,
+ description=description,
+ filters=filters)['endpoint_group']
+
+ cls.endpoint_groups.append(endpoint_group)
+
+ @classmethod
+ def resource_cleanup(cls):
+ for e in cls.endpoint_groups:
+ cls.client.delete_endpoint_group(e['id'])
+ for s in cls.service_ids:
+ cls.services_client.delete_service(s)
+ super(EndPointGroupsTest, cls).resource_cleanup()
+
+ @classmethod
+ def _create_service(self):
+ s_name = data_utils.rand_name('service')
+ s_type = data_utils.rand_name('type')
+ s_description = data_utils.rand_name('description')
+ service_data = (
+ self.services_client.create_service(name=s_name,
+ type=s_type,
+ description=s_description))
+
+ service_id = service_data['service']['id']
+ self.service_ids.append(service_id)
+ return service_id
+
+ @decorators.idempotent_id('7c69e7a1-f865-402d-a2ea-44493017315a')
+ def test_create_list_show_check_delete_endpoint_group(self):
+ service_id = self._create_service()
+ name = data_utils.rand_name('service_group')
+ description = data_utils.rand_name('description')
+ filters = {'service_id': service_id}
+
+ endpoint_group = self.client.create_endpoint_group(
+ name=name,
+ description=description,
+ filters=filters)['endpoint_group']
+
+ self.endpoint_groups.append(endpoint_group)
+
+ # Asserting created endpoint group response body
+ self.assertIn('id', endpoint_group)
+ self.assertEqual(name, endpoint_group['name'])
+ self.assertEqual(description, endpoint_group['description'])
+
+ # Checking if endpoint groups are present in the list of endpoints
+ # Note that there are two endpoint groups in the list, one created
+ # in the resource setup, one created in this test case.
+ fetched_endpoints = \
+ self.client.list_endpoint_groups()['endpoint_groups']
+
+ missing_endpoints = \
+ [e for e in self.endpoint_groups if e not in fetched_endpoints]
+
+ # Asserting LIST endpoints
+ self.assertEmpty(missing_endpoints,
+ "Failed to find endpoint %s in fetched list" %
+ ', '.join(str(e) for e in missing_endpoints))
+
+ # Show endpoint group
+ fetched_endpoint = self.client.show_endpoint_group(
+ endpoint_group['id'])['endpoint_group']
+
+ # Asserting if the attributes of endpoint group are the same
+ self.assertEqual(service_id,
+ fetched_endpoint['filters']['service_id'])
+ for attr in ('id', 'name', 'description'):
+ self.assertEqual(endpoint_group[attr], fetched_endpoint[attr])
+
+ # Check endpoint group
+ self.client.check_endpoint_group(endpoint_group['id'])
+
+ # Deleting the endpoint group created in this method
+ self.client.delete_endpoint_group(endpoint_group['id'])
+ self.endpoint_groups.remove(endpoint_group)
+
+ # Checking whether endpoint group is deleted successfully
+ fetched_endpoints = \
+ self.client.list_endpoint_groups()['endpoint_groups']
+ fetched_endpoint_ids = [e['id'] for e in fetched_endpoints]
+ self.assertNotIn(endpoint_group['id'], fetched_endpoint_ids)
+
+ @decorators.idempotent_id('51c8fc38-fa84-4e76-b5b6-6fc37770fb26')
+ def test_update_endpoint_group(self):
+ # Creating an endpoint group so as to check update endpoint group
+ # with new values
+ service1_id = self._create_service()
+ name = data_utils.rand_name('service_group')
+ description = data_utils.rand_name('description')
+ filters = {'service_id': service1_id}
+
+ endpoint_group = self.client.create_endpoint_group(
+ name=name,
+ description=description,
+ filters=filters)['endpoint_group']
+ self.endpoint_groups.append(endpoint_group)
+
+ # Creating new attr values to update endpoint group
+ service2_id = self._create_service()
+ name2 = data_utils.rand_name('service_group2')
+ description2 = data_utils.rand_name('description2')
+ filters = {'service_id': service2_id}
+
+ # Updating endpoint group with new attr values
+ updated_endpoint_group = self.client.update_endpoint_group(
+ endpoint_group['id'],
+ name=name2,
+ description=description2,
+ filters=filters)['endpoint_group']
+
+ self.assertEqual(name2, updated_endpoint_group['name'])
+ self.assertEqual(description2, updated_endpoint_group['description'])
+ self.assertEqual(service2_id,
+ updated_endpoint_group['filters']['service_id'])
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index 09f92e2..b1ae2aa 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -64,7 +64,7 @@
# Asserting LIST endpoints
missing_endpoints =\
[e for e in self.setup_endpoints if e not in fetched_endpoints]
- self.assertEqual(0, len(missing_endpoints),
+ self.assertEmpty(missing_endpoints,
"Failed to find endpoint %s in fetched list" %
', '.join(str(e) for e in missing_endpoints))
diff --git a/tempest/api/identity/admin/v3/test_list_users.py b/tempest/api/identity/admin/v3/test_list_users.py
index bcbf6b6..47a3580 100644
--- a/tempest/api/identity/admin/v3/test_list_users.py
+++ b/tempest/api/identity/admin/v3/test_list_users.py
@@ -93,7 +93,7 @@
fetched_ids = [u['id'] for u in body]
missing_users = [u['id'] for u in self.users
if u['id'] not in fetched_ids]
- self.assertEqual(0, len(missing_users),
+ self.assertEmpty(missing_users,
"Failed to find user %s in fetched list" %
', '.join(m_user for m_user in missing_users))
diff --git a/tempest/api/identity/admin/v3/test_policies.py b/tempest/api/identity/admin/v3/test_policies.py
index 730d469..960e2cb 100644
--- a/tempest/api/identity/admin/v3/test_policies.py
+++ b/tempest/api/identity/admin/v3/test_policies.py
@@ -41,7 +41,7 @@
for p in body:
fetched_ids.append(p['id'])
missing_pols = [p for p in policy_ids if p not in fetched_ids]
- self.assertEqual(0, len(missing_pols))
+ self.assertEmpty(missing_pols)
@decorators.attr(type='smoke')
@decorators.idempotent_id('e544703a-2f03-4cf2-9b0f-350782fdb0d3')
diff --git a/tempest/api/identity/admin/v3/test_regions.py b/tempest/api/identity/admin/v3/test_regions.py
index ac550a7..d00e408 100644
--- a/tempest/api/identity/admin/v3/test_regions.py
+++ b/tempest/api/identity/admin/v3/test_regions.py
@@ -98,7 +98,7 @@
missing_regions =\
[e for e in self.setup_regions if e not in fetched_regions]
# Asserting List Regions response
- self.assertEqual(0, len(missing_regions),
+ self.assertEmpty(missing_regions,
"Failed to find region %s in fetched list" %
', '.join(str(e) for e in missing_regions))
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index 751962f..409d4f8 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -131,7 +131,7 @@
missing_projects =\
[p for p in assigned_project_ids
if p not in fetched_project_ids]
- self.assertEqual(0, len(missing_projects),
+ self.assertEmpty(missing_projects,
"Failed to find project %s in fetched list" %
', '.join(m_project for m_project
in missing_projects))
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 785485b..3bc6ce1 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -225,6 +225,7 @@
cls.oauth_consumers_client = cls.os_admin.oauth_consumers_client
cls.domain_config_client = cls.os_admin.domain_config_client
cls.endpoint_filter_client = cls.os_admin.endpoint_filter_client
+ cls.endpoint_groups_client = cls.os_admin.endpoint_groups_client
if CONF.identity.admin_domain_scope:
# NOTE(andreaf) When keystone policy requires it, the identity
diff --git a/tempest/api/identity/v3/test_tokens.py b/tempest/api/identity/v3/test_tokens.py
index c9d7a4d..4c72d82 100644
--- a/tempest/api/identity/v3/test_tokens.py
+++ b/tempest/api/identity/v3/test_tokens.py
@@ -15,12 +15,39 @@
from oslo_utils import timeutils
import six
+
from tempest.api.identity import base
from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
class TokensV3Test(base.BaseIdentityV3Test):
+ @decorators.idempotent_id('a9512ac3-3909-48a4-b395-11f438e16260')
+ def test_validate_token(self):
+ creds = self.os_primary.credentials
+ user_id = creds.user_id
+ username = creds.username
+ password = creds.password
+ user_domain_id = creds.user_domain_id
+ # GET and validate token
+ subject_token, token_body = self.non_admin_token.get_token(
+ user_id=user_id,
+ username=username,
+ user_domain_id=user_domain_id,
+ password=password,
+ auth_data=True)
+ authenticated_token = self.non_admin_client.show_token(
+ subject_token)['token']
+ # sanity checking to make sure they are indeed the same token
+ self.assertEqual(authenticated_token, token_body)
+ # test to see if token has been properly authenticated
+ self.assertEqual(authenticated_token['user']['id'], user_id)
+ self.assertEqual(authenticated_token['user']['name'], username)
+ self.non_admin_client.delete_token(subject_token)
+ self.assertRaises(
+ lib_exc.NotFound, self.non_admin_client.show_token, subject_token)
+
@decorators.idempotent_id('6f8e4436-fc96-4282-8122-e41df57197a9')
def test_create_token(self):
@@ -54,15 +81,13 @@
self.assertEqual(subject_id, user_id)
else:
# Expect a user ID, but don't know what it will be.
- self.assertGreaterEqual(len(subject_id), 0,
- 'Expected user ID in token.')
+ self.assertIsNotNone(subject_id, 'Expected user ID in token.')
subject_name = resp['user']['name']
if username:
self.assertEqual(subject_name, username)
else:
# Expect a user name, but don't know what it will be.
- self.assertGreaterEqual(len(subject_name), 0,
- 'Expected user name in token.')
+ self.assertIsNotNone(subject_name, 'Expected user name in token.')
self.assertEqual(resp['methods'][0], 'password')
diff --git a/tempest/api/image/v1/test_image_members.py b/tempest/api/image/v1/test_image_members.py
index 4902316..bf2e510 100644
--- a/tempest/api/image/v1/test_image_members.py
+++ b/tempest/api/image/v1/test_image_members.py
@@ -54,6 +54,6 @@
self.alt_tenant_id)
body = self.image_member_client.list_image_members(image_id)
members = body['members']
- self.assertEqual(0, len(members), str(members))
+ self.assertEmpty(members)
self.assertRaises(
lib_exc.NotFound, self.alt_img_cli.show_image, image_id)
diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py
index 6389489..7304db9 100644
--- a/tempest/api/network/admin/test_agent_management.py
+++ b/tempest/api/network/admin/test_agent_management.py
@@ -49,7 +49,7 @@
@decorators.idempotent_id('e335be47-b9a1-46fd-be30-0874c0b751e6')
def test_list_agents_non_admin(self):
body = self.agents_client.list_agents()
- self.assertEqual(len(body["agents"]), 0)
+ self.assertEmpty(body["agents"])
@decorators.idempotent_id('869bc8e8-0fda-4a30-9b71-f8a7cf58ca9f')
def test_show_agent(self):
diff --git a/tempest/api/network/admin/test_metering_extensions.py b/tempest/api/network/admin/test_metering_extensions.py
index 3f94868..21a7ab4 100644
--- a/tempest/api/network/admin/test_metering_extensions.py
+++ b/tempest/api/network/admin/test_metering_extensions.py
@@ -74,7 +74,7 @@
# Asserting that the label is not found in list after deletion
labels = self.admin_metering_labels_client.list_metering_labels(
id=metering_label_id)
- self.assertEqual(len(labels['metering_labels']), 0)
+ self.assertEmpty(labels['metering_labels'])
def _delete_metering_label_rule(self, metering_label_rule_id):
client = self.admin_metering_label_rules_client
@@ -89,7 +89,7 @@
# Verify label filtering
body = self.admin_metering_labels_client.list_metering_labels(id=33)
metering_labels = body['metering_labels']
- self.assertEqual(0, len(metering_labels))
+ self.assertEmpty(metering_labels)
@decorators.idempotent_id('ec8e15ff-95d0-433b-b8a6-b466bddb1e50')
def test_create_delete_metering_label_with_filters(self):
@@ -126,7 +126,7 @@
# Verify rule filtering
body = client.list_metering_label_rules(id=33)
metering_label_rules = body['metering_label_rules']
- self.assertEqual(0, len(metering_label_rules))
+ self.assertEmpty(metering_label_rules)
@decorators.idempotent_id('f4d547cd-3aee-408f-bf36-454f8825e045')
def test_create_delete_metering_label_rule_with_filters(self):
diff --git a/tempest/api/network/admin/test_routers.py b/tempest/api/network/admin/test_routers.py
index ec8d260..07c4157 100644
--- a/tempest/api/network/admin/test_routers.py
+++ b/tempest/api/network/admin/test_routers.py
@@ -134,7 +134,7 @@
self.assertEqual(len(list_body['ports']), 1)
gw_port = list_body['ports'][0]
fixed_ips = gw_port['fixed_ips']
- self.assertGreaterEqual(len(fixed_ips), 1)
+ self.assertNotEmpty(fixed_ips)
# Assert that all of the IPs from the router gateway port
# are allocated from a valid public subnet.
public_net_body = self.admin_networks_client.show_network(
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 8775495..6bec0d7 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -83,6 +83,7 @@
cls.os_primary.security_group_rules_client)
cls.network_versions_client = cls.os_primary.network_versions_client
cls.service_providers_client = cls.os_primary.service_providers_client
+ cls.tags_client = cls.os_primary.tags_client
@classmethod
def resource_setup(cls):
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index d78cd1e..128544b 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -156,7 +156,7 @@
self.assertEqual(len(list_body['ports']), 1)
gw_port = list_body['ports'][0]
fixed_ips = gw_port['fixed_ips']
- self.assertGreaterEqual(len(fixed_ips), 1)
+ self.assertNotEmpty(fixed_ips)
# Assert that all of the IPs from the router gateway port
# are allocated from a valid public subnet.
public_net_body = self.admin_networks_client.show_network(
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 0d5e230..a121864 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -83,7 +83,7 @@
@decorators.attr(type='smoke')
@decorators.idempotent_id('bfd128e5-3c92-44b6-9d66-7fe29d22c802')
def test_create_list_update_show_delete_security_group(self):
- group_create_body, name = self._create_security_group()
+ group_create_body, _ = self._create_security_group()
# List security groups and verify if created group is there in response
list_body = self.security_groups_client.list_security_groups()
diff --git a/tempest/api/network/test_tags.py b/tempest/api/network/test_tags.py
new file mode 100644
index 0000000..1f3a7c4
--- /dev/null
+++ b/tempest/api/network/test_tags.py
@@ -0,0 +1,90 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.api.network import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from tempest import test
+
+
+class TagsTest(base.BaseNetworkTest):
+ """Tests the following operations in the tags API:
+
+ Update all tags.
+ Delete all tags.
+ Check tag existence.
+ Create a tag.
+ List tags.
+ Remove a tag.
+
+ v2.0 of the Neutron API is assumed. The tag extension allows users to set
+ tags on their networks. The extension supports networks only.
+ """
+
+ @classmethod
+ def skip_checks(cls):
+ super(TagsTest, cls).skip_checks()
+ if not test.is_extension_enabled('tag', 'network'):
+ msg = "tag extension not enabled."
+ raise cls.skipException(msg)
+
+ @classmethod
+ def resource_setup(cls):
+ super(TagsTest, cls).resource_setup()
+ cls.network = cls.create_network()
+
+ @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.
+ 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',
+ self.network['id'])
+ self.tags_client.check_tag_existence('networks', self.network['id'],
+ tag_name)
+
+ # Validate that listing tags on a network resource works.
+ retrieved_tags = self.tags_client.list_tags(
+ 'networks', self.network['id'])['tags']
+ self.assertEqual([tag_name], retrieved_tags)
+
+ # Generate 3 new tag names.
+ replace_tags = [data_utils.rand_name(
+ self.__class__.__name__ + '-Tag') for _ in range(3)]
+
+ # Replace the current tag with the 3 new tags and validate that the
+ # network resource has the 3 new tags.
+ updated_tags = self.tags_client.update_all_tags(
+ 'networks', self.network['id'], replace_tags)['tags']
+ self.assertEqual(3, len(updated_tags))
+ self.assertEqual(set(replace_tags), set(updated_tags))
+
+ # Delete the first tag and check that it has been removed.
+ self.tags_client.delete_tag(
+ 'networks', self.network['id'], replace_tags[0])
+ self.assertRaises(lib_exc.NotFound,
+ self.tags_client.check_tag_existence, 'networks',
+ self.network['id'], replace_tags[0])
+ for i in range(1, 3):
+ self.tags_client.check_tag_existence(
+ 'networks', self.network['id'], replace_tags[i])
+
+ # Delete all the remaining tags and check that they have been removed.
+ self.tags_client.delete_all_tags('networks', self.network['id'])
+ for i in range(1, 3):
+ self.assertRaises(lib_exc.NotFound,
+ self.tags_client.check_tag_existence, 'networks',
+ self.network['id'], replace_tags[i])
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 2bac8d3..13614cb 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -43,8 +43,7 @@
for cont in containers:
try:
params = {'limit': 9999, 'format': 'json'}
- resp, objlist = container_client.list_container_contents(
- cont, params)
+ _, objlist = container_client.list_container_contents(cont, params)
# delete every object in the container
for obj in objlist:
test_utils.call_and_ignore_notfound_exc(
diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py
index 0a72d75..e765414 100644
--- a/tempest/api/object_storage/test_account_bulk.py
+++ b/tempest/api/object_storage/test_account_bulk.py
@@ -112,7 +112,7 @@
self._upload_archive(filepath)
data = '%s/%s\n%s' % (container_name, object_name, container_name)
- resp, body = self.bulk_client.delete_bulk_data(data=data)
+ resp, _ = self.bulk_client.delete_bulk_data(data=data)
# When deleting multiple files using the bulk operation, the response
# does not contain 'content-length' header. This is the special case,
@@ -138,7 +138,7 @@
data = '%s/%s\n%s' % (container_name, object_name, container_name)
- resp, body = self.bulk_client.delete_bulk_data_with_post(data=data)
+ resp, _ = self.bulk_client.delete_bulk_data_with_post(data=data)
# When deleting multiple files using the bulk operation, the response
# does not contain 'content-length' header. This is the special case,
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index e54b6e7..9e62046 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -101,7 +101,7 @@
# Check only the format of common headers with custom matcher
self.assertThat(resp, custom_matchers.AreAllWellFormatted())
- self.assertEqual(len(container_list), 0)
+ self.assertEmpty(container_list)
@decorators.idempotent_id('1c7efa35-e8a2-4b0b-b5ff-862c7fd83704')
def test_list_containers_with_format_json(self):
@@ -135,7 +135,7 @@
not CONF.object_storage_feature_enabled.discoverability,
'Discoverability function is disabled')
def test_list_extensions(self):
- resp, extensions = self.capabilities_client.list_capabilities()
+ resp, _ = self.capabilities_client.list_capabilities()
self.assertThat(resp, custom_matchers.AreAllWellFormatted())
@@ -162,7 +162,7 @@
self.account_client.list_account_containers(params=params)
self.assertHeaders(resp, 'Account', 'GET')
- self.assertEqual(len(container_list), 0)
+ self.assertEmpty(container_list)
params = {'marker': self.containers[self.containers_count // 2]}
resp, container_list = \
@@ -182,7 +182,7 @@
resp, container_list = \
self.account_client.list_account_containers(params=params)
self.assertHeaders(resp, 'Account', 'GET')
- self.assertEqual(len(container_list), 0)
+ self.assertEmpty(container_list)
params = {'end_marker': self.containers[self.containers_count // 2]}
resp, container_list = \
@@ -297,7 +297,7 @@
create_update_metadata=metadata)
self.assertHeaders(resp, 'Account', 'POST')
- resp, body = self.account_client.list_account_metadata()
+ resp, _ = self.account_client.list_account_metadata()
self.assertIn('x-account-meta-test-account-meta1', resp)
self.assertEqual(resp['x-account-meta-test-account-meta1'],
metadata['test-account-meta1'])
@@ -352,7 +352,7 @@
self.account_client.create_update_or_delete_account_metadata(
create_update_metadata=metadata_1)
metadata_2 = {'test-account-meta2': 'Meta2'}
- resp, body = (
+ resp, _ = (
self.account_client.create_update_or_delete_account_metadata(
create_update_metadata=metadata_2,
delete_metadata=metadata_1))
diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py
index d4e5ec5..4b66ebf 100644
--- a/tempest/api/object_storage/test_container_acl.py
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -41,10 +41,10 @@
tenant_name = self.os_roles_operator_alt.credentials.tenant_name
username = self.os_roles_operator_alt.credentials.username
cont_headers = {'X-Container-Read': tenant_name + ':' + username}
- resp_meta, body = self.os_roles_operator.container_client.\
- update_container_metadata(
+ resp_meta, _ = (
+ self.os_roles_operator.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
- metadata_prefix='')
+ metadata_prefix=''))
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')
@@ -68,10 +68,10 @@
tenant_name = self.os_roles_operator_alt.credentials.tenant_name
username = self.os_roles_operator_alt.credentials.username
cont_headers = {'X-Container-Write': tenant_name + ':' + username}
- resp_meta, body = self.os_roles_operator.container_client.\
- update_container_metadata(self.container_name,
- metadata=cont_headers,
- metadata_prefix='')
+ resp_meta, _ = (
+ self.os_roles_operator.container_client.update_container_metadata(
+ self.container_name, metadata=cont_headers,
+ metadata_prefix=''))
self.assertHeaders(resp_meta, 'Container', 'POST')
# set alternative authentication data; cannot simply use the
# other object client.
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index 9c9d821..655626c 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -65,8 +65,8 @@
def test_delete_object_without_using_creds(self):
# create object
object_name = data_utils.rand_name(name='Object')
- resp, _ = self.object_client.create_object(self.container_name,
- object_name, 'data')
+ self.object_client.create_object(self.container_name, object_name,
+ 'data')
# trying to delete object with empty headers
# X-Auth-Token is not provided
self.object_client.auth_provider.set_alt_auth_data(
@@ -134,7 +134,7 @@
# attempt to read object using non-authorized user
# update X-Container-Read metadata ACL
cont_headers = {'X-Container-Read': 'badtenant:baduser'}
- resp_meta, body = self.container_client.update_container_metadata(
+ resp_meta, _ = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
self.assertHeaders(resp_meta, 'Container', 'POST')
@@ -158,7 +158,7 @@
# attempt to write object using non-authorized user
# update X-Container-Write metadata ACL
cont_headers = {'X-Container-Write': 'badtenant:baduser'}
- resp_meta, body = self.container_client.update_container_metadata(
+ resp_meta, _ = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
self.assertHeaders(resp_meta, 'Container', 'POST')
@@ -183,7 +183,7 @@
cont_headers = {'X-Container-Read':
tenant_name + ':' + username,
'X-Container-Write': ''}
- resp_meta, body = self.container_client.update_container_metadata(
+ resp_meta, _ = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
self.assertHeaders(resp_meta, 'Container', 'POST')
@@ -208,7 +208,7 @@
cont_headers = {'X-Container-Read':
tenant_name + ':' + username,
'X-Container-Write': ''}
- resp_meta, body = self.container_client.update_container_metadata(
+ resp_meta, _ = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
self.assertHeaders(resp_meta, 'Container', 'POST')
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 2b5692d..76fe8d4 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -27,7 +27,7 @@
@decorators.idempotent_id('92139d73-7819-4db1-85f8-3f2f22a8d91f')
def test_create_container(self):
container_name = data_utils.rand_name(name='TestContainer')
- resp, body = self.container_client.create_container(container_name)
+ resp, _ = self.container_client.create_container(container_name)
self.containers.append(container_name)
self.assertHeaders(resp, 'Container', 'PUT')
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 9e01c26..378061a 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -124,9 +124,8 @@
# test GET on http://account_url/container_name
# we should retrieve a listing of objects
- resp, body = self.account_client.request("GET",
- self.container_name,
- headers={})
+ _, body = self.account_client.request("GET", self.container_name,
+ headers={})
self.assertIn(self.object_name, body.decode())
css = '<link rel="stylesheet" type="text/css" href="listings.css" />'
self.assertIn(css, body.decode())
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index 3c11a51..4cb1914 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -90,8 +90,7 @@
cont_client = [self.clients[c][0] for c in cont]
obj_client = [self.clients[c][1] for c in cont]
headers = make_headers(cont[1], cont_client[1])
- resp, body = \
- cont_client[0].put(str(cont[0]), body=None, headers=headers)
+ cont_client[0].put(str(cont[0]), body=None, headers=headers)
# create object in container
object_name = data_utils.rand_name(name='TestSyncObject')
data = object_name[::-1].encode() # Raw data, we need bytes
diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py
index 7768d23..ed1be90 100644
--- a/tempest/api/object_storage/test_object_expiry.py
+++ b/tempest/api/object_storage/test_object_expiry.py
@@ -54,8 +54,8 @@
# actually expire, so figure out how many secs in the future that is.
sleepy_time = int(resp['x-delete-at']) - int(time.time())
sleepy_time = sleepy_time if sleepy_time > 0 else 0
- resp, body = self.object_client.get_object(self.container_name,
- self.object_name)
+ resp, _ = self.object_client.get_object(self.container_name,
+ self.object_name)
self.assertHeaders(resp, 'Object', 'GET')
self.assertIn('x-delete-at', resp)
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 21ea6ae..b29a77f 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -48,7 +48,7 @@
data_segments = [data + str(i) for i in range(segments)]
# uploading segments
for i in range(segments):
- resp, _ = self.object_client.create_object_segments(
+ self.object_client.create_object_segments(
self.container_name, object_name, i, data_segments[i])
return object_name, data_segments
@@ -184,7 +184,7 @@
# create object with transfer_encoding
object_name = data_utils.rand_name(name='TestObject')
data = data_utils.random_bytes(1024)
- status, _, resp_headers = self.object_client.put_object_with_chunk(
+ _, _, resp_headers = self.object_client.put_object_with_chunk(
container=self.container_name,
name=object_name,
contents=data_utils.chunkify(data, 512)
@@ -394,7 +394,7 @@
# update object metadata with x_object_manifest
# uploading segments
- object_name, data_segments = self._upload_segments()
+ object_name, _ = self._upload_segments()
# creating a manifest file
data_empty = ''
self.object_client.create_object(self.container_name,
@@ -414,7 +414,7 @@
self.container_name,
object_name)
self.assertIn('x-object-manifest', resp)
- self.assertNotEqual(len(resp['x-object-manifest']), 0)
+ self.assertNotEmpty(resp['x-object-manifest'])
@decorators.idempotent_id('0dbbe89c-6811-4d84-a2df-eca2bdd40c0e')
def test_update_object_metadata_with_x_object_metakey(self):
@@ -494,7 +494,7 @@
# get object metadata with x_object_manifest
# uploading segments
- object_name, data_segments = self._upload_segments()
+ object_name, _ = self._upload_segments()
# creating a manifest file
object_prefix = '%s/%s' % (self.container_name, object_name)
metadata = {'X-Object-Manifest': object_prefix}
@@ -520,11 +520,11 @@
self.assertTrue(resp['etag'].startswith('\"'))
self.assertTrue(resp['etag'].endswith('\"'))
self.assertTrue(resp['etag'].strip('\"').isalnum())
- self.assertTrue(re.match("^\d+\.?\d*\Z", resp['x-timestamp']))
- self.assertNotEqual(len(resp['content-type']), 0)
+ self.assertTrue(re.match(r"^\d+\.?\d*\Z", resp['x-timestamp']))
+ self.assertNotEmpty(resp['content-type'])
self.assertTrue(re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*",
resp['x-trans-id']))
- self.assertNotEqual(len(resp['date']), 0)
+ self.assertNotEmpty(resp['date'])
self.assertEqual(resp['accept-ranges'], 'bytes')
self.assertEqual(resp['x-object-manifest'],
'%s/%s' % (self.container_name, object_name))
@@ -612,11 +612,11 @@
self.assertTrue(resp['etag'].startswith('\"'))
self.assertTrue(resp['etag'].endswith('\"'))
self.assertTrue(resp['etag'].strip('\"').isalnum())
- self.assertTrue(re.match("^\d+\.?\d*\Z", resp['x-timestamp']))
- self.assertNotEqual(len(resp['content-type']), 0)
+ self.assertTrue(re.match(r"^\d+\.?\d*\Z", resp['x-timestamp']))
+ self.assertNotEmpty(resp['content-type'])
self.assertTrue(re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*",
resp['x-trans-id']))
- self.assertNotEqual(len(resp['date']), 0)
+ self.assertNotEmpty(resp['date'])
self.assertEqual(resp['accept-ranges'], 'bytes')
self.assertEqual(resp['x-object-manifest'],
'%s/%s' % (self.container_name, object_name))
@@ -955,7 +955,7 @@
local_data = "something different"
md5 = hashlib.md5(local_data.encode()).hexdigest()
headers = {'If-None-Match': md5}
- resp, body = self.object_client.get(url, headers=headers)
+ resp, _ = self.object_client.get(url, headers=headers)
self.assertHeaders(resp, 'Object', 'GET')
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
index 085ad13..894e42d 100644
--- a/tempest/api/object_storage/test_object_slo.py
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -127,7 +127,7 @@
# list static large object metadata using multipart manifest
object_name = self._create_large_object()
- resp, body = self.object_client.list_object_metadata(
+ resp, _ = self.object_client.list_object_metadata(
self.container_name,
object_name)
@@ -155,7 +155,7 @@
object_name = self._create_large_object()
params_del = {'multipart-manifest': 'delete'}
- resp, body = self.object_client.delete_object(
+ resp, _ = self.object_client.delete_object(
self.container_name,
object_name,
params=params_del)
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index 4b506f8..91bc677 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -128,7 +128,7 @@
url = self._get_temp_url(self.container_name,
self.object_name, "GET",
expires, key2)
- resp, body = self.object_client.get(url)
+ _, body = self.object_client.get(url)
self.assertEqual(body, self.content)
@decorators.idempotent_id('9b08dade-3571-4152-8a4f-a4f2a873a735')
@@ -168,7 +168,7 @@
expires, self.key)
# Testing a HEAD on this Temp URL
- resp, body = self.object_client.head(url)
+ resp, _ = self.object_client.head(url)
self.assertHeaders(resp, 'Object', 'HEAD')
@decorators.idempotent_id('9d9cfd90-708b-465d-802c-e4a8090b823d')
diff --git a/tempest/api/object_storage/test_object_temp_url_negative.py b/tempest/api/object_storage/test_object_temp_url_negative.py
index f4d63fd..3edaa86 100644
--- a/tempest/api/object_storage/test_object_temp_url_negative.py
+++ b/tempest/api/object_storage/test_object_temp_url_negative.py
@@ -46,7 +46,7 @@
@classmethod
def resource_cleanup(cls):
- resp, _ = cls.account_client.create_update_or_delete_account_metadata(
+ cls.account_client.create_update_or_delete_account_metadata(
delete_metadata=cls.metadata)
cls.delete_containers()
diff --git a/tempest/api/volume/admin/test_snapshot_manage.py b/tempest/api/volume/admin/test_snapshot_manage.py
index a2d5fb1..6c09042 100644
--- a/tempest/api/volume/admin/test_snapshot_manage.py
+++ b/tempest/api/volume/admin/test_snapshot_manage.py
@@ -13,11 +13,10 @@
# License for the specific language governing permissions and limitations
# under the License.
-import testtools
-
from tempest.api.volume import base
from tempest.common import waiters
from tempest import config
+from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
CONF = config.CONF
@@ -31,9 +30,18 @@
managed by Cinder from a storage back end to Cinder
"""
+ @classmethod
+ def skip_checks(cls):
+ super(SnapshotManageAdminTest, cls).skip_checks()
+
+ if not CONF.volume_feature_enabled.manage_snapshot:
+ raise cls.skipException("Manage snapshot tests are disabled")
+
+ if len(CONF.volume.manage_snapshot_ref) != 2:
+ raise cls.skipException("Manage snapshot ref is not correctly "
+ "configured")
+
@decorators.idempotent_id('0132f42d-0147-4b45-8501-cc504bbf7810')
- @testtools.skipUnless(CONF.volume_feature_enabled.manage_snapshot,
- "Manage snapshot tests are disabled")
def test_unmanage_manage_snapshot(self):
# Create a volume
volume = self.create_volume()
@@ -47,20 +55,30 @@
self.admin_snapshots_client.unmanage_snapshot(snapshot['id'])
self.admin_snapshots_client.wait_for_resource_deletion(snapshot['id'])
- # Fetch snapshot ids
- snapshot_list = [
- snap['id'] for snap in
- self.snapshots_client.list_snapshots()['snapshots']
- ]
-
- # Verify snapshot does not exist in snapshot list
- self.assertNotIn(snapshot['id'], snapshot_list)
+ # Verify the original snapshot does not exist in snapshot list
+ params = {'all_tenants': 1}
+ all_snapshots = self.admin_snapshots_client.list_snapshots(
+ detail=True, params=params)['snapshots']
+ self.assertNotIn(snapshot['id'], [v['id'] for v in all_snapshots])
# Manage the snapshot
- snapshot_ref = '_snapshot-%s' % snapshot['id']
+ name = data_utils.rand_name(self.__class__.__name__ +
+ '-Managed-Snapshot')
+ description = data_utils.rand_name(self.__class__.__name__ +
+ '-Managed-Snapshot-Description')
+ metadata = {"manage-snap-meta1": "value1",
+ "manage-snap-meta2": "value2",
+ "manage-snap-meta3": "value3"}
+ snapshot_ref = {
+ 'volume_id': volume['id'],
+ 'ref': {CONF.volume.manage_snapshot_ref[0]:
+ CONF.volume.manage_snapshot_ref[1] % snapshot['id']},
+ 'name': name,
+ 'description': description,
+ 'metadata': metadata
+ }
new_snapshot = self.admin_snapshot_manage_client.manage_snapshot(
- volume_id=volume['id'],
- ref={'source-name': snapshot_ref})['snapshot']
+ **snapshot_ref)['snapshot']
self.addCleanup(self.delete_snapshot, new_snapshot['id'],
self.admin_snapshots_client)
@@ -70,4 +88,9 @@
'available')
# Verify the managed snapshot has the expected parent volume
- self.assertEqual(new_snapshot['volume_id'], volume['id'])
+ # and the expected field values.
+ new_snapshot_info = self.admin_snapshots_client.show_snapshot(
+ new_snapshot['id'])['snapshot']
+ self.assertEqual(snapshot['size'], new_snapshot_info['size'])
+ for key in ['volume_id', 'name', 'description', 'metadata']:
+ self.assertEqual(snapshot_ref[key], new_snapshot_info[key])
diff --git a/tempest/api/volume/admin/test_volume_pools.py b/tempest/api/volume/admin/test_volume_pools.py
index 60a3bda..d389c26 100644
--- a/tempest/api/volume/admin/test_volume_pools.py
+++ b/tempest/api/volume/admin/test_volume_pools.py
@@ -22,7 +22,7 @@
class VolumePoolsAdminTestsJSON(base.BaseVolumeAdminTest):
def _assert_pools(self, with_detail=False):
- cinder_pools = self.admin_volume_client.show_pools(
+ cinder_pools = self.admin_scheduler_stats_client.list_pools(
detail=with_detail)['pools']
self.assertIn('name', cinder_pools[0])
if with_detail:
diff --git a/tempest/api/volume/admin/test_volume_services.py b/tempest/api/volume/admin/test_volume_services.py
index 4aab9c1..293af81 100644
--- a/tempest/api/volume/admin/test_volume_services.py
+++ b/tempest/api/volume/admin/test_volume_services.py
@@ -41,13 +41,13 @@
def test_list_services(self):
services = (self.admin_volume_services_client.list_services()
['services'])
- self.assertNotEqual(0, len(services))
+ self.assertNotEmpty(services)
@decorators.idempotent_id('63a3e1ca-37ee-4983-826d-83276a370d25')
def test_get_service_by_service_binary_name(self):
services = (self.admin_volume_services_client.list_services(
binary=self.binary_name)['services'])
- self.assertNotEqual(0, len(services))
+ self.assertNotEmpty(services)
for service in services:
self.assertEqual(self.binary_name, service['binary'])
@@ -76,7 +76,7 @@
services = (self.admin_volume_services_client.list_services(
host=hostname, binary='cinder-volume')['services'])
- self.assertNotEqual(0, len(services),
+ self.assertNotEmpty(services,
'cinder-volume not found on host %s' % hostname)
self.assertEqual(hostname, _get_host(services[0]['host']))
self.assertEqual('cinder-volume', services[0]['binary'])
@@ -87,6 +87,6 @@
services = (self.admin_volume_services_client.list_services(
host=self.host_name, binary=self.binary_name))['services']
- self.assertNotEqual(0, len(services))
+ self.assertNotEmpty(services)
self.assertEqual(self.host_name, _get_host(services[0]['host']))
self.assertEqual(self.binary_name, services[0]['binary'])
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index ac717f8..af1024c 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -57,8 +57,6 @@
"to the requested name")
self.assertIsNotNone(volume['id'],
"Field volume id is empty or not found.")
- waiters.wait_for_volume_resource_status(self.volumes_client,
- volume['id'], 'available')
# Update volume with new volume_type
self.volumes_client.retype_volume(volume['id'],
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index acff7cd..b81a477 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -70,7 +70,7 @@
@test.services('compute')
def test_force_detach_volume(self):
# Create a server and a volume
- server_id = self.create_server(wait_until='ACTIVE')['id']
+ server_id = self.create_server()['id']
volume_id = self.create_volume()['id']
# Attach volume
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index eace92d..8d66156 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -217,7 +217,7 @@
cls.snapshots_client.wait_for_resource_deletion,
snapshot)
- def create_server(self, **kwargs):
+ def create_server(self, wait_until='ACTIVE', **kwargs):
name = kwargs.pop(
'name',
data_utils.rand_name(self.__class__.__name__ + '-instance'))
@@ -227,6 +227,7 @@
self.os_primary,
tenant_network=tenant_network,
name=name,
+ wait_until=wait_until,
**kwargs)
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
diff --git a/tempest/api/volume/test_availability_zone.py b/tempest/api/volume/test_availability_zone.py
index 666efdf..d0a87db 100644
--- a/tempest/api/volume/test_availability_zone.py
+++ b/tempest/api/volume/test_availability_zone.py
@@ -30,4 +30,4 @@
# List of availability zone
availability_zone = (self.client.list_availability_zones()
['availabilityZoneInfo'])
- self.assertGreater(len(availability_zone), 0)
+ self.assertNotEmpty(availability_zone)
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index 5a192ac..2c13a3c 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-from testtools import matchers
-
from tempest.api.volume import base
from tempest.common import waiters
from tempest.lib import decorators
@@ -56,7 +54,7 @@
# List volume transfers, the result should be greater than
# or equal to 1
body = self.client.list_volume_transfers()['transfers']
- self.assertThat(len(body), matchers.GreaterThan(0))
+ self.assertNotEmpty(body)
# Accept a volume transfer by alt_tenant
body = self.alt_client.accept_volume_transfer(
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index 0e7f1e9..8541c6d 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -38,7 +38,7 @@
@test.services('compute')
def test_attach_detach_volume_to_instance(self):
# Create a server
- server = self.create_server(wait_until='ACTIVE')
+ server = self.create_server()
# Volume is attached and detached successfully from an instance
self.volumes_client.attach_volume(self.volume['id'],
instance_uuid=server['id'],
@@ -69,7 +69,7 @@
@test.services('compute')
def test_get_volume_attachment(self):
# Create a server
- server = self.create_server(wait_until='ACTIVE')
+ server = self.create_server()
# Verify that a volume's attachment information is retrieved
self.volumes_client.attach_volume(self.volume['id'],
instance_uuid=server['id'],
diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py
index 5ad209c..4b4aeec 100644
--- a/tempest/api/volume/test_volumes_backup.py
+++ b/tempest/api/volume/test_volumes_backup.py
@@ -108,7 +108,7 @@
volume = self.create_volume()
self.addCleanup(self.volumes_client.delete_volume,
volume['id'])
- server = self.create_server(wait_until='ACTIVE')
+ server = self.create_server()
# Attach volume to instance
self.attach_volume(server['id'], volume['id'])
# Create backup using force flag
@@ -118,9 +118,8 @@
name=backup_name, force=True)
self.assertEqual(backup_name, backup['name'])
- @testtools.skipUnless(CONF.service_available.glance,
- "Glance is not available")
@decorators.idempotent_id('2a8ba340-dff2-4511-9db7-646f07156b15')
+ @test.services('image')
def test_bootable_volume_backup_and_restore(self):
# Create volume from image
img_uuid = CONF.compute.image_ref
diff --git a/tempest/api/volume/test_volumes_clone.py b/tempest/api/volume/test_volumes_clone.py
index a6bbb0a..4c13375 100644
--- a/tempest/api/volume/test_volumes_clone.py
+++ b/tempest/api/volume/test_volumes_clone.py
@@ -13,11 +13,10 @@
# License for the specific language governing permissions and limitations
# under the License.
-import testtools
-
from tempest.api.volume import base
from tempest import config
from tempest.lib import decorators
+from tempest import test
CONF = config.CONF
@@ -47,9 +46,8 @@
self.assertEqual(volume['source_volid'], src_vol['id'])
self.assertEqual(volume['size'], src_size + 1)
- @testtools.skipUnless(CONF.service_available.glance,
- "Glance is not available")
@decorators.idempotent_id('cbbcd7c6-5a6c-481a-97ac-ca55ab715d16')
+ @test.services('image')
def test_create_from_bootable_volume(self):
# Create volume from image
img_uuid = CONF.compute.image_ref
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index fc3bcab..4e19e62 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -170,7 +170,7 @@
@decorators.idempotent_id('f5e56b0a-5d02-43c1-a2a7-c9b792c2e3f6')
@test.services('compute')
def test_attach_volumes_with_nonexistent_volume_id(self):
- server = self.create_server(wait_until='ACTIVE')
+ server = self.create_server()
self.assertRaises(lib_exc.NotFound,
self.volumes_client.attach_volume,
@@ -261,7 +261,7 @@
params = {'name': v_name}
fetched_volume = self.volumes_client.list_volumes(
params=params)['volumes']
- self.assertEqual(0, len(fetched_volume))
+ self.assertEmpty(fetched_volume)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('9ca17820-a0e7-4cbd-a7fa-f4468735e359')
@@ -271,7 +271,7 @@
fetched_volume = \
self.volumes_client.list_volumes(
detail=True, params=params)['volumes']
- self.assertEqual(0, len(fetched_volume))
+ self.assertEmpty(fetched_volume)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('143b279b-7522-466b-81be-34a87d564a7c')
@@ -279,7 +279,7 @@
params = {'status': 'null'}
fetched_volume = self.volumes_client.list_volumes(
params=params)['volumes']
- self.assertEqual(0, len(fetched_volume))
+ self.assertEmpty(fetched_volume)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('ba94b27b-be3f-496c-a00e-0283b373fa75')
@@ -288,7 +288,7 @@
fetched_volume = \
self.volumes_client.list_volumes(detail=True,
params=params)['volumes']
- self.assertEqual(0, len(fetched_volume))
+ self.assertEmpty(fetched_volume)
@decorators.attr(type=['negative'])
@decorators.idempotent_id('5b810c91-0ad1-47ce-aee8-615f789be78f')
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 99918eb..44c1def 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -39,7 +39,7 @@
@test.services('compute')
def test_snapshot_create_delete_with_volume_in_use(self):
# Create a test instance
- server = self.create_server(wait_until='ACTIVE')
+ server = self.create_server()
self.attach_volume(server['id'], self.volume_origin['id'])
# Snapshot a volume which attached to an instance with force=False
@@ -65,7 +65,7 @@
snapshot1 = self.create_snapshot(self.volume_origin['id'])
# Create a server and attach it
- server = self.create_server(wait_until='ACTIVE')
+ server = self.create_server()
self.attach_volume(server['id'], self.volume_origin['id'])
# Now that the volume is attached, create another snapshots
diff --git a/tempest/clients.py b/tempest/clients.py
index 7b6cc19..8ad6e92 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -79,6 +79,7 @@
self.security_groups_client = self.network.SecurityGroupsClient()
self.network_versions_client = self.network.NetworkVersionsClient()
self.service_providers_client = self.network.ServiceProvidersClient()
+ self.tags_client = self.network.TagsClient()
def _set_image_clients(self):
if CONF.service_available.glance:
@@ -203,6 +204,8 @@
**params_v3)
self.endpoint_filter_client = \
self.identity_v3.EndPointsFilterClient(**params_v3)
+ self.endpoint_groups_client = self.identity_v3.EndPointGroupsClient(
+ **params_v3)
# Token clients do not use the catalog. They only need default_params.
# They read auth_url, so they should only be set if the corresponding
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 9319d2a..99a628e 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -64,10 +64,14 @@
# Show header line too
selected.append(l)
# lsblk lists disk type in a column right-aligned with TYPE
- elif pos > 0 and l[pos:pos + 4] == "disk":
+ elif pos is not None and pos > 0 and l[pos:pos + 4] == "disk":
selected.append(l)
- return "\n".join(selected)
+ if selected:
+ return "\n".join(selected)
+ else:
+ msg = "'TYPE' column is requred but the output doesn't have it: "
+ raise tempest.lib.exceptions.TempestException(msg + output)
def get_boot_time(self):
cmd = 'cut -f1 -d. /proc/uptime'
@@ -89,12 +93,12 @@
def get_nic_name_by_mac(self, address):
cmd = "ip -o link | awk '/%s/ {print $2}'" % address
nic = self.exec_command(cmd)
- return nic.strip().strip(":").lower()
+ return nic.strip().strip(":").split('@')[0].lower()
def get_nic_name_by_ip(self, address):
cmd = "ip -o addr | awk '/%s/ {print $2}'" % address
nic = self.exec_command(cmd)
- return nic.strip().strip(":").lower()
+ return nic.strip().strip(":").split('@')[0].lower()
def get_dns_servers(self):
cmd = 'cat /etc/resolv.conf'
diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py
index b15796f..9e83a07 100644
--- a/tempest/common/validation_resources.py
+++ b/tempest/common/validation_resources.py
@@ -80,10 +80,23 @@
validation_data['security_group'] = \
create_ssh_security_group(os, add_rule)
if validation_resources['floating_ip']:
- floating_client = os.compute_floating_ips_client
- validation_data.update(
- floating_client.create_floating_ip(
- pool=CONF.network.floating_network_name))
+ if CONF.service_available.neutron:
+ floatingip = os.floating_ips_client.create_floatingip(
+ floating_network_id=CONF.network.public_network_id)
+ # validation_resources['floating_ip'] has historically looked
+ # like a compute API POST /os-floating-ips response, so we need
+ # to mangle it a bit for a Neutron response with different
+ # fields.
+ validation_data['floating_ip'] = floatingip['floatingip']
+ validation_data['floating_ip']['ip'] = (
+ floatingip['floatingip']['floating_ip_address'])
+ else:
+ # NOTE(mriedem): The os-floating-ips compute API was deprecated
+ # in the 2.36 microversion. Any tests for CRUD operations on
+ # floating IPs using the compute API should be capped at 2.35.
+ validation_data.update(
+ os.compute_floating_ips_client.create_floating_ip(
+ pool=CONF.network.floating_network_name))
return validation_data
diff --git a/tempest/config.py b/tempest/config.py
index 989d53a..fbe0a1b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -768,6 +768,12 @@
"It contains two elements, the first is ref type "
"(like 'source-name', 'source-id', etc), the second is "
"volume name template used in storage backend"),
+ cfg.ListOpt('manage_snapshot_ref',
+ default=['source-name', '_snapshot-%s'],
+ help="A reference to existing snapshot for snapshot manage. "
+ "It contains two elements, the first is ref type "
+ "(like 'source-name', 'source-id', etc), the second is "
+ "snapshot name template used in storage backend"),
cfg.StrOpt('min_microversion',
default=None,
help="Lower version of the test target microversion range. "
diff --git a/tempest/lib/api_schema/response/compute/v2_13/__init__.py b/tempest/lib/api_schema/response/compute/v2_13/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_13/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_13/servers.py b/tempest/lib/api_schema/response/compute/v2_13/servers.py
new file mode 100644
index 0000000..a90f3e4
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_13/servers.py
@@ -0,0 +1,34 @@
+# Copyright 2017 NTT Corporation. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import servers
+
+
+common_server_group = copy.deepcopy(servers.common_server_group)
+common_server_group['properties']['project_id'] = {'type': 'string'}
+common_server_group['properties']['user_id'] = {'type': 'string'}
+common_server_group['required'].append('project_id')
+common_server_group['required'].append('user_id')
+
+create_show_server_group = copy.deepcopy(servers.create_show_server_group)
+create_show_server_group['response_body']['properties'][
+ 'server_group'] = common_server_group
+
+delete_server_group = copy.deepcopy(servers.delete_server_group)
+
+list_server_groups = copy.deepcopy(servers.list_server_groups)
+list_server_groups['response_body']['properties']['server_groups'][
+ 'items'] = common_server_group
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index d72b4dd..63cf07f 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -474,7 +474,7 @@
# Ensure there are not more than one top-level keys
# NOTE(freerunner): Ensure, that JSON is not nullable to
# to prevent StopIteration Exception
- if len(body.keys()) != 1:
+ if not hasattr(body, "keys") or len(body.keys()) != 1:
return body
# Just return the "wrapped" element
first_key, first_item = six.next(six.iteritems(body))
diff --git a/tempest/lib/common/utils/linux/remote_client.py b/tempest/lib/common/utils/linux/remote_client.py
index 64d6be2..aef2ff3 100644
--- a/tempest/lib/common/utils/linux/remote_client.py
+++ b/tempest/lib/common/utils/linux/remote_client.py
@@ -28,29 +28,37 @@
def wrapper(self, *args, **kwargs):
try:
return function(self, *args, **kwargs)
- except tempest.lib.exceptions.SSHTimeout:
- try:
- original_exception = sys.exc_info()
- caller = test_utils.find_test_caller() or "not found"
- if self.server:
- msg = 'Caller: %s. Timeout trying to ssh to server %s'
- LOG.debug(msg, caller, self.server)
- if self.console_output_enabled and self.servers_client:
- try:
- msg = 'Console log for server %s: %s'
- console_log = (
- self.servers_client.get_console_output(
- self.server['id'])['output'])
- LOG.debug(msg, self.server['id'], console_log)
- except Exception:
- msg = 'Could not get console_log for server %s'
- LOG.debug(msg, self.server['id'])
- # re-raise the original ssh timeout exception
- six.reraise(*original_exception)
- finally:
- # Delete the traceback to avoid circular references
- _, _, trace = original_exception
- del trace
+ except Exception as e:
+ caller = test_utils.find_test_caller() or "not found"
+ if not isinstance(e, tempest.lib.exceptions.SSHTimeout):
+ message = ('Initializing SSH connection to %(ip)s failed. '
+ 'Error: %(error)s' % {'ip': self.ip_address,
+ 'error': e})
+ message = '(%s) %s' % (caller, message)
+ LOG.error(message)
+ raise
+ else:
+ try:
+ original_exception = sys.exc_info()
+ if self.server:
+ msg = 'Caller: %s. Timeout trying to ssh to server %s'
+ LOG.debug(msg, caller, self.server)
+ if self.console_output_enabled and self.servers_client:
+ try:
+ msg = 'Console log for server %s: %s'
+ console_log = (
+ self.servers_client.get_console_output(
+ self.server['id'])['output'])
+ LOG.debug(msg, self.server['id'], console_log)
+ except Exception:
+ msg = 'Could not get console_log for server %s'
+ LOG.debug(msg, self.server['id'])
+ # re-raise the original ssh timeout exception
+ six.reraise(*original_exception)
+ finally:
+ # Delete the traceback to avoid circular references
+ _, _, trace = original_exception
+ del trace
return wrapper
@@ -78,6 +86,7 @@
"""
self.server = server
self.servers_client = servers_client
+ self.ip_address = ip_address
self.console_output_enabled = console_output_enabled
self.ssh_shell_prologue = ssh_shell_prologue
self.ping_count = ping_count
diff --git a/tempest/lib/services/compute/server_groups_client.py b/tempest/lib/services/compute/server_groups_client.py
index 3a935b4..03cd645 100644
--- a/tempest/lib/services/compute/server_groups_client.py
+++ b/tempest/lib/services/compute/server_groups_client.py
@@ -17,12 +17,17 @@
from oslo_serialization import jsonutils as json
from tempest.lib.api_schema.response.compute.v2_1 import servers as schema
+from tempest.lib.api_schema.response.compute.v2_13 import servers as schemav213
from tempest.lib.common import rest_client
from tempest.lib.services.compute import base_compute_client
class ServerGroupsClient(base_compute_client.BaseComputeClient):
+ schema_versions_info = [
+ {'min': None, 'max': '2.12', 'schema': schema},
+ {'min': '2.13', 'max': None, 'schema': schemav213}]
+
def create_server_group(self, **kwargs):
"""Create the server group.
@@ -34,12 +39,14 @@
resp, body = self.post('os-server-groups', post_body)
body = json.loads(body)
+ schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.create_show_server_group, resp, body)
return rest_client.ResponseBody(resp, body)
def delete_server_group(self, server_group_id):
"""Delete the given server-group."""
resp, body = self.delete("os-server-groups/%s" % server_group_id)
+ schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.delete_server_group, resp, body)
return rest_client.ResponseBody(resp, body)
@@ -47,6 +54,7 @@
"""List the server-groups."""
resp, body = self.get("os-server-groups")
body = json.loads(body)
+ schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.list_server_groups, resp, body)
return rest_client.ResponseBody(resp, body)
@@ -54,5 +62,6 @@
"""Get the details of given server_group."""
resp, body = self.get("os-server-groups/%s" % server_group_id)
body = json.loads(body)
+ schema = self.get_schema(self.schema_versions_info)
self.validate_response(schema.create_show_server_group, resp, body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/identity/v2/identity_client.py b/tempest/lib/services/identity/v2/identity_client.py
index 6caff0e..c610d65 100644
--- a/tempest/lib/services/identity/v2/identity_client.py
+++ b/tempest/lib/services/identity/v2/identity_client.py
@@ -11,6 +11,7 @@
# under the License.
from oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
from tempest.lib.common import rest_client
@@ -45,3 +46,24 @@
self.expected_success(200, resp.status)
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
+
+ def list_endpoints_for_token(self, token_id):
+ """List endpoints for a token """
+ resp, body = self.get("tokens/%s/endpoints" % token_id)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def check_token_existence(self, token_id, **params):
+ """Validates a token and confirms that it belongs to a tenant.
+
+ For a full list of available parameters, please refer to the
+ official API reference:
+ https://developer.openstack.org/api-ref/identity/v2-admin/#validate-token
+ """
+ url = "tokens/%s" % token_id
+ if params:
+ url += '?%s' % urllib.urlencode(params)
+ resp, body = self.head(url)
+ self.expected_success(200, resp.status)
+ return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/identity/v3/__init__.py b/tempest/lib/services/identity/v3/__init__.py
index 6f498d9..ce607ff 100644
--- a/tempest/lib/services/identity/v3/__init__.py
+++ b/tempest/lib/services/identity/v3/__init__.py
@@ -19,6 +19,8 @@
from tempest.lib.services.identity.v3.domains_client import DomainsClient
from tempest.lib.services.identity.v3.endpoint_filter_client import \
EndPointsFilterClient
+from tempest.lib.services.identity.v3.endpoint_groups_client import \
+ EndPointGroupsClient
from tempest.lib.services.identity.v3.endpoints_client import EndPointsClient
from tempest.lib.services.identity.v3.groups_client import GroupsClient
from tempest.lib.services.identity.v3.identity_client import IdentityClient
@@ -39,8 +41,9 @@
from tempest.lib.services.identity.v3.versions_client import VersionsClient
__all__ = ['CredentialsClient', 'DomainsClient', 'DomainConfigurationClient',
- 'EndPointsClient', 'EndPointsFilterClient', 'GroupsClient',
- 'IdentityClient', 'InheritedRolesClient', 'OAUTHConsumerClient',
- 'PoliciesClient', 'ProjectsClient', 'RegionsClient',
- 'RoleAssignmentsClient', 'RolesClient', 'ServicesClient',
- 'V3TokenClient', 'TrustsClient', 'UsersClient', 'VersionsClient']
+ 'EndPointGroupsClient', 'EndPointsClient', 'EndPointsFilterClient',
+ 'GroupsClient', 'IdentityClient', 'InheritedRolesClient',
+ 'OAUTHConsumerClient', 'PoliciesClient', 'ProjectsClient',
+ 'RegionsClient', 'RoleAssignmentsClient', 'RolesClient',
+ 'ServicesClient', 'V3TokenClient', 'TrustsClient', 'UsersClient',
+ 'VersionsClient']
diff --git a/tempest/lib/services/identity/v3/endpoint_groups_client.py b/tempest/lib/services/identity/v3/endpoint_groups_client.py
new file mode 100644
index 0000000..723aeaa
--- /dev/null
+++ b/tempest/lib/services/identity/v3/endpoint_groups_client.py
@@ -0,0 +1,78 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+
+
+class EndPointGroupsClient(rest_client.RestClient):
+ api_version = "v3"
+
+ def create_endpoint_group(self, **kwargs):
+ """Create endpoint group.
+
+ For a full list of available parameters, please refer to the
+ official API reference:
+ https://developer.openstack.org/api-ref/identity/v3-ext/#create-endpoint-group
+ """
+ post_body = json.dumps({'endpoint_group': kwargs})
+ resp, body = self.post('OS-EP-FILTER/endpoint_groups', post_body)
+ self.expected_success(201, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def update_endpoint_group(self, endpoint_group_id, **kwargs):
+ """Update endpoint group.
+
+ For a full list of available parameters, please refer to the
+ official API reference:
+ https://developer.openstack.org/api-ref/identity/v3-ext/#update-endpoint-group
+ """
+ post_body = json.dumps({'endpoint_group': kwargs})
+ resp, body = self.patch(
+ 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id, post_body)
+ self.expected_success(200, resp.status)
+ body = json.loads(body)
+ return rest_client.ResponseBody(resp, body)
+
+ def delete_endpoint_group(self, endpoint_group_id):
+ """Delete endpoint group."""
+ resp_header, resp_body = self.delete(
+ 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id)
+ self.expected_success(204, resp_header.status)
+ return rest_client.ResponseBody(resp_header, resp_body)
+
+ def show_endpoint_group(self, endpoint_group_id):
+ """Get endpoint group."""
+ resp_header, resp_body = self.get(
+ 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id)
+ self.expected_success(200, resp_header.status)
+ resp_body = json.loads(resp_body)
+ return rest_client.ResponseBody(resp_header, resp_body)
+
+ def check_endpoint_group(self, endpoint_group_id):
+ """Check endpoint group."""
+ resp_header, resp_body = self.head(
+ 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id)
+ self.expected_success(200, resp_header.status)
+ return rest_client.ResponseBody(resp_header, resp_body)
+
+ def list_endpoint_groups(self):
+ """Get endpoint groups."""
+ resp_header, resp_body = self.get('OS-EP-FILTER/endpoint_groups')
+ self.expected_success(200, resp_header.status)
+ resp_body = json.loads(resp_body)
+ return rest_client.ResponseBody(resp_header, resp_body)
diff --git a/tempest/lib/services/network/__init__.py b/tempest/lib/services/network/__init__.py
index 19e5463..419e593 100644
--- a/tempest/lib/services/network/__init__.py
+++ b/tempest/lib/services/network/__init__.py
@@ -31,11 +31,12 @@
ServiceProvidersClient
from tempest.lib.services.network.subnetpools_client import SubnetpoolsClient
from tempest.lib.services.network.subnets_client import SubnetsClient
+from tempest.lib.services.network.tags_client import TagsClient
from tempest.lib.services.network.versions_client import NetworkVersionsClient
__all__ = ['AgentsClient', 'ExtensionsClient', 'FloatingIPsClient',
'MeteringLabelRulesClient', 'MeteringLabelsClient',
- 'NetworksClient', 'PortsClient', 'QuotasClient', 'RoutersClient',
- 'SecurityGroupRulesClient', 'SecurityGroupsClient',
- 'ServiceProvidersClient', 'SubnetpoolsClient', 'SubnetsClient',
- 'NetworkVersionsClient']
+ 'NetworksClient', 'NetworkVersionsClient', 'PortsClient',
+ 'QuotasClient', 'RoutersClient', 'SecurityGroupRulesClient',
+ 'SecurityGroupsClient', 'ServiceProvidersClient',
+ 'SubnetpoolsClient', 'SubnetsClient', 'TagsClient']
diff --git a/tempest/lib/services/network/tags_client.py b/tempest/lib/services/network/tags_client.py
new file mode 100644
index 0000000..20c2c11
--- /dev/null
+++ b/tempest/lib/services/network/tags_client.py
@@ -0,0 +1,88 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.common import rest_client
+from tempest.lib.services.network import base
+
+
+class TagsClient(base.BaseNetworkClient):
+
+ def create_tag(self, resource_type, resource_id, tag):
+ """Adds a tag on the resource.
+
+ For more information, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#add-a-tag
+ """
+ # NOTE(felipemonteiro): Cannot use ``update_resource`` method because
+ # this API requires self.put but returns 201 instead of 200 expected
+ # by ``update_resource``.
+ uri = '%s/%s/%s/tags/%s' % (
+ self.uri_prefix, resource_type, resource_id, tag)
+ resp, _ = self.put(uri, json.dumps({}))
+ self.expected_success(201, resp.status)
+ return rest_client.ResponseBody(resp)
+
+ def check_tag_existence(self, resource_type, resource_id, tag):
+ """Confirm that a given tag is set on the resource.
+
+ For more information, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#confirm-a-tag
+ """
+ # TODO(felipemonteiro): Use the "check_resource" method in
+ # ``BaseNetworkClient`` once it has been implemented.
+ uri = '%s/%s/%s/tags/%s' % (
+ self.uri_prefix, resource_type, resource_id, tag)
+ resp, _ = self.get(uri)
+ self.expected_success(204, resp.status)
+ return rest_client.ResponseBody(resp)
+
+ def update_all_tags(self, resource_type, resource_id, tags):
+ """Replace all tags on the resource.
+
+ For more information, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#replace-all-tags
+ """
+ uri = '/%s/%s/tags' % (resource_type, resource_id)
+ put_body = {"tags": tags}
+ return self.update_resource(uri, put_body)
+
+ def delete_tag(self, resource_type, resource_id, tag):
+ """Removes a tag on the resource.
+
+ For more information, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#remove-a-tag
+ """
+ uri = '/%s/%s/tags/%s' % (resource_type, resource_id, tag)
+ return self.delete_resource(uri)
+
+ def delete_all_tags(self, resource_type, resource_id):
+ """Removes all tags on the resource.
+
+ For more information, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#remove-all-tags
+ """
+ uri = '/%s/%s/tags' % (resource_type, resource_id)
+ return self.delete_resource(uri)
+
+ def list_tags(self, resource_type, resource_id):
+ """Retrieves the tags for a resource.
+
+ For more information, please refer to the official API reference:
+ http://developer.openstack.org/api-ref/networking/v2/index.html#obtain-tag-list
+ """
+ uri = '/%s/%s/tags' % (resource_type, resource_id)
+ return self.list_resources(uri)
diff --git a/tempest/lib/services/volume/v2/volumes_client.py b/tempest/lib/services/volume/v2/volumes_client.py
index 8b5c96f..f4e7c6a 100644
--- a/tempest/lib/services/volume/v2/volumes_client.py
+++ b/tempest/lib/services/volume/v2/volumes_client.py
@@ -321,7 +321,7 @@
self.expected_success(200, resp.status)
return rest_client.ResponseBody(resp, body)
- @removals.remove(message="use show_pools from tempest.lib.services."
+ @removals.remove(message="use list_pools from tempest.lib.services."
"volume.v2.scheduler_stats_client")
def show_pools(self, detail=False):
# List all the volumes pools (hosts)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index a486a29..38e03c7 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -195,7 +195,7 @@
tenant_network = self.get_tenant_network()
- body, servers = compute.create_test_server(
+ body, _ = compute.create_test_server(
clients,
tenant_network=tenant_network,
wait_until=wait_until,
@@ -313,13 +313,15 @@
return secgroup
- def get_remote_client(self, ip_address, username=None, private_key=None):
+ def get_remote_client(self, ip_address, username=None, private_key=None,
+ server=None):
"""Get a SSH client to a remote server
@param ip_address the server floating or fixed IP address to use
for ssh validation
@param username name of the Linux account on the remote server
@param private_key the SSH private key to use
+ @param server: server dict, used for debugging purposes
@return a RemoteClient object
"""
@@ -334,22 +336,10 @@
else:
password = CONF.validation.image_ssh_password
private_key = None
- linux_client = remote_client.RemoteClient(ip_address, username,
- pkey=private_key,
- password=password)
- try:
- linux_client.validate_authentication()
- except Exception as e:
- message = ('Initializing SSH connection to %(ip)s failed. '
- 'Error: %(error)s' % {'ip': ip_address,
- 'error': e})
- caller = test_utils.find_test_caller()
- if caller:
- message = '(%s) %s' % (caller, message)
- LOG.exception(message)
- self._log_console_output()
- raise
-
+ linux_client = remote_client.RemoteClient(
+ ip_address, username, pkey=private_key, password=password,
+ server=server, servers_client=self.servers_client)
+ linux_client.validate_authentication()
return linux_client
def _image_create(self, name, fmt, path,
@@ -811,7 +801,7 @@
if inactive:
LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
- self.assertNotEqual(0, len(port_map),
+ self.assertNotEmpty(port_map,
"No IPv4 addresses found in: %s" % ports)
self.assertEqual(len(port_map), 1,
"Found multiple IPv4 addresses: %s. "
@@ -822,7 +812,7 @@
def _get_network_by_name(self, network_name):
net = self.os_admin.networks_client.list_networks(
name=network_name)['networks']
- self.assertNotEqual(len(net), 0,
+ self.assertNotEmpty(net,
"Unable to get network by name: %s" % network_name)
return net[0]
@@ -1029,7 +1019,7 @@
if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
]
msg = "No default security group for tenant %s." % (tenant_id)
- self.assertGreater(len(sgs), 0, msg)
+ self.assertNotEmpty(sgs, msg)
return sgs[0]
def _create_security_group_rule(self, secgroup=None,
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index c06d239..25227be 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -52,7 +52,7 @@
def _get_host_name(self):
hosts = self.hosts_client.list_hosts()['hosts']
- self.assertGreaterEqual(len(hosts), 1)
+ self.assertNotEmpty(hosts)
computes = [x for x in hosts if x['service'] == 'compute']
return computes[0]['host_name']
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index eae1056..26a834b 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -141,14 +141,16 @@
# check that we can SSH to the server before reboot
self.linux_client = self.get_remote_client(
- floating_ip['ip'], private_key=keypair['private_key'])
+ floating_ip['ip'], private_key=keypair['private_key'],
+ server=server)
self.nova_reboot(server)
# check that we can SSH to the server after reboot
# (both connections are part of the scenario)
self.linux_client = self.get_remote_client(
- floating_ip['ip'], private_key=keypair['private_key'])
+ floating_ip['ip'], private_key=keypair['private_key'],
+ server=server)
self.check_disks()
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index ec6d362..c8add8b 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -62,7 +62,7 @@
if test.is_extension_enabled('security-group', 'network'):
security_group = self._create_security_group()
security_groups = [{'name': security_group['name']}]
- network, subnet, router = self.create_networks()
+ network, _, _ = self.create_networks()
server = self.create_server(
networks=[{'uuid': network['id']}],
key_name=keypair['name'],
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index c76c082..48ddac6 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -212,7 +212,7 @@
self.servers, mtu=mtu)
def _disassociate_floating_ips(self):
- floating_ip, server = self.floating_ip_tuple
+ floating_ip, _ = self.floating_ip_tuple
self._disassociate_floating_ip(floating_ip)
self.floating_ip_tuple = Floating_IP_tuple(
floating_ip, None)
@@ -240,7 +240,7 @@
ip_address = old_floating_ip['floating_ip_address']
private_key = self._get_server_key(server)
ssh_client = self.get_remote_client(
- ip_address, private_key=private_key)
+ ip_address, private_key=private_key, server=server)
old_nic_list = self._get_server_nics(ssh_client)
# get a port from a list of one item
port_list = self.os_admin.ports_client.list_ports(
@@ -287,7 +287,7 @@
"guest after %s sec"
% CONF.network.build_timeout)
- num, new_nic = self.diff_list[0]
+ _, new_nic = self.diff_list[0]
ssh_client.exec_command("sudo ip addr add %s/%s dev %s" % (
new_port['fixed_ips'][0]['ip_address'],
CONF.network.project_network_mask_bits,
@@ -295,7 +295,7 @@
ssh_client.exec_command("sudo ip link set %s up" % new_nic)
def _get_server_nics(self, ssh_client):
- reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+):')
+ reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+)[@]?.*:')
ipatxt = ssh_client.exec_command("ip address")
return reg.findall(ipatxt)
@@ -348,7 +348,8 @@
ip_address = floating_ip['floating_ip_address']
private_key = self._get_server_key(self.floating_ip_tuple.server)
ssh_source = self.get_remote_client(
- ip_address, private_key=private_key)
+ ip_address, private_key=private_key,
+ server=self.floating_ip_tuple.server)
for remote_ip in address_list:
self.check_remote_connectivity(ssh_source, remote_ip,
@@ -575,7 +576,7 @@
ip_address = floating_ip['floating_ip_address']
private_key = self._get_server_key(server)
ssh_client = self.get_remote_client(
- ip_address, private_key=private_key)
+ ip_address, private_key=private_key, server=server)
dns_servers = [initial_dns_server]
servers = ssh_client.get_dns_servers()
@@ -630,7 +631,7 @@
admin_state_up attribute of instance port to True
"""
self._setup_network_and_servers()
- floating_ip, server = self.floating_ip_tuple
+ _, server = self.floating_ip_tuple
server_id = server['id']
port_id = self.os_admin.ports_client.list_ports(
device_id=server_id)['ports'][0]['id']
@@ -641,7 +642,8 @@
private_key = self._get_server_key(server2)
ssh_client = self.get_remote_client(server2_fip['floating_ip_address'],
- private_key=private_key)
+ private_key=private_key,
+ server=server2)
self.check_public_network_connectivity(
should_connect=True, msg="before updating "
@@ -830,7 +832,8 @@
spoof_port = new_ports[0]
private_key = self._get_server_key(server)
ssh_client = self.get_remote_client(fip['floating_ip_address'],
- private_key=private_key)
+ private_key=private_key,
+ server=server)
spoof_nic = ssh_client.get_nic_name_by_mac(spoof_port["mac_address"])
peer = self._create_server(self.new_net)
peer_address = peer['addresses'][self.new_net['name']][0]['addr']
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 3504a44..bf26c2e 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -131,7 +131,7 @@
ips = self.define_server_ips(srv=srv)
ssh = self.get_remote_client(
ip_address=fip['floating_ip_address'],
- username=username)
+ username=username, server=srv)
return ssh, ips, srv["id"]
def turn_nic6_on(self, ssh, sid, network_id):
@@ -171,7 +171,7 @@
# Turn on 2nd NIC for Cirros when dualnet
if dualnet:
- network, network_v6 = net_list
+ _, network_v6 = net_list
self.turn_nic6_on(sshv4_1, sid1, network_v6['id'])
self.turn_nic6_on(sshv4_2, sid2, network_v6['id'])
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 77563b3..0c441ab 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -62,7 +62,8 @@
self.ssh_client = self.get_remote_client(
ip_address=self.fip,
username=self.ssh_user,
- private_key=keypair['private_key'])
+ private_key=keypair['private_key'],
+ server=self.instance)
def verify_metadata(self):
if self.run_ssh and CONF.compute_feature_enabled.metadata_service:
diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py
index 63dc23d..81b71b1 100644
--- a/tempest/scenario/test_volume_migrate_attached.py
+++ b/tempest/scenario/test_volume_migrate_attached.py
@@ -41,6 +41,7 @@
def setup_clients(cls):
super(TestVolumeMigrateRetypeAttached, cls).setup_clients()
cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client
+ cls.admin_volumes_client = cls.os_admin.volumes_v2_client
@classmethod
def skip_checks(cls):
@@ -82,7 +83,7 @@
def _volume_retype_with_migration(self, volume_id, new_volume_type):
migration_policy = 'on-demand'
- self.volumes_client.retype_volume(
+ self.admin_volumes_client.retype_volume(
volume_id, new_type=new_volume_type,
migration_policy=migration_policy)
waiters.wait_for_volume_retype(self.volumes_client,
diff --git a/tempest/tests/lib/test_rest_client.py b/tempest/tests/lib/common/test_rest_client.py
similarity index 99%
rename from tempest/tests/lib/test_rest_client.py
rename to tempest/tests/lib/common/test_rest_client.py
index ace2b80..4c0bb57 100644
--- a/tempest/tests/lib/test_rest_client.py
+++ b/tempest/tests/lib/common/test_rest_client.py
@@ -276,6 +276,11 @@
body = self.rest_client._parse_resp(json.dumps(self.null_dict))
self.assertEqual(self.null_dict, body)
+ def test_parse_empty_list(self):
+ empty_list = []
+ body = self.rest_client._parse_resp(json.dumps(empty_list))
+ self.assertEqual(empty_list, body)
+
class TestRestClientErrorCheckerJSON(base.TestCase):
c_type = "application/json"
diff --git a/tempest/tests/lib/services/base.py b/tempest/tests/lib/services/base.py
index 71b7f2d..90c9f63 100644
--- a/tempest/tests/lib/services/base.py
+++ b/tempest/tests/lib/services/base.py
@@ -31,12 +31,42 @@
def check_service_client_function(self, function, function2mock,
body, to_utf=False, status=200,
- headers=None, **kwargs):
+ headers=None, mock_args=None,
+ **kwargs):
+ """Mock a service client function for unit testing.
+
+ :param function: The service client function to call.
+ :param function2mock: The REST call to mock inside the service client
+ function.
+ :param body: Expected response body returned by the service client
+ function.
+ :param to_utf: Whether to use UTF-8 encoding for request.
+ :param status: Expected response status returned by the service client
+ function.
+ :param headers: Expected headers returned by the service client
+ function.
+ :param mock_args: List/dict/value of expected args/kwargs called by
+ function2mock. For example:
+ * If mock_args=['foo'] then ``assert_called_once_with('foo')``
+ is called.
+ * If mock_args={'foo': 'bar'} then
+ ``assert_called_once_with(foo='bar')`` is called.
+ * If mock_args='foo' then ``assert_called_once_with('foo')``
+ is called.
+ :param kwargs: kwargs that are passed to function.
+ """
mocked_response = self.create_response(body, to_utf, status, headers)
- self.useFixture(fixtures.MockPatch(
+ fixture = self.useFixture(fixtures.MockPatch(
function2mock, return_value=mocked_response))
if kwargs:
resp = function(**kwargs)
else:
resp = function()
self.assertEqual(body, resp)
+
+ if isinstance(mock_args, list):
+ fixture.mock.assert_called_once_with(*mock_args)
+ elif isinstance(mock_args, dict):
+ fixture.mock.assert_called_once_with(**mock_args)
+ elif mock_args is not None:
+ fixture.mock.assert_called_once_with(mock_args)
diff --git a/tempest/tests/lib/services/compute/test_server_groups_client.py b/tempest/tests/lib/services/compute/test_server_groups_client.py
index 1c535ca..9055a36 100644
--- a/tempest/tests/lib/services/compute/test_server_groups_client.py
+++ b/tempest/tests/lib/services/compute/test_server_groups_client.py
@@ -13,9 +13,10 @@
# under the License.
import fixtures
-from tempest.tests.lib import fake_auth_provider
+from tempest.lib.services.compute import base_compute_client
from tempest.lib.services.compute import server_groups_client
+from tempest.tests.lib import fake_auth_provider
from tempest.tests.lib import fake_http
from tempest.tests.lib.services import base
@@ -36,7 +37,7 @@
fake_auth, 'compute', 'regionOne')
def _test_create_server_group(self, bytes_body=False):
- expected = {"server_group": TestServerGroupsClient.server_group}
+ expected = {"server_group": self.server_group}
self.check_service_client_function(
self.client.create_server_group,
'tempest.lib.common.rest_client.RestClient.post', expected,
@@ -56,7 +57,7 @@
self.client.delete_server_group('fake-group')
def _test_list_server_groups(self, bytes_body=False):
- expected = {"server_groups": [TestServerGroupsClient.server_group]}
+ expected = {"server_groups": [self.server_group]}
self.check_service_client_function(
self.client.list_server_groups,
'tempest.lib.common.rest_client.RestClient.get',
@@ -69,7 +70,7 @@
self._test_list_server_groups(bytes_body=True)
def _test_show_server_group(self, bytes_body=False):
- expected = {"server_group": TestServerGroupsClient.server_group}
+ expected = {"server_group": self.server_group}
self.check_service_client_function(
self.client.show_server_group,
'tempest.lib.common.rest_client.RestClient.get',
@@ -81,3 +82,20 @@
def test_show_server_group_byte_body(self):
self._test_show_server_group(bytes_body=True)
+
+
+class TestServerGroupsClientMinV213(TestServerGroupsClient):
+
+ server_group = {
+ "id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9",
+ "name": "test",
+ "policies": ["anti-affinity"],
+ "members": [],
+ "metadata": {},
+ "project_id": "0beb4bffb7a445eb8eb05fee3ee7660a",
+ "user_id": "86031628064a4f99bb66ec03c507dcd8"}
+
+ def setUp(self):
+ super(TestServerGroupsClientMinV213, self).setUp()
+ self.patchobject(base_compute_client, 'COMPUTE_MICROVERSION',
+ new='2.13')
diff --git a/tempest/tests/lib/services/identity/v2/test_identity_client.py b/tempest/tests/lib/services/identity/v2/test_identity_client.py
index 96d50d7..303d1f7 100644
--- a/tempest/tests/lib/services/identity/v2/test_identity_client.py
+++ b/tempest/tests/lib/services/identity/v2/test_identity_client.py
@@ -26,6 +26,33 @@
}
}
+ FAKE_ENDPOINTS_FOR_TOKEN = {
+ "endpoints_links": [],
+ "endpoints": [
+ {
+ "name": "nova",
+ "adminURL": "https://nova.region-one.internal.com/" +
+ "v2/be1319401cfa4a0aa590b97cc7b64d8d",
+ "region": "RegionOne",
+ "internalURL": "https://nova.region-one.internal.com/" +
+ "v2/be1319401cfa4a0aa590b97cc7b64d8d",
+ "type": "compute",
+ "id": "11b41ee1b00841128b7333d4bf1a6140",
+ "publicURL": "https://nova.region-one.public.com/v2/" +
+ "be1319401cfa4a0aa590b97cc7b64d8d"
+ },
+ {
+ "name": "neutron",
+ "adminURL": "https://neutron.region-one.internal.com/",
+ "region": "RegionOne",
+ "internalURL": "https://neutron.region-one.internal.com/",
+ "type": "network",
+ "id": "cdbfa3c416d741a9b5c968f2dc628acb",
+ "publicURL": "https://neutron.region-one.public.com/"
+ }
+ ]
+ }
+
FAKE_API_INFO = {
"name": "API_info",
"type": "API",
@@ -148,6 +175,22 @@
bytes_body,
token_id="cbc36478b0bd8e67e89")
+ def _test_list_endpoints_for_token(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_endpoints_for_token,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_ENDPOINTS_FOR_TOKEN,
+ bytes_body,
+ token_id="cbc36478b0bd8e67e89")
+
+ def _test_check_token_existence(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.check_token_existence,
+ 'tempest.lib.common.rest_client.RestClient.head',
+ {},
+ bytes_body,
+ token_id="cbc36478b0bd8e67e89")
+
def test_show_api_description_with_str_body(self):
self._test_show_api_description()
@@ -166,6 +209,18 @@
def test_show_token_with_bytes_body(self):
self._test_show_token(bytes_body=True)
+ def test_list_endpoints_for_token_with_str_body(self):
+ self._test_list_endpoints_for_token()
+
+ def test_list_endpoints_for_token_with_bytes_body(self):
+ self._test_list_endpoints_for_token(bytes_body=True)
+
+ def test_check_token_existence_with_bytes_body(self):
+ self._test_check_token_existence(bytes_body=True)
+
+ def test_check_token_existence_with_str_body(self):
+ self._test_check_token_existence()
+
def test_delete_token(self):
self.check_service_client_function(
self.client.delete_token,
diff --git a/tempest/tests/lib/services/identity/v3/test_endpoint_groups_client.py b/tempest/tests/lib/services/identity/v3/test_endpoint_groups_client.py
new file mode 100644
index 0000000..8b034e6
--- /dev/null
+++ b/tempest/tests/lib/services/identity/v3/test_endpoint_groups_client.py
@@ -0,0 +1,162 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.identity.v3 import endpoint_groups_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestEndPointGroupsClient(base.BaseServiceTest):
+ FAKE_CREATE_ENDPOINT_GROUP = {
+ "endpoint_group": {
+ "id": 1,
+ "name": "FAKE_ENDPOINT_GROUP",
+ "description": "FAKE SERVICE ENDPOINT GROUP",
+ "filters": {
+ "service_id": 1
+ }
+ }
+ }
+
+ FAKE_ENDPOINT_GROUP_INFO = {
+ "endpoint_group": {
+ "id": 1,
+ "name": "FAKE_ENDPOINT_GROUP",
+ "description": "FAKE SERVICE ENDPOINT GROUP",
+ "links": {
+ "self": "http://example.com/identity/v3/OS-EP-FILTER/" +
+ "endpoint_groups/1"
+ },
+ "filters": {
+ "service_id": 1
+ }
+ }
+ }
+
+ FAKE_LIST_ENDPOINT_GROUPS = {
+ "endpoint_groups": [
+ {
+ "id": 1,
+ "name": "SERVICE_GROUP1",
+ "description": "FAKE SERVICE ENDPOINT GROUP",
+ "links": {
+ "self": "http://example.com/identity/v3/OS-EP-FILTER/" +
+ "endpoint_groups/1"
+ },
+ "filters": {
+ "service_id": 1
+ }
+ },
+ {
+ "id": 2,
+ "name": "SERVICE_GROUP2",
+ "description": "FAKE SERVICE ENDPOINT GROUP",
+ "links": {
+ "self": "http://example.com/identity/v3/OS-EP-FILTER/" +
+ "endpoint_groups/2"
+ },
+ "filters": {
+ "service_id": 2
+ }
+ }
+ ]
+ }
+
+ def setUp(self):
+ super(TestEndPointGroupsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = endpoint_groups_client.EndPointGroupsClient(
+ fake_auth, 'identity', 'regionOne')
+
+ def _test_create_endpoint_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_endpoint_group,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_CREATE_ENDPOINT_GROUP,
+ bytes_body,
+ status=201,
+ name="FAKE_ENDPOINT_GROUP",
+ filters={'service_id': "1"})
+
+ def _test_show_endpoint_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_endpoint_group,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_ENDPOINT_GROUP_INFO,
+ bytes_body,
+ endpoint_group_id="1")
+
+ def _test_check_endpoint_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.check_endpoint_group,
+ 'tempest.lib.common.rest_client.RestClient.head',
+ {},
+ bytes_body,
+ status=200,
+ endpoint_group_id="1")
+
+ def _test_update_endpoint_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_endpoint_group,
+ 'tempest.lib.common.rest_client.RestClient.patch',
+ self.FAKE_ENDPOINT_GROUP_INFO,
+ bytes_body,
+ endpoint_group_id="1",
+ name="NewName")
+
+ def _test_list_endpoint_groups(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_endpoint_groups,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_LIST_ENDPOINT_GROUPS,
+ bytes_body)
+
+ def test_create_endpoint_group_with_str_body(self):
+ self._test_create_endpoint_group()
+
+ def test_create_endpoint_group_with_bytes_body(self):
+ self._test_create_endpoint_group(bytes_body=True)
+
+ def test_show_endpoint_group_with_str_body(self):
+ self._test_show_endpoint_group()
+
+ def test_show_endpoint_group_with_bytes_body(self):
+ self._test_show_endpoint_group(bytes_body=True)
+
+ def test_check_endpoint_group_with_str_body(self):
+ self._test_check_endpoint_group()
+
+ def test_check_endpoint_group_with_bytes_body(self):
+ self._test_check_endpoint_group(bytes_body=True)
+
+ def test_list_endpoint_groups_with_str_body(self):
+ self._test_list_endpoint_groups()
+
+ def test_list_endpoint_groups_with_bytes_body(self):
+ self._test_list_endpoint_groups(bytes_body=True)
+
+ def test_update_endpoint_group_with_str_body(self):
+ self._test_update_endpoint_group()
+
+ def test_update_endpoint_group_with_bytes_body(self):
+ self._test_update_endpoint_group(bytes_body=True)
+
+ def test_delete_endpoint_group(self):
+ self.check_service_client_function(
+ self.client.delete_endpoint_group,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ endpoint_group_id="1",
+ status=204)
diff --git a/tempest/tests/lib/services/identity/v3/test_services_client.py b/tempest/tests/lib/services/identity/v3/test_services_client.py
index f87fcce..b464644 100644
--- a/tempest/tests/lib/services/identity/v3/test_services_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_services_client.py
@@ -101,12 +101,15 @@
bytes_body,
service_id="686766")
- def _test_list_services(self, bytes_body=False):
+ def _test_list_services(self, bytes_body=False, mock_args='services',
+ **params):
self.check_service_client_function(
self.client.list_services,
'tempest.lib.common.rest_client.RestClient.get',
self.FAKE_LIST_SERVICES,
- bytes_body)
+ bytes_body,
+ mock_args=[mock_args],
+ **params)
def _test_update_service(self, bytes_body=False):
self.check_service_client_function(
@@ -134,6 +137,10 @@
def test_list_services_with_bytes_body(self):
self._test_list_services(bytes_body=True)
+ def test_list_services_with_params(self):
+ self._test_list_services(
+ type='fake-type', mock_args='services?type=fake-type')
+
def test_update_service_with_str_body(self):
self._test_update_service()
diff --git a/tempest/tests/lib/services/network/test_extensions_client.py b/tempest/tests/lib/services/network/test_extensions_client.py
new file mode 100644
index 0000000..27eb485
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_extensions_client.py
@@ -0,0 +1,201 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.network import extensions_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestExtensionsClient(base.BaseServiceTest):
+
+ FAKE_EXTENSIONS = {
+ "extensions": [
+ {
+ "updated": "2013-01-20T00:00:00-00:00",
+ "name": "Neutron Service Type Management",
+ "links": [],
+ "alias": "service-type",
+ "description": "API for retrieving service providers for"
+ " Neutron advanced services"
+ },
+ {
+ "updated": "2012-10-05T10:00:00-00:00",
+ "name": "security-group",
+ "links": [],
+ "alias": "security-group",
+ "description": "The security groups extension."
+ },
+ {
+ "updated": "2013-02-07T10:00:00-00:00",
+ "name": "L3 Agent Scheduler",
+ "links": [],
+ "alias": "l3_agent_scheduler",
+ "description": "Schedule routers among l3 agents"
+ },
+ {
+ "updated": "2013-02-07T10:00:00-00:00",
+ "name": "Loadbalancer Agent Scheduler",
+ "links": [],
+ "alias": "lbaas_agent_scheduler",
+ "description": "Schedule pools among lbaas agents"
+ },
+ {
+ "updated": "2013-03-28T10:00:00-00:00",
+ "name": "Neutron L3 Configurable external gateway mode",
+ "links": [],
+ "alias": "ext-gw-mode",
+ "description":
+ "Extension of the router abstraction for specifying whether"
+ " SNAT should occur on the external gateway"
+ },
+ {
+ "updated": "2014-02-03T10:00:00-00:00",
+ "name": "Port Binding",
+ "links": [],
+ "alias": "binding",
+ "description": "Expose port bindings of a virtual port to"
+ " external application"
+ },
+ {
+ "updated": "2012-09-07T10:00:00-00:00",
+ "name": "Provider Network",
+ "links": [],
+ "alias": "provider",
+ "description": "Expose mapping of virtual networks to"
+ " physical networks"
+ },
+ {
+ "updated": "2013-02-03T10:00:00-00:00",
+ "name": "agent",
+ "links": [],
+ "alias": "agent",
+ "description": "The agent management extension."
+ },
+ {
+ "updated": "2012-07-29T10:00:00-00:00",
+ "name": "Quota management support",
+ "links": [],
+ "alias": "quotas",
+ "description": "Expose functions for quotas management per"
+ " tenant"
+ },
+ {
+ "updated": "2013-02-07T10:00:00-00:00",
+ "name": "DHCP Agent Scheduler",
+ "links": [],
+ "alias": "dhcp_agent_scheduler",
+ "description": "Schedule networks among dhcp agents"
+ },
+ {
+ "updated": "2013-06-27T10:00:00-00:00",
+ "name": "Multi Provider Network",
+ "links": [],
+ "alias": "multi-provider",
+ "description": "Expose mapping of virtual networks to"
+ " multiple physical networks"
+ },
+ {
+ "updated": "2013-01-14T10:00:00-00:00",
+ "name": "Neutron external network",
+ "links": [],
+ "alias": "external-net",
+ "description": "Adds external network attribute to network"
+ " resource."
+ },
+ {
+ "updated": "2012-07-20T10:00:00-00:00",
+ "name": "Neutron L3 Router",
+ "links": [],
+ "alias": "router",
+ "description": "Router abstraction for basic L3 forwarding"
+ " between L2 Neutron networks and access to external"
+ " networks via a NAT gateway."
+ },
+ {
+ "updated": "2013-07-23T10:00:00-00:00",
+ "name": "Allowed Address Pairs",
+ "links": [],
+ "alias": "allowed-address-pairs",
+ "description": "Provides allowed address pairs"
+ },
+ {
+ "updated": "2013-03-17T12:00:00-00:00",
+ "name": "Neutron Extra DHCP opts",
+ "links": [],
+ "alias": "extra_dhcp_opt",
+ "description": "Extra options configuration for DHCP. For"
+ " example PXE boot options to DHCP clients can be specified"
+ " (e.g. tftp-server, server-ip-address, bootfile-name)"
+ },
+ {
+ "updated": "2012-10-07T10:00:00-00:00",
+ "name": "LoadBalancing service",
+ "links": [],
+ "alias": "lbaas",
+ "description": "Extension for LoadBalancing service"
+ },
+ {
+ "updated": "2013-02-01T10:00:00-00:00",
+ "name": "Neutron Extra Route",
+ "links": [],
+ "alias": "extraroute",
+ "description": "Extra routes configuration for L3 router"
+ },
+ {
+ "updated": "2016-01-24T10:00:00-00:00",
+ "name": "Neutron Port Data Plane Status",
+ "links": [],
+ "alias": "data-plane-status",
+ "description": "Status of the underlying data plane."
+ }
+ ]
+ }
+
+ FAKE_EXTENSION_ALIAS = "service-type"
+
+ def setUp(self):
+ super(TestExtensionsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.extensions_client = extensions_client.ExtensionsClient(
+ fake_auth, "network", "regionOne")
+
+ def _test_list_extensions(self, bytes_body=False):
+ self.check_service_client_function(
+ self.extensions_client.list_extensions,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_EXTENSIONS,
+ bytes_body,
+ 200)
+
+ def _test_show_extension(self, bytes_body=False):
+ self.check_service_client_function(
+ self.extensions_client.show_extension,
+ "tempest.lib.common.rest_client.RestClient.get",
+ {"extension": self.FAKE_EXTENSIONS["extensions"][0]},
+ bytes_body,
+ 200,
+ ext_alias=self.FAKE_EXTENSION_ALIAS)
+
+ def test_list_extensions_with_str_body(self):
+ self._test_list_extensions()
+
+ def test_list_extensions_with_bytes_body(self):
+ self._test_list_extensions(bytes_body=True)
+
+ def test_show_extension_with_str_body(self):
+ self._test_show_extension()
+
+ def test_show_extension_with_bytes_body(self):
+ self._test_show_extension(bytes_body=True)
diff --git a/tempest/tests/lib/services/network/test_floating_ips_client.py b/tempest/tests/lib/services/network/test_floating_ips_client.py
new file mode 100644
index 0000000..c5b1845
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_floating_ips_client.py
@@ -0,0 +1,145 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from tempest.lib.services.network import floating_ips_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestFloatingIPsClient(base.BaseServiceTest):
+
+ FAKE_FLOATING_IPS = {
+ "floatingips": [
+ {
+ "router_id": "d23abc8d-2991-4a55-ba98-2aaea84cc72f",
+ "description": "for test",
+ "created_at": "2016-12-21T10:55:50Z",
+ "updated_at": "2016-12-21T10:55:53Z",
+ "revision_number": 1,
+ "project_id": "4969c491a3c74ee4af974e6d800c62de",
+ "tenant_id": "4969c491a3c74ee4af974e6d800c62de",
+ "floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57",
+ "fixed_ip_address": "10.0.0.3",
+ "floating_ip_address": "172.24.4.228",
+ "port_id": "ce705c24-c1ef-408a-bda3-7bbd946164ab",
+ "id": "2f245a7b-796b-4f26-9cf9-9e82d248fda7",
+ "status": "ACTIVE"
+ },
+ {
+ "router_id": None,
+ "description": "for test",
+ "created_at": "2016-12-21T11:55:50Z",
+ "updated_at": "2016-12-21T11:55:53Z",
+ "revision_number": 2,
+ "project_id": "4969c491a3c74ee4af974e6d800c62de",
+ "tenant_id": "4969c491a3c74ee4af974e6d800c62de",
+ "floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57",
+ "fixed_ip_address": None,
+ "floating_ip_address": "172.24.4.227",
+ "port_id": None,
+ "id": "61cea855-49cb-4846-997d-801b70c71bdd",
+ "status": "DOWN"
+ }
+ ]
+ }
+
+ FAKE_FLOATING_IP_ID = "2f245a7b-796b-4f26-9cf9-9e82d248fda7"
+
+ def setUp(self):
+ super(TestFloatingIPsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.floating_ips_client = floating_ips_client.FloatingIPsClient(
+ fake_auth, "compute", "regionOne")
+
+ def _test_list_floatingips(self, bytes_body=False):
+ self.check_service_client_function(
+ self.floating_ips_client.list_floatingips,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_FLOATING_IPS,
+ bytes_body,
+ 200)
+
+ def _test_create_floatingip(self, bytes_body=False):
+ self.check_service_client_function(
+ self.floating_ips_client.create_floatingip,
+ "tempest.lib.common.rest_client.RestClient.post",
+ {"floatingip": self.FAKE_FLOATING_IPS["floatingips"][1]},
+ bytes_body,
+ 201,
+ floating_network_id="172.24.4.228")
+
+ def _test_show_floatingip(self, bytes_body=False):
+ self.check_service_client_function(
+ self.floating_ips_client.show_floatingip,
+ "tempest.lib.common.rest_client.RestClient.get",
+ {"floatingip": self.FAKE_FLOATING_IPS["floatingips"][0]},
+ bytes_body,
+ 200,
+ floatingip_id=self.FAKE_FLOATING_IP_ID)
+
+ def _test_update_floatingip(self, bytes_body=False):
+ update_kwargs = {
+ "port_id": "fc861431-0e6c-4842-a0ed-e2363f9bc3a8"
+ }
+
+ resp_body = {
+ "floatingip": copy.deepcopy(
+ self.FAKE_FLOATING_IPS["floatingips"][0]
+ )
+ }
+ resp_body["floatingip"].update(update_kwargs)
+
+ self.check_service_client_function(
+ self.floating_ips_client.update_floatingip,
+ "tempest.lib.common.rest_client.RestClient.put",
+ resp_body,
+ bytes_body,
+ 200,
+ floatingip_id=self.FAKE_FLOATING_IP_ID,
+ **update_kwargs)
+
+ def test_list_floatingips_with_str_body(self):
+ self._test_list_floatingips()
+
+ def test_list_floatingips_with_bytes_body(self):
+ self._test_list_floatingips(bytes_body=True)
+
+ def test_create_floatingip_with_str_body(self):
+ self._test_create_floatingip()
+
+ def test_create_floatingip_with_bytes_body(self):
+ self._test_create_floatingip(bytes_body=True)
+
+ def test_show_floatingips_with_str_body(self):
+ self._test_show_floatingip()
+
+ def test_show_floatingips_with_bytes_body(self):
+ self._test_show_floatingip(bytes_body=True)
+
+ def test_update_floatingip_with_str_body(self):
+ self._test_update_floatingip()
+
+ def test_update_floatingip_with_bytes_body(self):
+ self._test_update_floatingip(bytes_body=True)
+
+ def test_delete_floatingip(self):
+ self.check_service_client_function(
+ self.floating_ips_client.delete_floatingip,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ status=204,
+ floatingip_id=self.FAKE_FLOATING_IP_ID)
diff --git a/tempest/tests/lib/services/network/test_metering_label_rules_client.py b/tempest/tests/lib/services/network/test_metering_label_rules_client.py
new file mode 100644
index 0000000..047c34f
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_metering_label_rules_client.py
@@ -0,0 +1,110 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.network import metering_label_rules_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestMeteringLabelRulesClient(base.BaseServiceTest):
+
+ FAKE_METERING_LABEL_RULES = {
+ "metering_label_rules": [
+ {
+ "remote_ip_prefix": "20.0.0.0/24",
+ "direction": "ingress",
+ "metering_label_id": "e131d186-b02d-4c0b-83d5-0c0725c4f812",
+ "id": "9536641a-7d14-4dc5-afaf-93a973ce0eb8",
+ "excluded": False
+ },
+ {
+ "remote_ip_prefix": "10.0.0.0/24",
+ "direction": "ingress",
+ "metering_label_id": "e131d186-b02d-4c0b-83d5-0c0725c4f812",
+ "id": "ffc6fd15-40de-4e7d-b617-34d3f7a93aec",
+ "excluded": False
+ }
+ ]
+ }
+
+ FAKE_METERING_LABEL_RULE = {
+ "remote_ip_prefix": "20.0.0.0/24",
+ "direction": "ingress",
+ "metering_label_id": "e131d186-b02d-4c0b-83d5-0c0725c4f812"
+ }
+
+ FAKE_METERING_LABEL_ID = "e131d186-b02d-4c0b-83d5-0c0725c4f812"
+ FAKE_METERING_LABEL_RULE_ID = "9536641a-7d14-4dc5-afaf-93a973ce0eb8"
+
+ def setUp(self):
+ super(TestMeteringLabelRulesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.metering_label_rules_client = \
+ metering_label_rules_client.MeteringLabelRulesClient(
+ fake_auth, "network", "regionOne")
+
+ def _test_list_metering_label_rules(self, bytes_body=False):
+ self.check_service_client_function(
+ self.metering_label_rules_client.list_metering_label_rules,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_METERING_LABEL_RULES,
+ bytes_body,
+ 200)
+
+ def _test_create_metering_label_rule(self, bytes_body=False):
+ self.check_service_client_function(
+ self.metering_label_rules_client.create_metering_label_rule,
+ "tempest.lib.common.rest_client.RestClient.post",
+ {"metering_label_rule": self.FAKE_METERING_LABEL_RULES[
+ "metering_label_rules"][0]},
+ bytes_body,
+ 201,
+ **self.FAKE_METERING_LABEL_RULE)
+
+ def _test_show_metering_label_rule(self, bytes_body=False):
+ self.check_service_client_function(
+ self.metering_label_rules_client.show_metering_label_rule,
+ "tempest.lib.common.rest_client.RestClient.get",
+ {"metering_label_rule": self.FAKE_METERING_LABEL_RULES[
+ "metering_label_rules"][0]},
+ bytes_body,
+ 200,
+ metering_label_rule_id=self.FAKE_METERING_LABEL_RULE_ID)
+
+ def test_delete_metering_label_rule(self):
+ self.check_service_client_function(
+ self.metering_label_rules_client.delete_metering_label_rule,
+ "tempest.lib.common.rest_client.RestClient.delete",
+ {},
+ status=204,
+ metering_label_rule_id=self.FAKE_METERING_LABEL_RULE_ID)
+
+ def test_list_metering_label_rules_with_str_body(self):
+ self._test_list_metering_label_rules()
+
+ def test_list_metering_label_rules_with_bytes_body(self):
+ self._test_list_metering_label_rules(bytes_body=True)
+
+ def test_create_metering_label_rule_with_str_body(self):
+ self._test_create_metering_label_rule()
+
+ def test_create_metering_label_rule_with_bytes_body(self):
+ self._test_create_metering_label_rule(bytes_body=True)
+
+ def test_show_metering_label_rule_with_str_body(self):
+ self._test_show_metering_label_rule()
+
+ def test_show_metering_label_rule_with_bytes_body(self):
+ self._test_show_metering_label_rule(bytes_body=True)
diff --git a/tempest/tests/lib/services/network/test_metering_labels_client.py b/tempest/tests/lib/services/network/test_metering_labels_client.py
new file mode 100644
index 0000000..a048326
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_metering_labels_client.py
@@ -0,0 +1,107 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.network import metering_labels_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestMeteringLabelsClient(base.BaseServiceTest):
+
+ FAKE_METERING_LABELS = {
+ "metering_labels": [
+ {
+ "project_id": "45345b0ee1ea477fac0f541b2cb79cd4",
+ "tenant_id": "45345b0ee1ea477fac0f541b2cb79cd4",
+ "description": "label1 description",
+ "name": "label1",
+ "id": "a6700594-5b7a-4105-8bfe-723b346ce866",
+ "shared": False
+ },
+ {
+ "project_id": "45345b0ee1ea477fac0f541b2cb79cd4",
+ "tenant_id": "45345b0ee1ea477fac0f541b2cb79cd4",
+ "description": "label2 description",
+ "name": "label2",
+ "id": "e131d186-b02d-4c0b-83d5-0c0725c4f812",
+ "shared": False
+ }
+ ]
+ }
+
+ FAKE_METERING_LABEL_ID = "a6700594-5b7a-4105-8bfe-723b346ce866"
+
+ def setUp(self):
+ super(TestMeteringLabelsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.metering_labels_client = \
+ metering_labels_client.MeteringLabelsClient(
+ fake_auth, "network", "regionOne")
+
+ def _test_list_metering_labels(self, bytes_body=False):
+ self.check_service_client_function(
+ self.metering_labels_client.list_metering_labels,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_METERING_LABELS,
+ bytes_body,
+ 200)
+
+ def _test_create_metering_label(self, bytes_body=False):
+ self.check_service_client_function(
+ self.metering_labels_client.create_metering_label,
+ "tempest.lib.common.rest_client.RestClient.post",
+ {"metering_label": self.FAKE_METERING_LABELS[
+ "metering_labels"][1]},
+ bytes_body,
+ 201,
+ name="label1",
+ description="label1 description",
+ shared=False)
+
+ def _test_show_metering_label(self, bytes_body=False):
+ self.check_service_client_function(
+ self.metering_labels_client.show_metering_label,
+ "tempest.lib.common.rest_client.RestClient.get",
+ {"metering_label": self.FAKE_METERING_LABELS[
+ "metering_labels"][0]},
+ bytes_body,
+ 200,
+ metering_label_id=self.FAKE_METERING_LABEL_ID)
+
+ def test_delete_metering_label(self):
+ self.check_service_client_function(
+ self.metering_labels_client.delete_metering_label,
+ "tempest.lib.common.rest_client.RestClient.delete",
+ {},
+ status=204,
+ metering_label_id=self.FAKE_METERING_LABEL_ID)
+
+ def test_list_metering_labels_with_str_body(self):
+ self._test_list_metering_labels()
+
+ def test_list_metering_labels_with_bytes_body(self):
+ self._test_list_metering_labels(bytes_body=True)
+
+ def test_create_metering_label_with_str_body(self):
+ self._test_create_metering_label()
+
+ def test_create_metering_label_with_bytes_body(self):
+ self._test_create_metering_label(bytes_body=True)
+
+ def test_show_metering_label_with_str_body(self):
+ self._test_show_metering_label()
+
+ def test_show_metering_label_with_bytes_body(self):
+ self._test_show_metering_label(bytes_body=True)
diff --git a/tempest/tests/lib/services/network/test_ports_client.py b/tempest/tests/lib/services/network/test_ports_client.py
new file mode 100644
index 0000000..20ef3f1
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_ports_client.py
@@ -0,0 +1,198 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from tempest.lib.services.network import ports_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestPortsClient(base.BaseServiceTest):
+
+ FAKE_PORTS = {
+ "ports": [
+ {
+ "admin_state_up": True,
+ "allowed_address_pairs": [],
+ "data_plane_status": None,
+ "description": "",
+ "device_id": "9ae135f4-b6e0-4dad-9e91-3c223e385824",
+ "device_owner": "network:router_gateway",
+ "extra_dhcp_opts": [],
+ "fixed_ips": [
+ {
+ "ip_address": "172.24.4.2",
+ "subnet_id": "008ba151-0b8c-4a67-98b5-0d2b87666062"
+ }
+ ],
+ "id": "d80b1a3b-4fc1-49f3-952e-1e2ab7081d8b",
+ "mac_address": "fa:16:3e:58:42:ed",
+ "name": "",
+ "network_id": "70c1db1f-b701-45bd-96e0-a313ee3430b3",
+ "project_id": "",
+ "security_groups": [],
+ "status": "ACTIVE",
+ "tenant_id": ""
+ },
+ {
+ "admin_state_up": True,
+ "allowed_address_pairs": [],
+ "data_plane_status": None,
+ "description": "",
+ "device_id": "9ae135f4-b6e0-4dad-9e91-3c223e385824",
+ "device_owner": "network:router_interface",
+ "extra_dhcp_opts": [],
+ "fixed_ips": [
+ {
+ "ip_address": "10.0.0.1",
+ "subnet_id": "288bf4a1-51ba-43b6-9d0a-520e9005db17"
+ }
+ ],
+ "id": "f71a6703-d6de-4be1-a91a-a570ede1d159",
+ "mac_address": "fa:16:3e:bb:3c:e4",
+ "name": "",
+ "network_id": "f27aa545-cbdd-4907-b0c6-c9e8b039dcc2",
+ "project_id": "d397de8a63f341818f198abb0966f6f3",
+ "security_groups": [],
+ "status": "ACTIVE",
+ "tenant_id": "d397de8a63f341818f198abb0966f6f3"
+ }
+ ]
+ }
+
+ FAKE_PORT_ID = "d80b1a3b-4fc1-49f3-952e-1e2ab7081d8b"
+
+ FAKE_PORT1 = {
+ "admin_state_up": True,
+ "name": "",
+ "network_id": "70c1db1f-b701-45bd-96e0-a313ee3430b3"
+ }
+
+ FAKE_PORT2 = {
+ "admin_state_up": True,
+ "name": "",
+ "network_id": "f27aa545-cbdd-4907-b0c6-c9e8b039dcc2"
+ }
+
+ FAKE_PORTS_REQ = {
+ "ports": [
+ FAKE_PORT1,
+ FAKE_PORT2
+ ]
+ }
+
+ def setUp(self):
+ super(TestPortsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.ports_client = ports_client.PortsClient(
+ fake_auth, "network", "regionOne")
+
+ def _test_list_ports(self, bytes_body=False):
+ self.check_service_client_function(
+ self.ports_client.list_ports,
+ "tempest.lib.common.rest_client.RestClient.get",
+ self.FAKE_PORTS,
+ bytes_body,
+ 200)
+
+ def _test_create_port(self, bytes_body=False):
+ self.check_service_client_function(
+ self.ports_client.create_port,
+ "tempest.lib.common.rest_client.RestClient.post",
+ {"port": self.FAKE_PORTS["ports"][0]},
+ bytes_body,
+ 201,
+ **self.FAKE_PORT1)
+
+ def _test_create_bulk_ports(self, bytes_body=False):
+ self.check_service_client_function(
+ self.ports_client.create_bulk_ports,
+ "tempest.lib.common.rest_client.RestClient.post",
+ self.FAKE_PORTS,
+ bytes_body,
+ 201,
+ ports=self.FAKE_PORTS_REQ)
+
+ def _test_show_port(self, bytes_body=False):
+ self.check_service_client_function(
+ self.ports_client.show_port,
+ "tempest.lib.common.rest_client.RestClient.get",
+ {"port": self.FAKE_PORTS["ports"][0]},
+ bytes_body,
+ 200,
+ port_id=self.FAKE_PORT_ID)
+
+ def _test_update_port(self, bytes_body=False):
+ update_kwargs = {
+ "admin_state_up": True,
+ "device_id": "d90a13da-be41-461f-9f99-1dbcf438fdf2",
+ "device_owner": "compute:nova",
+ "name": "test-for-port-update"
+ }
+
+ resp_body = {
+ "port": copy.deepcopy(
+ self.FAKE_PORTS["ports"][0]
+ )
+ }
+ resp_body["port"].update(update_kwargs)
+
+ self.check_service_client_function(
+ self.ports_client.update_port,
+ "tempest.lib.common.rest_client.RestClient.put",
+ resp_body,
+ bytes_body,
+ 200,
+ port_id=self.FAKE_PORT_ID,
+ **update_kwargs)
+
+ def test_delete_port(self):
+ self.check_service_client_function(
+ self.ports_client.delete_port,
+ "tempest.lib.common.rest_client.RestClient.delete",
+ {},
+ status=204,
+ port_id=self.FAKE_PORT_ID)
+
+ def test_list_ports_with_str_body(self):
+ self._test_list_ports()
+
+ def test_list_ports_with_bytes_body(self):
+ self._test_list_ports(bytes_body=True)
+
+ def test_create_port_with_str_body(self):
+ self._test_create_port()
+
+ def test_create_port_with_bytes_body(self):
+ self._test_create_port(bytes_body=True)
+
+ def test_create_bulk_port_with_str_body(self):
+ self._test_create_bulk_ports()
+
+ def test_create_bulk_port_with_bytes_body(self):
+ self._test_create_bulk_ports(bytes_body=True)
+
+ def test_show_port_with_str_body(self):
+ self._test_show_port()
+
+ def test_show_port_with_bytes_body(self):
+ self._test_show_port(bytes_body=True)
+
+ def test_update_port_with_str_body(self):
+ self._test_update_port()
+
+ def test_update_port_with_bytes_body(self):
+ self._test_update_port(bytes_body=True)
diff --git a/tempest/tests/lib/services/network/test_security_group_rules_client.py b/tempest/tests/lib/services/network/test_security_group_rules_client.py
new file mode 100644
index 0000000..ebffcbe
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_security_group_rules_client.py
@@ -0,0 +1,130 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.services.network import security_group_rules_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestSecurityGroupsClient(base.BaseServiceTest):
+
+ FAKE_SEC_GROUP_RULE_ID = "3c0e45ff-adaf-4124-b083-bf390e5482ff"
+
+ FAKE_SECURITY_GROUP_RULES = {
+ "security_group_rules": [
+ {
+ "direction": "egress",
+ "ethertype": "IPv6",
+ "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff",
+ "port_range_max": None,
+ "port_range_min": None,
+ "protocol": None,
+ "remote_group_id": None,
+ "remote_ip_prefix": None,
+ "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5",
+ "project_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "description": ""
+ },
+ {
+ "direction": "egress",
+ "ethertype": "IPv4",
+ "id": "93aa42e5-80db-4581-9391-3a608bd0e448",
+ "port_range_max": None,
+ "port_range_min": None,
+ "protocol": None,
+ "remote_group_id": None,
+ "remote_ip_prefix": None,
+ "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5",
+ "project_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "description": ""
+ }
+ ]
+ }
+
+ FAKE_SECURITY_GROUP_RULE = copy.copy(
+ FAKE_SECURITY_GROUP_RULES['security_group_rules'][0])
+
+ def setUp(self):
+ super(TestSecurityGroupsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = security_group_rules_client.SecurityGroupRulesClient(
+ fake_auth, 'network', 'regionOne')
+
+ def _test_list_security_group_rules(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_security_group_rules,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SECURITY_GROUP_RULES,
+ bytes_body,
+ mock_args='v2.0/security-group-rules')
+
+ def _test_create_security_group_rule(self, bytes_body=False):
+ kwargs = {'direction': 'egress',
+ 'security_group_id': '85cc3048-abc3-43cc-89b3-377341426ac5',
+ 'remote_ip_prefix': None}
+
+ self.check_service_client_function(
+ self.client.create_security_group_rule,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_SECURITY_GROUP_RULE,
+ bytes_body,
+ status=201,
+ mock_args=['v2.0/security-group-rules',
+ json.dumps({"security_group_rule": kwargs})],
+ **kwargs)
+
+ def _test_show_security_group_rule(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_security_group_rule,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SECURITY_GROUP_RULE,
+ bytes_body,
+ security_group_rule_id=self.FAKE_SEC_GROUP_RULE_ID,
+ mock_args='v2.0/security-group-rules/%s'
+ % self.FAKE_SEC_GROUP_RULE_ID)
+
+ def test_list_security_group_rules_with_str_body(self):
+ self._test_list_security_group_rules()
+
+ def test_list_security_group_rules_with_bytes_body(self):
+ self._test_list_security_group_rules(bytes_body=True)
+
+ def test_create_security_group_rule_with_str_body(self):
+ self._test_create_security_group_rule()
+
+ def test_create_security_group_rule_with_bytes_body(self):
+ self._test_create_security_group_rule(bytes_body=True)
+
+ def test_show_security_group_rule_with_str_body(self):
+ self._test_show_security_group_rule()
+
+ def test_show_security_group_rule_with_bytes_body(self):
+ self._test_show_security_group_rule(bytes_body=True)
+
+ def test_delete_security_group_rule(self):
+ self.check_service_client_function(
+ self.client.delete_security_group_rule,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ status=204,
+ security_group_rule_id=self.FAKE_SEC_GROUP_RULE_ID,
+ mock_args='v2.0/security-group-rules/%s'
+ % self.FAKE_SEC_GROUP_RULE_ID)
diff --git a/tempest/tests/lib/services/network/test_security_groups_client.py b/tempest/tests/lib/services/network/test_security_groups_client.py
new file mode 100644
index 0000000..d066378
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_security_groups_client.py
@@ -0,0 +1,157 @@
+# Copyright 2017 AT&T Corporation.
+# All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import copy
+
+from oslo_serialization import jsonutils as json
+
+from tempest.lib.services.network import security_groups_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestSecurityGroupsClient(base.BaseServiceTest):
+
+ FAKE_SEC_GROUP_ID = "85cc3048-abc3-43cc-89b3-377341426ac5"
+
+ FAKE_SECURITY_GROUPS = {
+ "security_groups": [
+ {
+ "description": "default",
+ "id": FAKE_SEC_GROUP_ID,
+ "name": "fake-security-group-name",
+ "security_group_rules": [
+ {
+ "direction": "egress",
+ "ethertype": "IPv4",
+ "id": "38ce2d8e-e8f1-48bd-83c2-d33cb9f50c3d",
+ "port_range_max": None,
+ "port_range_min": None,
+ "protocol": None,
+ "remote_group_id": None,
+ "remote_ip_prefix": None,
+ "security_group_id": FAKE_SEC_GROUP_ID,
+ "project_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "description": ""
+ },
+ {
+ "direction": "egress",
+ "ethertype": "IPv6",
+ "id": "565b9502-12de-4ffd-91e9-68885cff6ae1",
+ "port_range_max": None,
+ "port_range_min": None,
+ "protocol": None,
+ "remote_group_id": None,
+ "remote_ip_prefix": None,
+ "security_group_id": FAKE_SEC_GROUP_ID,
+ "project_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "description": ""
+ }
+ ],
+ "project_id": "e4f50856753b4dc6afee5fa6b9b6c550",
+ "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550"
+ }
+ ]
+ }
+
+ FAKE_SECURITY_GROUP = {
+ "security_group": copy.deepcopy(
+ FAKE_SECURITY_GROUPS["security_groups"][0])
+ }
+
+ def setUp(self):
+ super(TestSecurityGroupsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = security_groups_client.SecurityGroupsClient(
+ fake_auth, 'network', 'regionOne')
+
+ def _test_list_security_groups(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_security_groups,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SECURITY_GROUPS,
+ bytes_body,
+ mock_args='v2.0/security-groups')
+
+ def _test_create_security_group(self, bytes_body=False):
+ kwargs = {'name': 'fake-security-group-name'}
+ self.check_service_client_function(
+ self.client.create_security_group,
+ 'tempest.lib.common.rest_client.RestClient.post',
+ self.FAKE_SECURITY_GROUP,
+ bytes_body,
+ status=201,
+ mock_args=['v2.0/security-groups',
+ json.dumps({"security_group": kwargs})],
+ **kwargs)
+
+ def _test_show_security_group(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_security_group,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_SECURITY_GROUP,
+ bytes_body,
+ security_group_id=self.FAKE_SEC_GROUP_ID,
+ mock_args='v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID)
+
+ def _test_update_security_group(self, bytes_body=False):
+ kwargs = {'name': 'updated-security-group-name'}
+ resp_body = copy.deepcopy(self.FAKE_SECURITY_GROUP)
+ resp_body["security_group"]["name"] = 'updated-security-group-name'
+
+ self.check_service_client_function(
+ self.client.update_security_group,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ resp_body,
+ bytes_body,
+ security_group_id=self.FAKE_SEC_GROUP_ID,
+ mock_args=['v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID,
+ json.dumps({'security_group': kwargs})],
+ **kwargs)
+
+ def test_list_security_groups_with_str_body(self):
+ self._test_list_security_groups()
+
+ def test_list_security_groups_with_bytes_body(self):
+ self._test_list_security_groups(bytes_body=True)
+
+ def test_create_security_group_with_str_body(self):
+ self._test_create_security_group()
+
+ def test_create_security_group_with_bytes_body(self):
+ self._test_create_security_group(bytes_body=True)
+
+ def test_show_security_group_with_str_body(self):
+ self._test_show_security_group()
+
+ def test_show_security_group_with_bytes_body(self):
+ self._test_show_security_group(bytes_body=True)
+
+ def test_update_security_group_with_str_body(self):
+ self._test_update_security_group()
+
+ def test_update_security_group_with_bytes_body(self):
+ self._test_update_security_group(bytes_body=True)
+
+ def test_delete_security_group(self):
+ self.check_service_client_function(
+ self.client.delete_security_group,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ status=204,
+ security_group_id=self.FAKE_SEC_GROUP_ID,
+ mock_args='v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID)
diff --git a/tempest/tests/lib/services/network/test_tags_client.py b/tempest/tests/lib/services/network/test_tags_client.py
new file mode 100644
index 0000000..dbe50a0
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_tags_client.py
@@ -0,0 +1,123 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+
+from tempest.lib.services.network import tags_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestTagsClient(base.BaseServiceTest):
+
+ FAKE_TAGS = {
+ "tags": [
+ "red",
+ "blue"
+ ]
+ }
+
+ FAKE_RESOURCE_TYPE = 'network'
+
+ FAKE_RESOURCE_ID = '7a8f904b-c1ed-4446-a87d-60440c02934b'
+
+ def setUp(self):
+ super(TestTagsClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = tags_client.TagsClient(
+ fake_auth, 'network', 'regionOne')
+
+ def _test_update_all_tags(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.update_all_tags,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ self.FAKE_TAGS,
+ bytes_body,
+ resource_type=self.FAKE_RESOURCE_TYPE,
+ resource_id=self.FAKE_RESOURCE_ID,
+ tags=self.FAKE_TAGS)
+
+ def _test_check_tag_existence(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.check_tag_existence,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ {},
+ bytes_body,
+ resource_type=self.FAKE_RESOURCE_TYPE,
+ resource_id=self.FAKE_RESOURCE_ID,
+ tag=self.FAKE_TAGS['tags'][0],
+ status=204)
+
+ def _test_create_tag(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.create_tag,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ {},
+ bytes_body,
+ resource_type=self.FAKE_RESOURCE_TYPE,
+ resource_id=self.FAKE_RESOURCE_ID,
+ tag=self.FAKE_TAGS['tags'][0],
+ status=201)
+
+ def _test_list_tags(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.list_tags,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_TAGS,
+ bytes_body,
+ resource_type=self.FAKE_RESOURCE_TYPE,
+ resource_id=self.FAKE_RESOURCE_ID)
+
+ def test_update_all_tags_with_str_body(self):
+ self._test_update_all_tags()
+
+ def test_update_all_tags_with_bytes_body(self):
+ self._test_update_all_tags(bytes_body=True)
+
+ def test_delete_all_tags(self):
+ self.check_service_client_function(
+ self.client.delete_all_tags,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ resource_type=self.FAKE_RESOURCE_TYPE,
+ resource_id=self.FAKE_RESOURCE_ID,
+ status=204)
+
+ def test_check_tag_existence_with_str_body(self):
+ self._test_check_tag_existence()
+
+ def test_check_tag_existence_with_bytes_body(self):
+ self._test_check_tag_existence(bytes_body=True)
+
+ def test_create_tag_with_str_body(self):
+ self._test_create_tag()
+
+ def test_create_tag_with_bytes_body(self):
+ self._test_create_tag(bytes_body=True)
+
+ def test_list_tags_with_str_body(self):
+ self._test_list_tags()
+
+ def test_list_tags_with_bytes_body(self):
+ self._test_list_tags(bytes_body=True)
+
+ def test_delete_tag(self):
+ self.check_service_client_function(
+ self.client.delete_tag,
+ 'tempest.lib.common.rest_client.RestClient.delete',
+ {},
+ resource_type=self.FAKE_RESOURCE_TYPE,
+ resource_id=self.FAKE_RESOURCE_ID,
+ tag=self.FAKE_TAGS['tags'][0],
+ status=204)
diff --git a/tempest/tests/lib/services/volume/v2/test_capabilities_client.py b/tempest/tests/lib/services/volume/v2/test_capabilities_client.py
new file mode 100644
index 0000000..3d3f1e1
--- /dev/null
+++ b/tempest/tests/lib/services/volume/v2/test_capabilities_client.py
@@ -0,0 +1,77 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.services.volume.v2 import capabilities_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestCapabilitiesClient(base.BaseServiceTest):
+
+ FAKE_BACKEND_CAPABILITIES = {
+ "namespace": "OS::Storage::Capabilities::fake",
+ "vendor_name": "OpenStack",
+ "volume_backend_name": "lvmdriver-1",
+ "pool_name": "pool",
+ "driver_version": "2.0.0",
+ "storage_protocol": "iSCSI",
+ "display_name": "Capabilities of Cinder LVM driver",
+ "description": (
+ "These are volume type options provided by Cinder LVM driver."),
+ "visibility": "public",
+ "replication_targets": [],
+ "properties": {
+ "compression": {
+ "title": "Compression",
+ "description": "Enables compression.",
+ "type": "boolean"
+ },
+ "qos": {
+ "title": "QoS",
+ "description": "Enables QoS.",
+ "type": "boolean"
+ },
+ "replication": {
+ "title": "Replication",
+ "description": "Enables replication.",
+ "type": "boolean"
+ },
+ "thin_provisioning": {
+ "title": "Thin Provisioning",
+ "description": "Sets thin provisioning.",
+ "type": "boolean"
+ }
+ }
+ }
+
+ def setUp(self):
+ super(TestCapabilitiesClient, self).setUp()
+ fake_auth = fake_auth_provider.FakeAuthProvider()
+ self.client = capabilities_client.CapabilitiesClient(
+ fake_auth, 'volume', 'regionOne')
+
+ def _test_show_backend_capabilities(self, bytes_body=False):
+ self.check_service_client_function(
+ self.client.show_backend_capabilities,
+ 'tempest.lib.common.rest_client.RestClient.get',
+ self.FAKE_BACKEND_CAPABILITIES,
+ bytes_body,
+ host='lvmdriver-1')
+
+ def test_show_backend_capabilities_with_str_body(self):
+ self._test_show_backend_capabilities()
+
+ def test_show_backend_capabilities_with_bytes_body(self):
+ self._test_show_backend_capabilities(bytes_body=True)
diff --git a/test-requirements.txt b/test-requirements.txt
index fbdad44..19b45ea 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -5,7 +5,7 @@
# needed for doc build
sphinx!=1.6.1,>=1.5.1 # BSD
oslosphinx>=4.7.0 # Apache-2.0
-reno>=1.8.0 # Apache-2.0
+reno!=2.3.1,>=1.8.0 # Apache-2.0
mock>=2.0 # BSD
coverage!=4.4,>=4.0 # Apache-2.0
oslotest>=1.10.0 # Apache-2.0
diff --git a/tools/check_logs.py b/tools/check_logs.py
index f82b387..fc21f75 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -25,7 +25,6 @@
import six.moves.urllib.request as urlreq
import yaml
-
# DEVSTACK_GATE_GRENADE is either unset if grenade is not running
# or a string describing what type of grenade run to perform.
is_grenade = os.environ.get('DEVSTACK_GATE_GRENADE') is not None
@@ -137,7 +136,7 @@
with open(WHITELIST_FILE) as stream:
loaded = yaml.safe_load(stream)
if loaded:
- for (name, l) in loaded.iteritems():
+ for (name, l) in six.iteritems(loaded):
for w in l:
assert 'module' in w, 'no module in %s' % name
assert 'message' in w, 'no message in %s' % name
diff --git a/tools/find_stack_traces.py b/tools/find_stack_traces.py
index 2ba8b16..1f2b88b 100755
--- a/tools/find_stack_traces.py
+++ b/tools/find_stack_traces.py
@@ -126,8 +126,8 @@
def print_stats(items, fname, verbose=False):
- errors = len(filter(lambda x: x.level == "ERROR", items))
- traces = len(filter(lambda x: x.level == "TRACE", items))
+ errors = len([x for x in items if x.level == "ERROR"])
+ traces = len([x for x in items if x.level == "TRACE"])
print("%d ERRORS found in %s" % (errors, fname))
print("%d TRACES found in %s" % (traces, fname))
diff --git a/tools/generate-tempest-plugins-list.py b/tools/generate-tempest-plugins-list.py
index acb29af..a33962b 100644
--- a/tools/generate-tempest-plugins-list.py
+++ b/tools/generate-tempest-plugins-list.py
@@ -26,7 +26,12 @@
import json
import re
-import requests
+try:
+ # For Python 3.0 and later
+ import urllib
+except ImportError:
+ # Fall back to Python 2's urllib2
+ import urllib2 as urllib
url = 'https://review.openstack.org/projects/'
@@ -49,23 +54,31 @@
def has_tempest_plugin(proj):
- if proj.startswith('openstack/deb-'):
- return False
- r = requests.get(
- "https://git.openstack.org/cgit/%s/plain/setup.cfg" % proj)
+ try:
+ r = urllib.urlopen("https://git.openstack.org/cgit/%s/plain/setup.cfg"
+ % proj)
+ except urllib.HTTPError as err:
+ if err.code == 404:
+ return False
p = re.compile('^tempest\.test_plugins', re.M)
- if p.findall(r.text):
+ if p.findall(r.read()):
return True
else:
False
-r = requests.get(url)
+r = urllib.urlopen(url)
# Gerrit prepends 4 garbage octets to the JSON, in order to counter
# cross-site scripting attacks. Therefore we must discard it so the
# json library won't choke.
-projects = sorted(filter(is_in_openstack_namespace, json.loads(r.text[4:])))
+projects = sorted(filter(is_in_openstack_namespace, json.loads(r.read()[4:])))
-found_plugins = filter(has_tempest_plugin, projects)
+# Retrieve projects having no deb, ui or spec namespace as those namespaces
+# do not contains tempest plugins.
+projects_list = [i for i in projects if not (i.startswith('openstack/deb-') or
+ i.endswith('-ui') or
+ i.endswith('-specs'))]
+
+found_plugins = list(filter(has_tempest_plugin, projects_list))
# Every element of the found_plugins list begins with "openstack/".
# We drop those initial 10 octets when printing the list.