Merge "Reuse mocked body value between tests"
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage.py b/tempest/api/compute/admin/test_simple_tenant_usage.py
index 1c9e5d7..204281c 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage.py
@@ -50,7 +50,7 @@
def test_list_usage_all_tenants(self):
# Get usage for all tenants
tenant_usage = self.adm_client.list_tenant_usages(
- start=self.start, end=self.end, detailed=int(bool(True)))
+ start=self.start, end=self.end, detailed="1")
self.assertEqual(len(tenant_usage), 8)
@test.idempotent_id('94135049-a4c5-4934-ad39-08fa7da4f22e')
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
index 934fc31..e9b4ad4 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
@@ -66,6 +66,6 @@
# Get usage for all tenants with non admin user
params = {'start': self.start,
'end': self.end,
- 'detailed': int(bool(True))}
+ 'detailed': "1"}
self.assertRaises(lib_exc.Forbidden,
self.client.list_tenant_usages, **params)
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index cb113a7..63395cc 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -61,7 +61,7 @@
# Change quotas for tenant
quota_set = self.admin_client.update_quotas(tenant_id,
- **new_quotas)
+ **new_quotas)['quota']
self.addCleanup(self.admin_client.reset_quotas, tenant_id)
for key, value in six.iteritems(new_quotas):
self.assertEqual(value, quota_set[key])
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index 2c545a7..8015c35 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -38,6 +38,10 @@
cls.volume = cls.create_volume()
+ def _delete_backup(self, backup_id):
+ self.backups_adm_client.delete_backup(backup_id)
+ self.backups_adm_client.wait_for_backup_deletion(backup_id)
+
@test.idempotent_id('a66eb488-8ee1-47d4-8e9f-575a095728c6')
def test_volume_backup_create_get_detailed_list_restore_delete(self):
# Create backup
@@ -74,6 +78,52 @@
self.admin_volume_client.wait_for_volume_status(
restore['volume_id'], 'available')
+ @test.idempotent_id('a99c54a1-dd80-4724-8a13-13bf58d4068d')
+ def test_volume_backup_export_import(self):
+ # Create backup
+ backup_name = data_utils.rand_name('Backup')
+ backup = self.backups_adm_client.create_backup(self.volume['id'],
+ name=backup_name)
+ self.addCleanup(self._delete_backup, backup['id'])
+ self.assertEqual(backup_name, backup['name'])
+ self.backups_adm_client.wait_for_backup_status(backup['id'],
+ 'available')
+
+ # Export Backup
+ export_backup = self.backups_adm_client.export_backup(backup['id'])
+ self.assertIn('backup_service', export_backup)
+ self.assertIn('backup_url', export_backup)
+ self.assertTrue(export_backup['backup_service'].startswith(
+ 'cinder.backup.drivers'))
+ self.assertIsNotNone(export_backup['backup_url'])
+
+ # Import Backup
+ import_backup = self.backups_adm_client.import_backup(
+ backup_service=export_backup['backup_service'],
+ backup_url=export_backup['backup_url'])
+ self.addCleanup(self._delete_backup, import_backup['id'])
+ self.assertIn("id", import_backup)
+ self.backups_adm_client.wait_for_backup_status(import_backup['id'],
+ 'available')
+
+ # Verify Import Backup
+ backups = self.backups_adm_client.list_backups(detail=True)
+ self.assertIn(import_backup['id'], [b['id'] for b in backups])
+
+ # Restore backup
+ restore = self.backups_adm_client.restore_backup(import_backup['id'])
+ self.addCleanup(self.admin_volume_client.delete_volume,
+ restore['volume_id'])
+ self.assertEqual(import_backup['id'], restore['backup_id'])
+ self.admin_volume_client.wait_for_volume_status(restore['volume_id'],
+ 'available')
+
+ # Verify if restored volume is there in volume list
+ volumes = self.admin_volume_client.list_volumes()
+ self.assertIn(restore['volume_id'], [v['id'] for v in volumes])
+ self.backups_adm_client.wait_for_backup_status(import_backup['id'],
+ 'available')
+
class VolumesBackupsV1Test(VolumesBackupsV2Test):
_api_version = 1
diff --git a/tempest/api_schema/response/compute/v2_1/migrations.py b/tempest/api_schema/response/compute/v2_1/migrations.py
index 722372c..b7d66ea 100644
--- a/tempest/api_schema/response/compute/v2_1/migrations.py
+++ b/tempest/api_schema/response/compute/v2_1/migrations.py
@@ -23,15 +23,15 @@
'type': 'object',
'properties': {
'id': {'type': 'integer'},
- 'status': {'type': 'string'},
- 'instance_uuid': {'type': 'string'},
- 'source_node': {'type': 'string'},
- 'source_compute': {'type': 'string'},
- 'dest_node': {'type': 'string'},
- 'dest_compute': {'type': 'string'},
- 'dest_host': {'type': 'string'},
- 'old_instance_type_id': {'type': 'integer'},
- 'new_instance_type_id': {'type': 'integer'},
+ 'status': {'type': ['string', 'null']},
+ 'instance_uuid': {'type': ['string', 'null']},
+ 'source_node': {'type': ['string', 'null']},
+ 'source_compute': {'type': ['string', 'null']},
+ 'dest_node': {'type': ['string', 'null']},
+ 'dest_compute': {'type': ['string', 'null']},
+ 'dest_host': {'type': ['string', 'null']},
+ 'old_instance_type_id': {'type': ['integer', 'null']},
+ 'new_instance_type_id': {'type': ['integer', 'null']},
'created_at': {'type': 'string'},
'updated_at': {'type': ['string', 'null']}
},
diff --git a/tempest/common/accounts.py b/tempest/common/accounts.py
index 650faf1..78e0e72 100644
--- a/tempest/common/accounts.py
+++ b/tempest/common/accounts.py
@@ -31,8 +31,8 @@
def read_accounts_yaml(path):
- yaml_file = open(path, 'r')
- accounts = yaml.load(yaml_file)
+ with open(path, 'r') as yaml_file:
+ accounts = yaml.load(yaml_file)
return accounts
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 65f3aa7..ce200d2 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -39,46 +39,12 @@
version = '2.0'
uri_prefix = "v2.0"
- def get_uri(self, plural_name):
- # get service prefix from resource name
-
- # the following map is used to construct proper URI
- # for the given neutron resource
- service_resource_prefix_map = {
- 'networks': '',
- 'subnets': '',
- 'ports': '',
- 'metering_labels': 'metering',
- 'metering_label_rules': 'metering',
- }
- service_prefix = service_resource_prefix_map.get(
- plural_name)
- plural_name = plural_name.replace("_", "-")
- if service_prefix:
- uri = '%s/%s/%s' % (self.uri_prefix, service_prefix,
- plural_name)
- else:
- uri = '%s/%s' % (self.uri_prefix, plural_name)
- return uri
-
- def pluralize(self, resource_name):
- # get plural from map or just add 's'
-
- # map from resource name to a plural name
- # needed only for those which can't be constructed as name + 's'
- resource_plural_map = {
- 'security_groups': 'security_groups',
- 'security_group_rules': 'security_group_rules',
- 'quotas': 'quotas',
- }
- return resource_plural_map.get(resource_name, resource_name + 's')
-
def _list_resources(self, uri, **filters):
req_uri = self.uri_prefix + uri
if filters:
req_uri += '?' + urllib.urlencode(filters, doseq=1)
resp, body = self.get(req_uri)
- body = self.deserialize_list(body)
+ body = json.loads(body)
self.expected_success(200, resp.status)
return service_client.ResponseBody(resp, body)
@@ -96,23 +62,23 @@
if fields:
req_uri += '?' + urllib.urlencode(fields, doseq=1)
resp, body = self.get(req_uri)
- body = self.deserialize_single(body)
+ body = json.loads(body)
self.expected_success(200, resp.status)
return service_client.ResponseBody(resp, body)
def _create_resource(self, uri, post_data):
req_uri = self.uri_prefix + uri
- req_post_data = self.serialize(post_data)
+ req_post_data = json.dumps(post_data)
resp, body = self.post(req_uri, req_post_data)
- body = self.deserialize_single(body)
+ body = json.loads(body)
self.expected_success(201, resp.status)
return service_client.ResponseBody(resp, body)
def _update_resource(self, uri, post_data):
req_uri = self.uri_prefix + uri
- req_post_data = self.serialize(post_data)
+ req_post_data = json.dumps(post_data)
resp, body = self.put(req_uri, req_post_data)
- body = self.deserialize_single(body)
+ body = json.loads(body)
self.expected_success(200, resp.status)
return service_client.ResponseBody(resp, body)
@@ -285,34 +251,21 @@
uri = '/extensions'
return self._list_resources(uri, **filters)
- # Common methods that are hard to automate
def create_bulk_network(self, names):
network_list = [{'name': name} for name in names]
post_data = {'networks': network_list}
- body = self.serialize_list(post_data, "networks", "network")
- uri = self.get_uri("networks")
- resp, body = self.post(uri, body)
- body = self.deserialize_list(body)
- self.expected_success(201, resp.status)
- return service_client.ResponseBody(resp, body)
+ uri = '/networks'
+ return self._create_resource(uri, post_data)
def create_bulk_subnet(self, subnet_list):
post_data = {'subnets': subnet_list}
- body = self.serialize_list(post_data, 'subnets', 'subnet')
- uri = self.get_uri('subnets')
- resp, body = self.post(uri, body)
- body = self.deserialize_list(body)
- self.expected_success(201, resp.status)
- return service_client.ResponseBody(resp, body)
+ uri = '/subnets'
+ return self._create_resource(uri, post_data)
def create_bulk_port(self, port_list):
post_data = {'ports': port_list}
- body = self.serialize_list(post_data, 'ports', 'port')
- uri = self.get_uri('ports')
- resp, body = self.post(uri, body)
- body = self.deserialize_list(body)
- self.expected_success(201, resp.status)
- return service_client.ResponseBody(resp, body)
+ uri = '/ports'
+ return self._create_resource(uri, post_data)
def wait_for_resource_deletion(self, resource_type, id):
"""Waits for a resource to be deleted."""
@@ -371,32 +324,14 @@
message = '(%s) %s' % (caller, message)
raise exceptions.TimeoutException(message)
- def deserialize_single(self, body):
- return json.loads(body)
-
- def deserialize_list(self, body):
- return json.loads(body)
-
- def serialize(self, data):
- return json.dumps(data)
-
- def serialize_list(self, data, root=None, item=None):
- return self.serialize(data)
-
def update_quotas(self, tenant_id, **kwargs):
put_body = {'quota': kwargs}
- body = json.dumps(put_body)
- uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
- resp, body = self.put(uri, body)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body['quota'])
+ uri = '/quotas/%s' % tenant_id
+ return self._update_resource(uri, put_body)
def reset_quotas(self, tenant_id):
- uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
- resp, body = self.delete(uri)
- self.expected_success(204, resp.status)
- return service_client.ResponseBody(resp, body)
+ uri = '/quotas/%s' % tenant_id
+ return self._delete_resource(uri)
def show_quotas(self, tenant_id, **fields):
uri = '/quotas/%s' % tenant_id
@@ -410,18 +345,12 @@
post_body = {'router': kwargs}
post_body['router']['name'] = name
post_body['router']['admin_state_up'] = admin_state_up
- body = json.dumps(post_body)
- uri = '%s/routers' % (self.uri_prefix)
- resp, body = self.post(uri, body)
- self.expected_success(201, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ uri = '/routers'
+ return self._create_resource(uri, post_body)
def _update_router(self, router_id, set_enable_snat, **kwargs):
- uri = '%s/routers/%s' % (self.uri_prefix, router_id)
- resp, body = self.get(uri)
- self.expected_success(200, resp.status)
- body = json.loads(body)
+ uri = '/routers/%s' % router_id
+ body = self._show_resource(uri)
update_body = {}
update_body['name'] = kwargs.get('name', body['router']['name'])
update_body['admin_state_up'] = kwargs.get(
@@ -440,11 +369,7 @@
if 'distributed' in kwargs:
update_body['distributed'] = kwargs['distributed']
update_body = dict(router=update_body)
- update_body = json.dumps(update_body)
- resp, body = self.put(uri, update_body)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ return self._update_resource(uri, update_body)
def update_router(self, router_id, **kwargs):
"""Update a router leaving enable_snat to its default value."""
@@ -476,64 +401,37 @@
return self._update_router(router_id, set_enable_snat=True, **kwargs)
def add_router_interface_with_subnet_id(self, router_id, subnet_id):
- uri = '%s/routers/%s/add_router_interface' % (self.uri_prefix,
- router_id)
+ uri = '/routers/%s/add_router_interface' % router_id
update_body = {"subnet_id": subnet_id}
- update_body = json.dumps(update_body)
- resp, body = self.put(uri, update_body)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ return self._update_resource(uri, update_body)
def add_router_interface_with_port_id(self, router_id, port_id):
- uri = '%s/routers/%s/add_router_interface' % (self.uri_prefix,
- router_id)
+ uri = '/routers/%s/add_router_interface' % router_id
update_body = {"port_id": port_id}
- update_body = json.dumps(update_body)
- resp, body = self.put(uri, update_body)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ return self._update_resource(uri, update_body)
def remove_router_interface_with_subnet_id(self, router_id, subnet_id):
- uri = '%s/routers/%s/remove_router_interface' % (self.uri_prefix,
- router_id)
+ uri = '/routers/%s/remove_router_interface' % router_id
update_body = {"subnet_id": subnet_id}
- update_body = json.dumps(update_body)
- resp, body = self.put(uri, update_body)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ return self._update_resource(uri, update_body)
def remove_router_interface_with_port_id(self, router_id, port_id):
- uri = '%s/routers/%s/remove_router_interface' % (self.uri_prefix,
- router_id)
+ uri = '/routers/%s/remove_router_interface' % router_id
update_body = {"port_id": port_id}
- update_body = json.dumps(update_body)
- resp, body = self.put(uri, update_body)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ return self._update_resource(uri, update_body)
def list_router_interfaces(self, uuid):
- uri = '%s/ports?device_id=%s' % (self.uri_prefix, uuid)
- resp, body = self.get(uri)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ uri = '/ports?device_id=%s' % uuid
+ return self._list_resources(uri)
def update_agent(self, agent_id, agent_info):
"""
:param agent_info: Agent update information.
E.g {"admin_state_up": True}
"""
- uri = '%s/agents/%s' % (self.uri_prefix, agent_id)
+ uri = '/agents/%s' % agent_id
agent = {"agent": agent_info}
- body = json.dumps(agent)
- resp, body = self.put(uri, body)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ return self._update_resource(uri, agent)
def show_agent(self, agent_id, **fields):
uri = '/agents/%s' % agent_id
@@ -544,88 +442,54 @@
return self._list_resources(uri, **filters)
def list_routers_on_l3_agent(self, agent_id):
- uri = '%s/agents/%s/l3-routers' % (self.uri_prefix, agent_id)
- resp, body = self.get(uri)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ uri = '/agents/%s/l3-routers' % agent_id
+ return self._list_resources(uri)
def list_l3_agents_hosting_router(self, router_id):
- uri = '%s/routers/%s/l3-agents' % (self.uri_prefix, router_id)
- resp, body = self.get(uri)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ uri = '/routers/%s/l3-agents' % router_id
+ return self._list_resources(uri)
def add_router_to_l3_agent(self, agent_id, router_id):
- uri = '%s/agents/%s/l3-routers' % (self.uri_prefix, agent_id)
+ uri = '/agents/%s/l3-routers' % agent_id
post_body = {"router_id": router_id}
- body = json.dumps(post_body)
- resp, body = self.post(uri, body)
- self.expected_success(201, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ return self._create_resource(uri, post_body)
def remove_router_from_l3_agent(self, agent_id, router_id):
- uri = '%s/agents/%s/l3-routers/%s' % (
- self.uri_prefix, agent_id, router_id)
- resp, body = self.delete(uri)
- self.expected_success(204, resp.status)
- return service_client.ResponseBody(resp, body)
+ uri = '/agents/%s/l3-routers/%s' % (agent_id, router_id)
+ return self._delete_resource(uri)
def list_dhcp_agent_hosting_network(self, network_id):
- uri = '%s/networks/%s/dhcp-agents' % (self.uri_prefix, network_id)
- resp, body = self.get(uri)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ uri = '/networks/%s/dhcp-agents' % network_id
+ return self._list_resources(uri)
def list_networks_hosted_by_one_dhcp_agent(self, agent_id):
- uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
- resp, body = self.get(uri)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ uri = '/agents/%s/dhcp-networks' % agent_id
+ return self._list_resources(uri)
def remove_network_from_dhcp_agent(self, agent_id, network_id):
- uri = '%s/agents/%s/dhcp-networks/%s' % (self.uri_prefix, agent_id,
- network_id)
- resp, body = self.delete(uri)
- self.expected_success(204, resp.status)
- return service_client.ResponseBody(resp, body)
+ uri = '/agents/%s/dhcp-networks/%s' % (agent_id,
+ network_id)
+ return self._delete_resource(uri)
def update_extra_routes(self, router_id, routes):
- uri = '%s/routers/%s' % (self.uri_prefix, router_id)
+ uri = '/routers/%s' % router_id
put_body = {
'router': {
'routes': routes
}
}
- body = json.dumps(put_body)
- resp, body = self.put(uri, body)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ return self._update_resource(uri, put_body)
def delete_extra_routes(self, router_id):
- uri = '%s/routers/%s' % (self.uri_prefix, router_id)
- null_routes = None
+ uri = '/routers/%s' % router_id
put_body = {
'router': {
- 'routes': null_routes
+ 'routes': None
}
}
- body = json.dumps(put_body)
- resp, body = self.put(uri, body)
- self.expected_success(200, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ return self._update_resource(uri, put_body)
def add_dhcp_agent_to_network(self, agent_id, network_id):
post_body = {'network_id': network_id}
- body = json.dumps(post_body)
- uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
- resp, body = self.post(uri, body)
- self.expected_success(201, resp.status)
- body = json.loads(body)
- return service_client.ResponseBody(resp, body)
+ uri = '/agents/%s/dhcp-networks' % agent_id
+ return self._create_resource(uri, post_body)
diff --git a/tempest/services/volume/json/backups_client.py b/tempest/services/volume/json/backups_client.py
index 0f83b8d..8d34230 100644
--- a/tempest/services/volume/json/backups_client.py
+++ b/tempest/services/volume/json/backups_client.py
@@ -17,6 +17,8 @@
from oslo_serialization import jsonutils as json
+from tempest_lib import exceptions as lib_exc
+
from tempest.common import service_client
from tempest import exceptions
@@ -75,6 +77,24 @@
self.expected_success(200, resp.status)
return service_client.ResponseBodyList(resp, body['backups'])
+ def export_backup(self, backup_id):
+ """Export backup metadata record."""
+ url = "backups/%s/export_record" % backup_id
+ resp, body = self.get(url)
+ body = json.loads(body)
+ self.expected_success(200, resp.status)
+ return service_client.ResponseBody(resp, body['backup-record'])
+
+ def import_backup(self, backup_service, backup_url):
+ """Import backup metadata record."""
+ post_body = {'backup_service': backup_service,
+ 'backup_url': backup_url}
+ post_body = json.dumps({'backup-record': post_body})
+ resp, body = self.post("backups/import_record", post_body)
+ body = json.loads(body)
+ self.expected_success(201, resp.status)
+ return service_client.ResponseBody(resp, body['backup'])
+
def wait_for_backup_status(self, backup_id, status):
"""Waits for a Backup to reach a given status."""
body = self.show_backup(backup_id)
@@ -95,6 +115,18 @@
self.build_timeout))
raise exceptions.TimeoutException(message)
+ def wait_for_backup_deletion(self, backup_id):
+ """Waits for backup deletion"""
+ start_time = int(time.time())
+ while True:
+ try:
+ self.show_backup(backup_id)
+ except lib_exc.NotFound:
+ return
+ if int(time.time()) - start_time >= self.build_timeout:
+ raise exceptions.TimeoutException
+ time.sleep(self.build_interval)
+
class BackupsClient(BaseBackupsClient):
"""Volume V1 Backups client"""
diff --git a/tempest/test.py b/tempest/test.py
index 0e60041..df6b30d 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -44,7 +44,7 @@
def attr(**kwargs):
- """A decorator which applies the testtools attr decorator
+ """A decorator which applies the testtools attr decorator
This decorator applies the testtools.testcase.attr if it is in the list of
attributes to testtools we want to apply.