Merge "Change orchestration client to return one value and update tests"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 234273b..02609ae 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -135,6 +135,9 @@
# concurrent test processes. (boolean value)
#locking_credentials_provider = false
+# Roles to assign to all users created by tempest (list value)
+#tempest_roles =
+
[baremetal]
@@ -582,9 +585,6 @@
# applies to user and project (string value)
#admin_domain_name = <None>
-# Roles to assign to all users created by tempest (list value)
-#tempest_roles =
-
[identity-feature-enabled]
@@ -920,6 +920,11 @@
# operations testing. (integer value)
#large_ops_number = 0
+# DHCP client used by images to renew DCHP lease. If left empty,
+# update operation will be skipped. Supported clients: "udhcpc",
+# "dhclient" (string value)
+#dhcp_client = udhcpc
+
[service_available]
diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py
index 3bdcfd6..425ce13 100644
--- a/tempest/api/compute/admin/test_agents.py
+++ b/tempest/api/compute/admin/test_agents.py
@@ -37,8 +37,7 @@
hypervisor='common', os='linux', architecture='x86_64',
version='7.0', url='xxx://xxxx/xxx/xxx',
md5hash='add6bb58e139be103324d04d82d8f545')
- resp, body = self.client.create_agent(**params)
- self.assertEqual(200, resp.status)
+ body = self.client.create_agent(**params)
self.agent_id = body['agent_id']
def tearDown(self):
@@ -67,8 +66,7 @@
hypervisor='kvm', os='win', architecture='x86',
version='7.0', url='xxx://xxxx/xxx/xxx',
md5hash='add6bb58e139be103324d04d82d8f545')
- resp, body = self.client.create_agent(**params)
- self.assertEqual(200, resp.status)
+ body = self.client.create_agent(**params)
self.addCleanup(self.client.delete_agent, body['agent_id'])
for expected_item, value in params.items():
self.assertEqual(value, body[expected_item])
@@ -79,27 +77,23 @@
params = self._param_helper(
version='8.0', url='xxx://xxxx/xxx/xxx2',
md5hash='add6bb58e139be103324d04d82d8f547')
- resp, body = self.client.update_agent(self.agent_id, **params)
- self.assertEqual(200, resp.status)
+ body = self.client.update_agent(self.agent_id, **params)
for expected_item, value in params.items():
self.assertEqual(value, body[expected_item])
@test.attr(type='gate')
def test_delete_agent(self):
# Delete an agent.
- resp, _ = self.client.delete_agent(self.agent_id)
- self.assertEqual(200, resp.status)
+ self.client.delete_agent(self.agent_id)
# Verify the list doesn't contain the deleted agent.
- resp, agents = self.client.list_agents()
- self.assertEqual(200, resp.status)
+ agents = self.client.list_agents()
self.assertNotIn(self.agent_id, map(lambda x: x['agent_id'], agents))
@test.attr(type='gate')
def test_list_agents(self):
# List all agents.
- resp, agents = self.client.list_agents()
- self.assertEqual(200, resp.status)
+ agents = self.client.list_agents()
self.assertTrue(len(agents) > 0, 'Cannot get any agents.(%s)' % agents)
self.assertIn(self.agent_id, map(lambda x: x['agent_id'], agents))
@@ -110,14 +104,12 @@
hypervisor='xen', os='linux', architecture='x86',
version='7.0', url='xxx://xxxx/xxx/xxx1',
md5hash='add6bb58e139be103324d04d82d8f546')
- resp, agent_xen = self.client.create_agent(**params)
- self.assertEqual(200, resp.status)
+ agent_xen = self.client.create_agent(**params)
self.addCleanup(self.client.delete_agent, agent_xen['agent_id'])
agent_id_xen = agent_xen['agent_id']
params_filter = {'hypervisor': agent_xen['hypervisor']}
- resp, agents = self.client.list_agents(params_filter)
- self.assertEqual(200, resp.status)
+ agents = self.client.list_agents(params_filter)
self.assertTrue(len(agents) > 0, 'Cannot get any agents.(%s)' % agents)
self.assertIn(agent_id_xen, map(lambda x: x['agent_id'], agents))
self.assertNotIn(self.agent_id, map(lambda x: x['agent_id'], agents))
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 7c2e604..a866ede 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -35,7 +35,7 @@
cls.aggregate_name_prefix = 'test_aggregate_'
cls.az_name_prefix = 'test_az_'
- resp, hosts_all = cls.os_adm.hosts_client.list_hosts()
+ hosts_all = cls.os_adm.hosts_client.list_hosts()
hosts = map(lambda x: x['host_name'],
filter(lambda y: y['service'] == 'compute', hosts_all))
cls.host = hosts[0]
@@ -52,14 +52,12 @@
def test_aggregate_create_delete(self):
# Create and delete an aggregate.
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self._try_delete_aggregate, aggregate['id'])
- self.assertEqual(200, resp.status)
self.assertEqual(aggregate_name, aggregate['name'])
self.assertIsNone(aggregate['availability_zone'])
- resp, _ = self.client.delete_aggregate(aggregate['id'])
- self.assertEqual(200, resp.status)
+ self.client.delete_aggregate(aggregate['id'])
self.client.wait_for_resource_deletion(aggregate['id'])
@test.attr(type='gate')
@@ -67,26 +65,23 @@
# Create and delete an aggregate.
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
az_name = data_utils.rand_name(self.az_name_prefix)
- resp, aggregate = self.client.create_aggregate(
+ aggregate = self.client.create_aggregate(
name=aggregate_name, availability_zone=az_name)
self.addCleanup(self._try_delete_aggregate, aggregate['id'])
- self.assertEqual(200, resp.status)
self.assertEqual(aggregate_name, aggregate['name'])
self.assertEqual(az_name, aggregate['availability_zone'])
- resp, _ = self.client.delete_aggregate(aggregate['id'])
- self.assertEqual(200, resp.status)
+ self.client.delete_aggregate(aggregate['id'])
self.client.wait_for_resource_deletion(aggregate['id'])
@test.attr(type='gate')
def test_aggregate_create_verify_entry_in_list(self):
# Create an aggregate and ensure it is listed.
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
- resp, aggregates = self.client.list_aggregates()
- self.assertEqual(200, resp.status)
+ aggregates = self.client.list_aggregates()
self.assertIn((aggregate['id'], aggregate['availability_zone']),
map(lambda x: (x['id'], x['availability_zone']),
aggregates))
@@ -95,11 +90,10 @@
def test_aggregate_create_update_metadata_get_details(self):
# Create an aggregate and ensure its details are returned.
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
- resp, body = self.client.get_aggregate(aggregate['id'])
- self.assertEqual(200, resp.status)
+ body = self.client.get_aggregate(aggregate['id'])
self.assertEqual(aggregate['name'], body['name'])
self.assertEqual(aggregate['availability_zone'],
body['availability_zone'])
@@ -107,13 +101,11 @@
# set the metadata of the aggregate
meta = {"key": "value"}
- resp, body = self.client.set_metadata(aggregate['id'], meta)
- self.assertEqual(200, resp.status)
+ body = self.client.set_metadata(aggregate['id'], meta)
self.assertEqual(meta, body["metadata"])
# verify the metadata has been set
- resp, body = self.client.get_aggregate(aggregate['id'])
- self.assertEqual(200, resp.status)
+ body = self.client.get_aggregate(aggregate['id'])
self.assertEqual(meta, body["metadata"])
@test.attr(type='gate')
@@ -121,11 +113,10 @@
# Update an aggregate and ensure properties are updated correctly
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
az_name = data_utils.rand_name(self.az_name_prefix)
- resp, aggregate = self.client.create_aggregate(
+ aggregate = self.client.create_aggregate(
name=aggregate_name, availability_zone=az_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
- self.assertEqual(200, resp.status)
self.assertEqual(aggregate_name, aggregate['name'])
self.assertEqual(az_name, aggregate['availability_zone'])
self.assertIsNotNone(aggregate['id'])
@@ -134,15 +125,13 @@
new_aggregate_name = aggregate_name + '_new'
new_az_name = az_name + '_new'
- resp, resp_aggregate = self.client.update_aggregate(aggregate_id,
- new_aggregate_name,
- new_az_name)
- self.assertEqual(200, resp.status)
+ resp_aggregate = self.client.update_aggregate(aggregate_id,
+ new_aggregate_name,
+ new_az_name)
self.assertEqual(new_aggregate_name, resp_aggregate['name'])
self.assertEqual(new_az_name, resp_aggregate['availability_zone'])
- resp, aggregates = self.client.list_aggregates()
- self.assertEqual(200, resp.status)
+ aggregates = self.client.list_aggregates()
self.assertIn((aggregate_id, new_aggregate_name, new_az_name),
map(lambda x:
(x['id'], x['name'], x['availability_zone']),
@@ -153,18 +142,16 @@
# Add an host to the given aggregate and remove.
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
- resp, body = self.client.add_host(aggregate['id'], self.host)
- self.assertEqual(200, resp.status)
+ body = self.client.add_host(aggregate['id'], self.host)
self.assertEqual(aggregate_name, body['name'])
self.assertEqual(aggregate['availability_zone'],
body['availability_zone'])
self.assertIn(self.host, body['hosts'])
- resp, body = self.client.remove_host(aggregate['id'], self.host)
- self.assertEqual(200, resp.status)
+ body = self.client.remove_host(aggregate['id'], self.host)
self.assertEqual(aggregate_name, body['name'])
self.assertEqual(aggregate['availability_zone'],
body['availability_zone'])
@@ -175,12 +162,12 @@
# Add an host to the given aggregate and list.
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
self.client.add_host(aggregate['id'], self.host)
self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
- resp, aggregates = self.client.list_aggregates()
+ aggregates = self.client.list_aggregates()
aggs = filter(lambda x: x['id'] == aggregate['id'], aggregates)
self.assertEqual(1, len(aggs))
agg = aggs[0]
@@ -193,12 +180,12 @@
# Add an host to the given aggregate and get details.
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
self.client.add_host(aggregate['id'], self.host)
self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
- resp, body = self.client.get_aggregate(aggregate['id'])
+ body = self.client.get_aggregate(aggregate['id'])
self.assertEqual(aggregate_name, body['name'])
self.assertIsNone(body['availability_zone'])
self.assertIn(self.host, body['hosts'])
@@ -209,7 +196,7 @@
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
az_name = data_utils.rand_name(self.az_name_prefix)
- resp, aggregate = self.client.create_aggregate(
+ aggregate = self.client.create_aggregate(
name=aggregate_name, availability_zone=az_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
self.client.add_host(aggregate['id'], self.host)
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
index 219d12e..a450e5d 100644
--- a/tempest/api/compute/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -34,7 +34,7 @@
cls.aggregate_name_prefix = 'test_aggregate_'
cls.az_name_prefix = 'test_az_'
- resp, hosts_all = cls.os_adm.hosts_client.list_hosts()
+ hosts_all = cls.os_adm.hosts_client.list_hosts()
hosts = map(lambda x: x['host_name'],
filter(lambda y: y['service'] == 'compute', hosts_all))
cls.host = hosts[0]
@@ -66,8 +66,7 @@
def test_aggregate_create_with_existent_aggregate_name(self):
# creating an aggregate with existent aggregate name is forbidden
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
- self.assertEqual(200, resp.status)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
self.assertRaises(exceptions.Conflict,
@@ -78,8 +77,7 @@
def test_aggregate_delete_as_user(self):
# Regular user is not allowed to delete an aggregate.
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
- self.assertEqual(200, resp.status)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
self.assertRaises(exceptions.Unauthorized,
@@ -96,8 +94,7 @@
def test_aggregate_get_details_as_user(self):
# Regular user is not allowed to get aggregate details.
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
- self.assertEqual(200, resp.status)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
self.assertRaises(exceptions.Unauthorized,
@@ -119,7 +116,7 @@
@test.attr(type=['negative', 'gate'])
def test_aggregate_add_non_exist_host(self):
# Adding a non-exist host to an aggregate should raise exceptions.
- resp, hosts_all = self.os_adm.hosts_client.list_hosts()
+ hosts_all = self.os_adm.hosts_client.list_hosts()
hosts = map(lambda x: x['host_name'], hosts_all)
while True:
non_exist_host = data_utils.rand_name('nonexist_host_')
@@ -127,7 +124,7 @@
break
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
self.assertRaises(exceptions.NotFound, self.client.add_host,
@@ -137,8 +134,7 @@
def test_aggregate_add_host_as_user(self):
# Regular user is not allowed to add a host to an aggregate.
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
- self.assertEqual(200, resp.status)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
self.assertRaises(exceptions.Unauthorized,
@@ -149,12 +145,10 @@
def test_aggregate_add_existent_host(self):
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
- self.assertEqual(200, resp.status)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
- resp, body = self.client.add_host(aggregate['id'], self.host)
- self.assertEqual(200, resp.status)
+ self.client.add_host(aggregate['id'], self.host)
self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
self.assertRaises(exceptions.Conflict, self.client.add_host,
@@ -165,11 +159,9 @@
# Regular user is not allowed to remove a host from an aggregate.
self.useFixture(fixtures.LockFixture('availability_zone'))
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
- self.assertEqual(200, resp.status)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
- resp, body = self.client.add_host(aggregate['id'], self.host)
- self.assertEqual(200, resp.status)
+ self.client.add_host(aggregate['id'], self.host)
self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
self.assertRaises(exceptions.Unauthorized,
@@ -180,8 +172,7 @@
def test_aggregate_remove_nonexistent_host(self):
non_exist_host = data_utils.rand_name('nonexist_host_')
aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
- resp, aggregate = self.client.create_aggregate(name=aggregate_name)
- self.assertEqual(200, resp.status)
+ aggregate = self.client.create_aggregate(name=aggregate_name)
self.addCleanup(self.client.delete_aggregate, aggregate['id'])
self.assertRaises(exceptions.NotFound, self.client.remove_host,
diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py
index 25965fd..b9d47bb 100644
--- a/tempest/api/compute/admin/test_hosts.py
+++ b/tempest/api/compute/admin/test_hosts.py
@@ -30,19 +30,17 @@
@test.attr(type='gate')
def test_list_hosts(self):
- resp, hosts = self.client.list_hosts()
- self.assertEqual(200, resp.status)
+ hosts = self.client.list_hosts()
self.assertTrue(len(hosts) >= 2, str(hosts))
@test.attr(type='gate')
def test_list_hosts_with_zone(self):
self.useFixture(fixtures.LockFixture('availability_zone'))
- resp, hosts = self.client.list_hosts()
+ hosts = self.client.list_hosts()
host = hosts[0]
zone_name = host['zone']
params = {'zone': zone_name}
- resp, hosts = self.client.list_hosts(params)
- self.assertEqual(200, resp.status)
+ hosts = self.client.list_hosts(params)
self.assertTrue(len(hosts) >= 1)
self.assertIn(host, hosts)
@@ -51,31 +49,27 @@
# If send the request with a blank zone, the request will be successful
# and it will return all the hosts list
params = {'zone': ''}
- resp, hosts = self.client.list_hosts(params)
+ hosts = self.client.list_hosts(params)
self.assertNotEqual(0, len(hosts))
- self.assertEqual(200, resp.status)
@test.attr(type='gate')
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 retured
params = {'zone': 'xxx'}
- resp, hosts = self.client.list_hosts(params)
+ hosts = self.client.list_hosts(params)
self.assertEqual(0, len(hosts))
- self.assertEqual(200, resp.status)
@test.attr(type='gate')
def test_show_host_detail(self):
- resp, hosts = self.client.list_hosts()
- self.assertEqual(200, resp.status)
+ hosts = self.client.list_hosts()
hosts = [host for host in hosts if host['service'] == 'compute']
self.assertTrue(len(hosts) >= 1)
for host in hosts:
hostname = host['host_name']
- resp, resources = self.client.show_host_detail(hostname)
- self.assertEqual(200, resp.status)
+ resources = self.client.show_host_detail(hostname)
self.assertTrue(len(resources) >= 1)
host_resource = resources[0]['resource']
self.assertIsNotNone(host_resource)
diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py
index 055219f..fc918a3 100644
--- a/tempest/api/compute/admin/test_hosts_negative.py
+++ b/tempest/api/compute/admin/test_hosts_negative.py
@@ -31,8 +31,7 @@
cls.non_admin_client = cls.os.hosts_client
def _get_host_name(self):
- resp, hosts = self.client.list_hosts()
- self.assertEqual(200, resp.status)
+ hosts = self.client.list_hosts()
self.assertTrue(len(hosts) >= 1)
hostname = hosts[0]['host_name']
return hostname
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index de3debb..fbfef87 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -30,8 +30,7 @@
def _list_hypervisors(self):
# List of hypervisors
- resp, hypers = self.client.get_hypervisor_list()
- self.assertEqual(200, resp.status)
+ hypers = self.client.get_hypervisor_list()
return hypers
def assertHypervisors(self, hypers):
@@ -46,8 +45,7 @@
@test.attr(type='gate')
def test_get_hypervisor_list_details(self):
# Display the details of the all hypervisor
- resp, hypers = self.client.get_hypervisor_list_details()
- self.assertEqual(200, resp.status)
+ hypers = self.client.get_hypervisor_list_details()
self.assertHypervisors(hypers)
@test.attr(type='gate')
@@ -56,9 +54,7 @@
hypers = self._list_hypervisors()
self.assertHypervisors(hypers)
- resp, details = (self.client.
- get_hypervisor_show_details(hypers[0]['id']))
- self.assertEqual(200, resp.status)
+ details = self.client.get_hypervisor_show_details(hypers[0]['id'])
self.assertTrue(len(details) > 0)
self.assertEqual(details['hypervisor_hostname'],
hypers[0]['hypervisor_hostname'])
@@ -70,15 +66,13 @@
self.assertHypervisors(hypers)
hostname = hypers[0]['hypervisor_hostname']
- resp, hypervisors = self.client.get_hypervisor_servers(hostname)
- self.assertEqual(200, resp.status)
+ hypervisors = self.client.get_hypervisor_servers(hostname)
self.assertTrue(len(hypervisors) > 0)
@test.attr(type='gate')
def test_get_hypervisor_stats(self):
# Verify the stats of the all hypervisor
- resp, stats = self.client.get_hypervisor_stats()
- self.assertEqual(200, resp.status)
+ stats = self.client.get_hypervisor_stats()
self.assertTrue(len(stats) > 0)
@test.attr(type='gate')
@@ -94,9 +88,7 @@
ironic_only = True
hypers_without_ironic = []
for hyper in hypers:
- resp, details = (self.client.
- get_hypervisor_show_details(hypers[0]['id']))
- self.assertEqual(200, resp.status)
+ details = self.client.get_hypervisor_show_details(hypers[0]['id'])
if details['hypervisor_type'] != 'ironic':
hypers_without_ironic.append(hyper)
ironic_only = False
@@ -110,8 +102,8 @@
# because hypervisors might be disabled, this loops looking
# for any good hit.
try:
- resp, uptime = self.client.get_hypervisor_uptime(hyper['id'])
- if (resp.status == 200) and (len(uptime) > 0):
+ uptime = self.client.get_hypervisor_uptime(hyper['id'])
+ if len(uptime) > 0:
has_valid_uptime = True
break
except Exception:
@@ -124,7 +116,6 @@
def test_search_hypervisor(self):
hypers = self._list_hypervisors()
self.assertHypervisors(hypers)
- resp, hypers = self.client.search_hypervisor(
+ hypers = self.client.search_hypervisor(
hypers[0]['hypervisor_hostname'])
- self.assertEqual(200, resp.status)
self.assertHypervisors(hypers)
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index b1f2351..a137a61 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -35,8 +35,7 @@
def _list_hypervisors(self):
# List of hypervisors
- resp, hypers = self.client.get_hypervisor_list()
- self.assertEqual(200, resp.status)
+ hypers = self.client.get_hypervisor_list()
return hypers
@test.attr(type=['negative', 'gate'])
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index e7a39f8..5cf4a31 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -31,29 +31,27 @@
@test.attr(type='gate')
def test_list_services(self):
- resp, services = self.client.list_services()
- self.assertEqual(200, resp.status)
+ services = self.client.list_services()
self.assertNotEqual(0, len(services))
@test.attr(type='gate')
def test_get_service_by_service_binary_name(self):
binary_name = 'nova-compute'
params = {'binary': binary_name}
- resp, services = self.client.list_services(params)
- self.assertEqual(200, resp.status)
+ services = self.client.list_services(params)
self.assertNotEqual(0, len(services))
for service in services:
self.assertEqual(binary_name, service['binary'])
@test.attr(type='gate')
def test_get_service_by_host_name(self):
- resp, services = self.client.list_services()
+ services = self.client.list_services()
host_name = services[0]['host']
services_on_host = [service for service in services if
service['host'] == host_name]
params = {'host': host_name}
- resp, services = self.client.list_services(params)
+ services = self.client.list_services(params)
# we could have a periodic job checkin between the 2 service
# lookups, so only compare binary lists.
@@ -66,13 +64,12 @@
@test.attr(type='gate')
def test_get_service_by_service_and_host_name(self):
- resp, services = self.client.list_services()
+ services = self.client.list_services()
host_name = services[0]['host']
binary_name = services[0]['binary']
params = {'host': host_name, 'binary': binary_name}
- resp, services = self.client.list_services(params)
- self.assertEqual(200, resp.status)
+ services = self.client.list_services(params)
self.assertEqual(1, len(services))
self.assertEqual(host_name, services[0]['host'])
self.assertEqual(binary_name, services[0]['binary'])
diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py
index 534afc5..bb19a39 100644
--- a/tempest/api/compute/admin/test_services_negative.py
+++ b/tempest/api/compute/admin/test_services_negative.py
@@ -37,26 +37,23 @@
@test.attr(type=['negative', 'gate'])
def test_get_service_by_invalid_params(self):
# return all services if send the request with invalid parameter
- resp, services = self.client.list_services()
+ services = self.client.list_services()
params = {'xxx': 'nova-compute'}
- resp, services_xxx = self.client.list_services(params)
- self.assertEqual(200, resp.status)
+ services_xxx = self.client.list_services(params)
self.assertEqual(len(services), len(services_xxx))
@test.attr(type=['negative', 'gate'])
def test_get_service_by_invalid_service_and_valid_host(self):
- resp, services = self.client.list_services()
+ services = self.client.list_services()
host_name = services[0]['host']
params = {'host': host_name, 'binary': 'xxx'}
- resp, services = self.client.list_services(params)
- self.assertEqual(200, resp.status)
+ services = self.client.list_services(params)
self.assertEqual(0, len(services))
@test.attr(type=['negative', 'gate'])
def test_get_service_with_valid_service_and_invalid_host(self):
- resp, services = self.client.list_services()
+ services = self.client.list_services()
binary_name = services[0]['binary']
params = {'host': 'xxx', 'binary': binary_name}
- resp, services = self.client.list_services(params)
- self.assertEqual(200, resp.status)
+ services = self.client.list_services(params)
self.assertEqual(0, len(services))
diff --git a/tempest/api/compute/test_live_block_migration.py b/tempest/api/compute/test_live_block_migration.py
index cb75d07..e04439f 100644
--- a/tempest/api/compute/test_live_block_migration.py
+++ b/tempest/api/compute/test_live_block_migration.py
@@ -36,7 +36,7 @@
cls.created_server_ids = []
def _get_compute_hostnames(self):
- _resp, body = self.admin_hosts_client.list_hosts()
+ body = self.admin_hosts_client.list_hosts()
return [
host_record['host_name']
for host_record in body
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 60a1ae9..bf85e90 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -103,7 +103,8 @@
address = self._get_ipaddress_from_tempest_conf()
allocation_pools = {'allocation_pools': [{'start': str(address + 4),
'end': str(address + 6)}]}
- self.create_subnet(network, **allocation_pools)
+ subnet = self.create_subnet(network, **allocation_pools)
+ self.addCleanup(self.client.delete_subnet, subnet['id'])
body = self.client.create_port(network_id=net_id)
self.addCleanup(self.client.delete_port, body['port']['id'])
port = body['port']
@@ -149,8 +150,11 @@
def test_port_list_filter_by_router_id(self):
# Create a router
network = self.create_network()
- self.create_subnet(network)
+ self.addCleanup(self.client.delete_network, network['id'])
+ subnet = self.create_subnet(network)
+ self.addCleanup(self.client.delete_subnet, subnet['id'])
router = self.create_router(data_utils.rand_name('router-'))
+ self.addCleanup(self.client.delete_router, router['id'])
port = self.client.create_port(network_id=network['id'])
# Add router interface to port created above
self.client.add_router_interface_with_port_id(
@@ -179,8 +183,11 @@
def test_create_update_port_with_second_ip(self):
# Create a network with two subnets
network = self.create_network()
+ self.addCleanup(self.client.delete_network, network['id'])
subnet_1 = self.create_subnet(network)
+ self.addCleanup(self.client.delete_subnet, subnet_1['id'])
subnet_2 = self.create_subnet(network)
+ self.addCleanup(self.client.delete_subnet, subnet_2['id'])
fixed_ip_1 = [{'subnet_id': subnet_1['id']}]
fixed_ip_2 = [{'subnet_id': subnet_2['id']}]
@@ -189,6 +196,7 @@
# Create a port with multiple IP addresses
port = self.create_port(network,
fixed_ips=fixed_ips)
+ self.addCleanup(self.client.delete_port, port['id'])
self.assertEqual(2, len(port['fixed_ips']))
check_fixed_ips = [subnet_1['id'], subnet_2['id']]
for item in port['fixed_ips']:
@@ -204,6 +212,7 @@
def _update_port_with_security_groups(self, security_groups_names):
subnet_1 = self.create_subnet(self.network)
+ self.addCleanup(self.client.delete_subnet, subnet_1['id'])
fixed_ip_1 = [{'subnet_id': subnet_1['id']}]
security_groups_list = list()
@@ -281,23 +290,14 @@
@test.attr(type='smoke')
def test_create_port_with_no_securitygroups(self):
network = self.create_network()
- self.create_subnet(network)
+ self.addCleanup(self.client.delete_network, network['id'])
+ subnet = self.create_subnet(network)
+ self.addCleanup(self.client.delete_subnet, subnet['id'])
port = self.create_port(network, security_groups=[])
+ self.addCleanup(self.client.delete_port, port['id'])
self.assertIsNotNone(port['security_groups'])
self.assertEmpty(port['security_groups'])
- @test.attr(type='smoke')
- def test_update_port_with_no_securitygroups(self):
- network = self.create_network()
- self.create_subnet(network)
- port = self.create_port(network)
- # Verify that port is created with default security group
- self.assertIsNotNone(port['security_groups'])
- self.assertNotEmpty(port['security_groups'])
- updated_port = self.update_port(port, security_groups=[])
- self.assertIsNotNone(updated_port['security_groups'])
- self.assertEmpty(updated_port['security_groups'])
-
class PortsAdminExtendedAttrsTestJSON(base.BaseAdminNetworkTest):
_interface = 'json'
diff --git a/tempest/clients.py b/tempest/clients.py
index 8d59742..63bae6c 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -133,15 +133,22 @@
Top level manager for OpenStack tempest clients
"""
+ default_params = {
+ 'disable_ssl_certificate_validation':
+ CONF.identity.disable_ssl_certificate_validation,
+ 'ca_certs': CONF.identity.ca_certificates_file,
+ 'trace_requests': CONF.debug.trace_requests
+ }
+
def __init__(self, credentials=None, interface='json', service=None):
# Set interface and client type first
self.interface = interface
# super cares for credentials validation
super(Manager, self).__init__(credentials=credentials)
- self._set_compute_clients(self.interface)
- self._set_identity_clients(self.interface)
- self._set_volume_clients(self.interface)
+ self._set_compute_clients()
+ self._set_identity_clients()
+ self._set_volume_clients()
self.baremetal_client = BaremetalClientJSON(self.auth_provider)
self.network_client = NetworkClientJSON(self.auth_provider)
@@ -170,23 +177,25 @@
self.container_client = ContainerClient(self.auth_provider)
self.object_client = ObjectClient(self.auth_provider)
self.orchestration_client = OrchestrationClient(
- self.auth_provider)
+ self.auth_provider,
+ CONF.orchestration.catalog_type,
+ CONF.orchestration.region or CONF.identity.region,
+ endpoint_type=CONF.orchestration.endpoint_type,
+ build_interval=CONF.orchestration.build_interval,
+ build_timeout=CONF.orchestration.build_timeout,
+ **self.default_params)
+
self.ec2api_client = botoclients.APIClientEC2(*ec2_client_args)
self.s3_client = botoclients.ObjectClientS3(*ec2_client_args)
self.data_processing_client = DataProcessingClient(
self.auth_provider)
- def _set_compute_clients(self, type):
- self._set_compute_json_clients()
-
- # Common compute clients
+ def _set_compute_clients(self):
self.agents_client = AgentsClientJSON(self.auth_provider)
self.networks_client = NetworksClientJSON(self.auth_provider)
self.migrations_client = MigrationsClientJSON(self.auth_provider)
self.security_group_default_rules_client = (
SecurityGroupDefaultRulesClientJSON(self.auth_provider))
-
- def _set_compute_json_clients(self):
self.certificates_client = CertificatesClientJSON(self.auth_provider)
self.servers_client = ServersClientJSON(self.auth_provider)
self.limits_client = LimitsClientJSON(self.auth_provider)
@@ -213,10 +222,7 @@
self.instance_usages_audit_log_client = \
InstanceUsagesAuditLogClientJSON(self.auth_provider)
- def _set_identity_clients(self, type):
- self._set_identity_json_clients()
-
- def _set_identity_json_clients(self):
+ def _set_identity_clients(self):
self.identity_client = IdentityClientJSON(self.auth_provider)
self.identity_v3_client = IdentityV3ClientJSON(self.auth_provider)
self.endpoints_client = EndPointClientJSON(self.auth_provider)
@@ -228,20 +234,12 @@
self.token_v3_client = V3TokenClientJSON()
self.credentials_client = CredentialsClientJSON(self.auth_provider)
- def _set_volume_clients(self, type):
- self._set_volume_json_clients()
- # Common volume clients
- # NOTE : As XML clients are not implemented for Qos-specs.
- # So, setting the qos_client here. Once client are implemented,
- # qos_client would be moved to its respective if/else.
- # Bug : 1312553
+ def _set_volume_clients(self):
self.volume_qos_client = QosSpecsClientJSON(self.auth_provider)
self.volume_qos_v2_client = QosSpecsV2ClientJSON(
self.auth_provider)
self.volume_services_v2_client = VolumesServicesV2ClientJSON(
self.auth_provider)
-
- def _set_volume_json_clients(self):
self.backups_client = BackupsClientJSON(self.auth_provider)
self.backups_v2_client = BackupsClientV2JSON(self.auth_provider)
self.snapshots_client = SnapshotsClientJSON(self.auth_provider)
diff --git a/tempest/common/http.py b/tempest/common/http.py
deleted file mode 100644
index b3793bc..0000000
--- a/tempest/common/http.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# Copyright 2013 Citrix Systems, Inc.
-# 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 httplib2
-
-
-class ClosingHttp(httplib2.Http):
- def request(self, *args, **kwargs):
- original_headers = kwargs.get('headers', {})
- new_headers = dict(original_headers, connection='close')
- new_kwargs = dict(kwargs, headers=new_headers)
- return super(ClosingHttp, self).request(*args, **new_kwargs)
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index e7590b7..a663931 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -124,7 +124,7 @@
self._assign_user_role(tenant, user, swift_operator_role)
if admin:
self._assign_user_role(tenant, user, CONF.identity.admin_role)
- for role in CONF.identity.tempest_roles:
+ for role in CONF.auth.tempest_roles:
self._assign_user_role(tenant, user, role)
return self._get_credentials(user, tenant)
diff --git a/tempest/common/negative_rest_client.py b/tempest/common/negative_rest_client.py
index a9ae1c3..d9842e6 100644
--- a/tempest/common/negative_rest_client.py
+++ b/tempest/common/negative_rest_client.py
@@ -15,7 +15,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.common import rest_client
+from tempest_lib.common import rest_client
+
from tempest import config
CONF = config.CONF
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
deleted file mode 100644
index c5696b7..0000000
--- a/tempest/common/rest_client.py
+++ /dev/null
@@ -1,567 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# Copyright 2013 IBM Corp.
-# 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 collections
-import json
-import logging as real_logging
-import re
-import time
-
-import jsonschema
-import six
-
-from tempest.common import http
-from tempest.common.utils import misc as misc_utils
-from tempest import exceptions
-from tempest.openstack.common import log as logging
-
-# redrive rate limited calls at most twice
-MAX_RECURSION_DEPTH = 2
-
-# All the successful HTTP status codes from RFC 7231 & 4918
-HTTP_SUCCESS = (200, 201, 202, 203, 204, 205, 206, 207)
-
-
-class RestClient(object):
-
- TYPE = "json"
-
- LOG = logging.getLogger(__name__)
-
- def __init__(self, auth_provider, service, region,
- endpoint_type='publicURL',
- build_interval=1, build_timeout=60,
- disable_ssl_certificate_validation=False, ca_certs=None,
- trace_requests=''):
- self.auth_provider = auth_provider
- self.service = service
- self.region = region
- self.endpoint_type = endpoint_type
- self.build_interval = build_interval
- self.build_timeout = build_timeout
- self.trace_requests = trace_requests
-
- # The version of the API this client implements
- self.api_version = None
- self._skip_path = False
- self.general_header_lc = set(('cache-control', 'connection',
- 'date', 'pragma', 'trailer',
- 'transfer-encoding', 'via',
- 'warning'))
- self.response_header_lc = set(('accept-ranges', 'age', 'etag',
- 'location', 'proxy-authenticate',
- 'retry-after', 'server',
- 'vary', 'www-authenticate'))
- dscv = disable_ssl_certificate_validation
- self.http_obj = http.ClosingHttp(
- disable_ssl_certificate_validation=dscv, ca_certs=ca_certs)
-
- def _get_type(self):
- return self.TYPE
-
- def get_headers(self, accept_type=None, send_type=None):
- if accept_type is None:
- accept_type = self._get_type()
- if send_type is None:
- send_type = self._get_type()
- return {'Content-Type': 'application/%s' % send_type,
- 'Accept': 'application/%s' % accept_type}
-
- def __str__(self):
- STRING_LIMIT = 80
- str_format = ("service:%s, base_url:%s, "
- "filters: %s, build_interval:%s, build_timeout:%s"
- "\ntoken:%s..., \nheaders:%s...")
- return str_format % (self.service, self.base_url,
- self.filters, self.build_interval,
- self.build_timeout,
- str(self.token)[0:STRING_LIMIT],
- str(self.get_headers())[0:STRING_LIMIT])
-
- @property
- def user(self):
- return self.auth_provider.credentials.username
-
- @property
- def user_id(self):
- return self.auth_provider.credentials.user_id
-
- @property
- def tenant_name(self):
- return self.auth_provider.credentials.tenant_name
-
- @property
- def tenant_id(self):
- return self.auth_provider.credentials.tenant_id
-
- @property
- def password(self):
- return self.auth_provider.credentials.password
-
- @property
- def base_url(self):
- return self.auth_provider.base_url(filters=self.filters)
-
- @property
- def token(self):
- return self.auth_provider.get_token()
-
- @property
- def filters(self):
- _filters = dict(
- service=self.service,
- endpoint_type=self.endpoint_type,
- region=self.region
- )
- if self.api_version is not None:
- _filters['api_version'] = self.api_version
- if self._skip_path:
- _filters['skip_path'] = self._skip_path
- return _filters
-
- def skip_path(self):
- """
- When set, ignore the path part of the base URL from the catalog
- """
- self._skip_path = True
-
- def reset_path(self):
- """
- When reset, use the base URL from the catalog as-is
- """
- self._skip_path = False
-
- @classmethod
- def expected_success(cls, expected_code, read_code):
- assert_msg = ("This function only allowed to use for HTTP status"
- "codes which explicitly defined in the RFC 7231 & 4918."
- "{0} is not a defined Success Code!"
- ).format(expected_code)
- if isinstance(expected_code, list):
- for code in expected_code:
- assert code in HTTP_SUCCESS, assert_msg
- else:
- assert expected_code in HTTP_SUCCESS, assert_msg
-
- # NOTE(afazekas): the http status code above 400 is processed by
- # the _error_checker method
- if read_code < 400:
- pattern = """Unexpected http success status code {0},
- The expected status code is {1}"""
- if ((not isinstance(expected_code, list) and
- (read_code != expected_code)) or
- (isinstance(expected_code, list) and
- (read_code not in expected_code))):
- details = pattern.format(read_code, expected_code)
- raise exceptions.InvalidHttpSuccessCode(details)
-
- def post(self, url, body, headers=None, extra_headers=False):
- return self.request('POST', url, extra_headers, headers, body)
-
- def get(self, url, headers=None, extra_headers=False):
- return self.request('GET', url, extra_headers, headers)
-
- def delete(self, url, headers=None, body=None, extra_headers=False):
- return self.request('DELETE', url, extra_headers, headers, body)
-
- def patch(self, url, body, headers=None, extra_headers=False):
- return self.request('PATCH', url, extra_headers, headers, body)
-
- def put(self, url, body, headers=None, extra_headers=False):
- return self.request('PUT', url, extra_headers, headers, body)
-
- def head(self, url, headers=None, extra_headers=False):
- return self.request('HEAD', url, extra_headers, headers)
-
- def copy(self, url, headers=None, extra_headers=False):
- return self.request('COPY', url, extra_headers, headers)
-
- def get_versions(self):
- resp, body = self.get('')
- body = self._parse_resp(body)
- versions = map(lambda x: x['id'], body)
- return resp, versions
-
- def _get_request_id(self, resp):
- for i in ('x-openstack-request-id', 'x-compute-request-id'):
- if i in resp:
- return resp[i]
- return ""
-
- def _safe_body(self, body, maxlen=4096):
- # convert a structure into a string safely
- try:
- text = six.text_type(body)
- except UnicodeDecodeError:
- # if this isn't actually text, return marker that
- return "<BinaryData: removed>"
- if len(text) > maxlen:
- return text[:maxlen]
- else:
- return text
-
- def _log_request_start(self, method, req_url, req_headers=None,
- req_body=None):
- if req_headers is None:
- req_headers = {}
- caller_name = misc_utils.find_test_caller()
- if self.trace_requests and re.search(self.trace_requests, caller_name):
- self.LOG.debug('Starting Request (%s): %s %s' %
- (caller_name, method, req_url))
-
- def _log_request_full(self, method, req_url, resp,
- secs="", req_headers=None,
- req_body=None, resp_body=None,
- caller_name=None, extra=None):
- if 'X-Auth-Token' in req_headers:
- req_headers['X-Auth-Token'] = '<omitted>'
- log_fmt = """Request (%s): %s %s %s%s
- Request - Headers: %s
- Body: %s
- Response - Headers: %s
- Body: %s"""
-
- self.LOG.debug(
- log_fmt % (
- caller_name,
- resp['status'],
- method,
- req_url,
- secs,
- str(req_headers),
- self._safe_body(req_body),
- str(resp),
- self._safe_body(resp_body)),
- extra=extra)
-
- def _log_request(self, method, req_url, resp,
- secs="", req_headers=None,
- req_body=None, resp_body=None):
- if req_headers is None:
- req_headers = {}
- # if we have the request id, put it in the right part of the log
- extra = dict(request_id=self._get_request_id(resp))
- # NOTE(sdague): while we still have 6 callers to this function
- # we're going to just provide work around on who is actually
- # providing timings by gracefully adding no content if they don't.
- # Once we're down to 1 caller, clean this up.
- caller_name = misc_utils.find_test_caller()
- if secs:
- secs = " %.3fs" % secs
- if not self.LOG.isEnabledFor(real_logging.DEBUG):
- self.LOG.info(
- 'Request (%s): %s %s %s%s' % (
- caller_name,
- resp['status'],
- method,
- req_url,
- secs),
- extra=extra)
-
- # Also look everything at DEBUG if you want to filter this
- # out, don't run at debug.
- self._log_request_full(method, req_url, resp, secs, req_headers,
- req_body, resp_body, caller_name, extra)
-
- def _parse_resp(self, body):
- body = json.loads(body)
-
- # We assume, that if the first value of the deserialized body's
- # item set is a dict or a list, that we just return the first value
- # of deserialized body.
- # Essentially "cutting out" the first placeholder element in a body
- # that looks like this:
- #
- # {
- # "users": [
- # ...
- # ]
- # }
- try:
- # Ensure there are not more than one top-level keys
- if len(body.keys()) > 1:
- return body
- # Just return the "wrapped" element
- first_key, first_item = six.next(six.iteritems(body))
- if isinstance(first_item, (dict, list)):
- return first_item
- except (ValueError, IndexError):
- pass
- return body
-
- def response_checker(self, method, resp, resp_body):
- if (resp.status in set((204, 205, 304)) or resp.status < 200 or
- method.upper() == 'HEAD') and resp_body:
- raise exceptions.ResponseWithNonEmptyBody(status=resp.status)
- # NOTE(afazekas):
- # If the HTTP Status Code is 205
- # 'The response MUST NOT include an entity.'
- # A HTTP entity has an entity-body and an 'entity-header'.
- # In the HTTP response specification (Section 6) the 'entity-header'
- # 'generic-header' and 'response-header' are in OR relation.
- # All headers not in the above two group are considered as entity
- # header in every interpretation.
-
- if (resp.status == 205 and
- 0 != len(set(resp.keys()) - set(('status',)) -
- self.response_header_lc - self.general_header_lc)):
- raise exceptions.ResponseWithEntity()
- # NOTE(afazekas)
- # Now the swift sometimes (delete not empty container)
- # returns with non json error response, we can create new rest class
- # for swift.
- # Usually RFC2616 says error responses SHOULD contain an explanation.
- # The warning is normal for SHOULD/SHOULD NOT case
-
- # Likely it will cause an error
- if method != 'HEAD' and not resp_body and resp.status >= 400:
- self.LOG.warning("status >= 400 response with empty body")
-
- def _request(self, method, url, headers=None, body=None):
- """A simple HTTP request interface."""
- # Authenticate the request with the auth provider
- req_url, req_headers, req_body = self.auth_provider.auth_request(
- method, url, headers, body, self.filters)
-
- # Do the actual request, and time it
- start = time.time()
- self._log_request_start(method, req_url)
- resp, resp_body = self.raw_request(
- req_url, method, headers=req_headers, body=req_body)
- end = time.time()
- self._log_request(method, req_url, resp, secs=(end - start),
- req_headers=req_headers, req_body=req_body,
- resp_body=resp_body)
-
- # Verify HTTP response codes
- self.response_checker(method, resp, resp_body)
-
- return resp, resp_body
-
- def raw_request(self, url, method, headers=None, body=None):
- if headers is None:
- headers = self.get_headers()
- return self.http_obj.request(url, method,
- headers=headers, body=body)
-
- def request(self, method, url, extra_headers=False, headers=None,
- body=None):
- # if extra_headers is True
- # default headers would be added to headers
- retry = 0
-
- if headers is None:
- # NOTE(vponomaryov): if some client do not need headers,
- # it should explicitly pass empty dict
- headers = self.get_headers()
- elif extra_headers:
- try:
- headers = headers.copy()
- headers.update(self.get_headers())
- except (ValueError, TypeError):
- headers = self.get_headers()
-
- resp, resp_body = self._request(method, url,
- headers=headers, body=body)
-
- while (resp.status == 413 and
- 'retry-after' in resp and
- not self.is_absolute_limit(
- resp, self._parse_resp(resp_body)) and
- retry < MAX_RECURSION_DEPTH):
- retry += 1
- delay = int(resp['retry-after'])
- time.sleep(delay)
- resp, resp_body = self._request(method, url,
- headers=headers, body=body)
- self._error_checker(method, url, headers, body,
- resp, resp_body)
- return resp, resp_body
-
- def _error_checker(self, method, url,
- headers, body, resp, resp_body):
-
- # NOTE(mtreinish): Check for httplib response from glance_http. The
- # object can't be used here because importing httplib breaks httplib2.
- # If another object from a class not imported were passed here as
- # resp this could possibly fail
- if str(type(resp)) == "<type 'instance'>":
- ctype = resp.getheader('content-type')
- else:
- try:
- ctype = resp['content-type']
- # NOTE(mtreinish): Keystone delete user responses doesn't have a
- # content-type header. (They don't have a body) So just pretend it
- # is set.
- except KeyError:
- ctype = 'application/json'
-
- # It is not an error response
- if resp.status < 400:
- return
-
- JSON_ENC = ['application/json', 'application/json; charset=utf-8']
- # NOTE(mtreinish): This is for compatibility with Glance and swift
- # APIs. These are the return content types that Glance api v1
- # (and occasionally swift) are using.
- TXT_ENC = ['text/plain', 'text/html', 'text/html; charset=utf-8',
- 'text/plain; charset=utf-8']
-
- if ctype.lower() in JSON_ENC:
- parse_resp = True
- elif ctype.lower() in TXT_ENC:
- parse_resp = False
- else:
- raise exceptions.InvalidContentType(str(resp.status))
-
- if resp.status == 401 or resp.status == 403:
- raise exceptions.Unauthorized(resp_body)
-
- if resp.status == 404:
- raise exceptions.NotFound(resp_body)
-
- if resp.status == 400:
- if parse_resp:
- resp_body = self._parse_resp(resp_body)
- raise exceptions.BadRequest(resp_body)
-
- if resp.status == 409:
- if parse_resp:
- resp_body = self._parse_resp(resp_body)
- raise exceptions.Conflict(resp_body)
-
- if resp.status == 413:
- if parse_resp:
- resp_body = self._parse_resp(resp_body)
- if self.is_absolute_limit(resp, resp_body):
- raise exceptions.OverLimit(resp_body)
- else:
- raise exceptions.RateLimitExceeded(resp_body)
-
- if resp.status == 415:
- if parse_resp:
- resp_body = self._parse_resp(resp_body)
- raise exceptions.InvalidContentType(resp_body)
-
- if resp.status == 422:
- if parse_resp:
- resp_body = self._parse_resp(resp_body)
- raise exceptions.UnprocessableEntity(resp_body)
-
- if resp.status in (500, 501):
- message = resp_body
- if parse_resp:
- try:
- resp_body = self._parse_resp(resp_body)
- except ValueError:
- # If response body is a non-json string message.
- # Use resp_body as is and raise InvalidResponseBody
- # exception.
- raise exceptions.InvalidHTTPResponseBody(message)
- else:
- if isinstance(resp_body, dict):
- # I'm seeing both computeFault
- # and cloudServersFault come back.
- # Will file a bug to fix, but leave as is for now.
- if 'cloudServersFault' in resp_body:
- message = resp_body['cloudServersFault']['message']
- elif 'computeFault' in resp_body:
- message = resp_body['computeFault']['message']
- elif 'error' in resp_body:
- message = resp_body['error']['message']
- elif 'message' in resp_body:
- message = resp_body['message']
- else:
- message = resp_body
-
- if resp.status == 501:
- raise exceptions.NotImplemented(message)
- else:
- raise exceptions.ServerFault(message)
-
- if resp.status >= 400:
- raise exceptions.UnexpectedResponseCode(str(resp.status))
-
- def is_absolute_limit(self, resp, resp_body):
- if (not isinstance(resp_body, collections.Mapping) or
- 'retry-after' not in resp):
- return True
- over_limit = resp_body.get('overLimit', None)
- if not over_limit:
- return True
- return 'exceed' in over_limit.get('message', 'blabla')
-
- def wait_for_resource_deletion(self, id):
- """Waits for a resource to be deleted."""
- start_time = int(time.time())
- while True:
- if self.is_resource_deleted(id):
- return
- if int(time.time()) - start_time >= self.build_timeout:
- message = ('Failed to delete %(resource_type)s %(id)s within '
- 'the required time (%(timeout)s s).' %
- {'resource_type': self.resource_type, 'id': id,
- 'timeout': self.build_timeout})
- caller = misc_utils.find_test_caller()
- if caller:
- message = '(%s) %s' % (caller, message)
- raise exceptions.TimeoutException(message)
- time.sleep(self.build_interval)
-
- def is_resource_deleted(self, id):
- """
- Subclasses override with specific deletion detection.
- """
- message = ('"%s" does not implement is_resource_deleted'
- % self.__class__.__name__)
- raise NotImplementedError(message)
-
- @property
- def resource_type(self):
- """Returns the primary type of resource this client works with."""
- return 'resource'
-
- @classmethod
- def validate_response(cls, schema, resp, body):
- # Only check the response if the status code is a success code
- # TODO(cyeoh): Eventually we should be able to verify that a failure
- # code if it exists is something that we expect. This is explicitly
- # declared in the V3 API and so we should be able to export this in
- # the response schema. For now we'll ignore it.
- if resp.status in HTTP_SUCCESS:
- cls.expected_success(schema['status_code'], resp.status)
-
- # Check the body of a response
- body_schema = schema.get('response_body')
- if body_schema:
- try:
- jsonschema.validate(body, body_schema)
- except jsonschema.ValidationError as ex:
- msg = ("HTTP response body is invalid (%s)") % ex
- raise exceptions.InvalidHTTPResponseBody(msg)
- else:
- if body:
- msg = ("HTTP response body should not exist (%s)") % body
- raise exceptions.InvalidHTTPResponseBody(msg)
-
- # Check the header of a response
- header_schema = schema.get('response_header')
- if header_schema:
- try:
- jsonschema.validate(resp, header_schema)
- except jsonschema.ValidationError as ex:
- msg = ("HTTP response header is invalid (%s)") % ex
- raise exceptions.InvalidHTTPResponseHeader(msg)
diff --git a/tempest/common/service_client.py b/tempest/common/service_client.py
index c32a7d0..45a07f1 100644
--- a/tempest/common/service_client.py
+++ b/tempest/common/service_client.py
@@ -12,8 +12,11 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest.common import rest_client
+from tempest_lib.common import rest_client
+from tempest_lib import exceptions as lib_exceptions
+
from tempest import config
+from tempest import exceptions
CONF = config.CONF
@@ -21,13 +24,21 @@
class ServiceClient(rest_client.RestClient):
def __init__(self, auth_provider, service, region,
- endpoint_type=None, build_interval=None, build_timeout=None):
+ endpoint_type=None, build_interval=None, build_timeout=None,
+ disable_ssl_certificate_validation=None, ca_certs=None,
+ trace_requests=None):
+
+ # TODO(oomichi): This params setting should be removed after all
+ # service clients pass these values, and we can make ServiceClient
+ # free from CONF values.
+ dscv = (disable_ssl_certificate_validation or
+ CONF.identity.disable_ssl_certificate_validation)
params = {
- 'disable_ssl_certificate_validation':
- CONF.identity.disable_ssl_certificate_validation,
- 'ca_certs': CONF.identity.ca_certificates_file,
- 'trace_requests': CONF.debug.trace_requests
+ 'disable_ssl_certificate_validation': dscv,
+ 'ca_certs': ca_certs or CONF.identity.ca_certificates_file,
+ 'trace_requests': trace_requests or CONF.debug.trace_requests
}
+
if endpoint_type is not None:
params.update({'endpoint_type': endpoint_type})
if build_interval is not None:
@@ -37,6 +48,42 @@
super(ServiceClient, self).__init__(auth_provider, service, region,
**params)
+ def request(self, method, url, extra_headers=False, headers=None,
+ body=None):
+ # TODO(oomichi): This translation is just for avoiding a single
+ # huge patch to migrate rest_client module to tempest-lib.
+ # Ideally(in the future), we need to remove this translation and
+ # replace each API tests with tempest-lib's exceptions.
+ try:
+ return super(ServiceClient, self).request(
+ method, url,
+ extra_headers=extra_headers,
+ headers=headers, body=body)
+ except lib_exceptions.Unauthorized as ex:
+ raise exceptions.Unauthorized(ex)
+ except lib_exceptions.NotFound as ex:
+ raise exceptions.NotFound(ex)
+ except lib_exceptions.BadRequest as ex:
+ raise exceptions.BadRequest(ex)
+ except lib_exceptions.Conflict as ex:
+ raise exceptions.Conflict(ex)
+ except lib_exceptions.OverLimit as ex:
+ raise exceptions.OverLimit(ex)
+ except lib_exceptions.RateLimitExceeded as ex:
+ raise exceptions.RateLimitExceeded(ex)
+ except lib_exceptions.InvalidContentType as ex:
+ raise exceptions.InvalidContentType(ex)
+ except lib_exceptions.UnprocessableEntity as ex:
+ raise exceptions.UnprocessableEntity(ex)
+ except lib_exceptions.InvalidHTTPResponseBody as ex:
+ raise exceptions.InvalidHTTPResponseBody(ex)
+ except lib_exceptions.NotImplemented as ex:
+ raise exceptions.NotImplemented(ex)
+ except lib_exceptions.ServerFault as ex:
+ raise exceptions.ServerFault(ex)
+ except lib_exceptions.UnexpectedResponseCode as ex:
+ raise exceptions.UnexpectedResponseCode(ex)
+
class ResponseBody(dict):
"""Class that wraps an http response and dict body into a single value.
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index d8bfef8..6e61c55 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -97,6 +97,10 @@
cmd = "/bin/ip addr | awk '/ether/ {print $2}'"
return self.exec_command(cmd)
+ def get_nic_name(self, address):
+ cmd = "/bin/ip -o addr | awk '/%s/ {print $2}'" % address
+ return self.exec_command(cmd)
+
def get_ip_list(self):
cmd = "/bin/ip address"
return self.exec_command(cmd)
@@ -116,3 +120,47 @@
# Get pid(s) of a process/program
cmd = "ps -ef | grep %s | grep -v 'grep' | awk {'print $1'}" % pr_name
return self.exec_command(cmd).split('\n')
+
+ def get_dns_servers(self):
+ cmd = 'cat /etc/resolv.conf'
+ resolve_file = self.exec_command(cmd).strip().split('\n')
+ entries = (l.split() for l in resolve_file)
+ dns_servers = [l[1] for l in entries
+ if len(l) and l[0] == 'nameserver']
+ return dns_servers
+
+ def send_signal(self, pid, signum):
+ cmd = 'sudo /bin/kill -{sig} {pid}'.format(pid=pid, sig=signum)
+ return self.exec_command(cmd)
+
+ def _renew_lease_udhcpc(self, fixed_ip=None):
+ """Renews DHCP lease via udhcpc client. """
+ file_path = '/var/run/udhcpc.'
+ nic_name = self.get_nic_name(fixed_ip)
+ nic_name = nic_name.strip().lower()
+ pid = self.exec_command('cat {path}{nic}.pid'.
+ format(path=file_path, nic=nic_name))
+ pid = pid.strip()
+ self.send_signal(pid, 'USR1')
+
+ def _renew_lease_dhclient(self, fixed_ip=None):
+ """Renews DHCP lease via dhclient client. """
+ cmd = "sudo /sbin/dhclient -r && /sbin/dhclient"
+ self.exec_command(cmd)
+
+ def renew_lease(self, fixed_ip=None):
+ """Wrapper method for renewing DHCP lease via given client
+
+ Supporting:
+ * udhcpc
+ * dhclient
+ """
+ # TODO(yfried): add support for dhcpcd
+ suported_clients = ['udhcpc', 'dhclient']
+ dhcp_client = CONF.scenario.dhcp_client
+ if dhcp_client not in suported_clients:
+ raise exceptions.InvalidConfiguration('%s DHCP client unsupported'
+ % dhcp_client)
+ if dhcp_client == 'udhcpc' and not fixed_ip:
+ raise ValueError("need to set 'fixed_ip' for udhcpc client")
+ return getattr(self, '_renew_lease_' + dhcp_client)(fixed_ip=fixed_ip)
\ No newline at end of file
diff --git a/tempest/config.py b/tempest/config.py
index 4858fda..dd693e5 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -59,6 +59,9 @@
"It requires at least `2 * CONC` distinct accounts "
"configured in `test_accounts_file`, with CONC == the "
"number of concurrent test processes."),
+ cfg.ListOpt('tempest_roles',
+ help="Roles to assign to all users created by tempest",
+ default=[])
]
identity_group = cfg.OptGroup(name='identity',
@@ -131,9 +134,6 @@
cfg.StrOpt('admin_domain_name',
help="Admin domain name for authentication (Keystone V3)."
"The same domain applies to user and project"),
- cfg.ListOpt('tempest_roles',
- help="Roles to assign to all users created by tempest",
- default=[])
]
identity_feature_group = cfg.OptGroup(name='identity-feature-enabled',
@@ -860,7 +860,14 @@
'large_ops_number',
default=0,
help="specifies how many resources to request at once. Used "
- "for large operations testing.")
+ "for large operations testing."),
+ # TODO(yfried): add support for dhcpcd
+ cfg.StrOpt('dhcp_client',
+ default='udhcpc',
+ choices=["udhcpc", "dhclient"],
+ help='DHCP client used by images to renew DCHP lease. '
+ 'If left empty, update operation will be skipped. '
+ 'Supported clients: "udhcpc", "dhclient"')
]
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 9b2b4d4..86f488a 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -51,10 +51,6 @@
pass
-class RFCViolation(RestClientException):
- message = "RFC Violation"
-
-
class InvalidConfiguration(TempestException):
message = "Invalid Configuration"
@@ -63,18 +59,6 @@
message = "Invalid Credentials"
-class InvalidHttpSuccessCode(RestClientException):
- message = "The success code is different than the expected one"
-
-
-class NotFound(RestClientException):
- message = "Object not found"
-
-
-class Unauthorized(RestClientException):
- message = 'Unauthorized'
-
-
class InvalidServiceTag(TempestException):
message = "Invalid service tag"
@@ -123,15 +107,7 @@
"'%(resource_status_reason)s'")
-class BadRequest(RestClientException):
- message = "Bad request"
-
-
-class UnprocessableEntity(RestClientException):
- message = "Unprocessable entity"
-
-
-class AuthenticationFailure(RestClientException):
+class AuthenticationFailure(TempestException):
message = ("Authentication with user %(user)s and password "
"%(password)s failed auth using tenant %(tenant)s.")
@@ -140,22 +116,6 @@
message = "Endpoint not found"
-class RateLimitExceeded(RestClientException):
- message = "Rate limit exceeded"
-
-
-class OverLimit(RestClientException):
- message = "Quota exceeded"
-
-
-class ServerFault(RestClientException):
- message = "Got server fault"
-
-
-class NotImplemented(RestClientException):
- message = "Got NotImplemented error"
-
-
class ImageFault(TempestException):
message = "Got image fault"
@@ -164,10 +124,6 @@
message = "Got identity error"
-class Conflict(RestClientException):
- message = "An object with that identifier already exists"
-
-
class SSHTimeout(TempestException):
message = ("Connection to the %(host)s via SSH timed out.\n"
"User: %(user)s, Password: %(password)s")
@@ -187,6 +143,50 @@
message = "%(num)d cleanUp operation failed"
+class RFCViolation(RestClientException):
+ message = "RFC Violation"
+
+
+class InvalidHttpSuccessCode(RestClientException):
+ message = "The success code is different than the expected one"
+
+
+class NotFound(RestClientException):
+ message = "Object not found"
+
+
+class Unauthorized(RestClientException):
+ message = 'Unauthorized'
+
+
+class BadRequest(RestClientException):
+ message = "Bad request"
+
+
+class UnprocessableEntity(RestClientException):
+ message = "Unprocessable entity"
+
+
+class RateLimitExceeded(RestClientException):
+ message = "Rate limit exceeded"
+
+
+class OverLimit(RestClientException):
+ message = "Quota exceeded"
+
+
+class ServerFault(RestClientException):
+ message = "Got server fault"
+
+
+class NotImplemented(RestClientException):
+ message = "Got NotImplemented error"
+
+
+class Conflict(RestClientException):
+ message = "An object with that identifier already exists"
+
+
class ResponseWithNonEmptyBody(RFCViolation):
message = ("RFC Violation! Response with %(status)d HTTP Status Code "
"MUST NOT have a body")
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 220a7e7..1fdd26a 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -1012,12 +1012,16 @@
router.update(admin_state_up=admin_state_up)
self.assertEqual(admin_state_up, router.admin_state_up)
- def create_networks(self, client=None, tenant_id=None):
+ def create_networks(self, client=None, tenant_id=None,
+ dns_nameservers=None):
"""Create a network with a subnet connected to a router.
The baremetal driver is a special case since all nodes are
on the same shared network.
+ :param client: network client to create resources with.
+ :param tenant_id: id of tenant to create resources in.
+ :param dns_nameservers: list of dns servers to send to subnet.
:returns: network, subnet, router
"""
if CONF.baremetal.driver_enabled:
@@ -1033,7 +1037,12 @@
else:
network = self._create_network(client=client, tenant_id=tenant_id)
router = self._get_router(client=client, tenant_id=tenant_id)
- subnet = self._create_subnet(network=network, client=client)
+
+ subnet_kwargs = dict(network=network, client=client)
+ # use explicit check because empty list is a valid option
+ if dns_nameservers is not None:
+ subnet_kwargs['dns_nameservers'] = dns_nameservers
+ subnet = self._create_subnet(**subnet_kwargs)
subnet.add_to_router(router.id)
return network, subnet, router
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 75769ce..469ac4a 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -43,7 +43,7 @@
return cls.admin_credentials()
def _create_aggregate(self, **kwargs):
- _, aggregate = self.aggregates_client.create_aggregate(**kwargs)
+ aggregate = self.aggregates_client.create_aggregate(**kwargs)
self.addCleanup(self._delete_aggregate, aggregate)
aggregate_name = kwargs['name']
availability_zone = kwargs['availability_zone']
@@ -55,23 +55,23 @@
self.aggregates_client.delete_aggregate(aggregate['id'])
def _get_host_name(self):
- _, hosts = self.hosts_client.list_hosts()
+ hosts = self.hosts_client.list_hosts()
self.assertTrue(len(hosts) >= 1)
computes = [x for x in hosts if x['service'] == 'compute']
return computes[0]['host_name']
def _add_host(self, aggregate_id, host):
- _, aggregate = self.aggregates_client.add_host(aggregate_id, host)
+ aggregate = self.aggregates_client.add_host(aggregate_id, host)
self.addCleanup(self._remove_host, aggregate['id'], host)
self.assertIn(host, aggregate['hosts'])
def _remove_host(self, aggregate_id, host):
- _, aggregate = self.aggregates_client.remove_host(aggregate_id, host)
+ aggregate = self.aggregates_client.remove_host(aggregate_id, host)
self.assertNotIn(host, aggregate['hosts'])
def _check_aggregate_details(self, aggregate, aggregate_name, azone,
hosts, metadata):
- _, aggregate = self.aggregates_client.get_aggregate(aggregate['id'])
+ aggregate = self.aggregates_client.get_aggregate(aggregate['id'])
self.assertEqual(aggregate_name, aggregate['name'])
self.assertEqual(azone, aggregate['availability_zone'])
self.assertEqual(hosts, aggregate['hosts'])
@@ -81,15 +81,15 @@
aggregate['metadata'][meta_key])
def _set_aggregate_metadata(self, aggregate, meta):
- _, aggregate = self.aggregates_client.set_metadata(aggregate['id'],
- meta)
+ aggregate = self.aggregates_client.set_metadata(aggregate['id'],
+ meta)
for key, value in meta.items():
self.assertEqual(meta[key], aggregate['metadata'][key])
def _update_aggregate(self, aggregate, aggregate_name,
availability_zone):
- _, aggregate = self.aggregates_client.update_aggregate(
+ aggregate = self.aggregates_client.update_aggregate(
aggregate['id'], name=aggregate_name,
availability_zone=availability_zone)
self.assertEqual(aggregate['name'], aggregate_name)
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 30c3b9d..2cfec14 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -100,10 +100,10 @@
self.keypairs = {}
self.servers = []
- def _setup_network_and_servers(self):
+ def _setup_network_and_servers(self, **kwargs):
self.security_group = \
self._create_security_group(tenant_id=self.tenant_id)
- self.network, self.subnet, self.router = self.create_networks()
+ self.network, self.subnet, self.router = self.create_networks(**kwargs)
self.check_networks()
name = data_utils.rand_name('server-smoke')
@@ -425,3 +425,62 @@
self.check_public_network_connectivity(
should_connect=True, msg="after updating "
"admin_state_up of router to True")
+
+ def _check_dns_server(self, ssh_client, dns_servers):
+ servers = ssh_client.get_dns_servers()
+ self.assertEqual(set(dns_servers), set(servers),
+ 'Looking for servers: {trgt_serv}. '
+ 'Retrieved DNS nameservers: {act_serv} '
+ 'From host: {host}.'
+ .format(host=ssh_client.ssh_client.host,
+ act_serv=servers,
+ trgt_serv=dns_servers))
+
+ @testtools.skipUnless(CONF.scenario.dhcp_client,
+ "DHCP client is not available.")
+ @test.attr(type='smoke')
+ @test.services('compute', 'network')
+ def test_subnet_details(self):
+ """Tests that subnet's extra configuration details are affecting
+ the VMs
+
+ NOTE: Neutron subnets push data to servers via dhcp-agent, so any
+ update in subnet requires server to actively renew its DHCP lease.
+
+ 1. Configure subnet with dns nameserver
+ 2. retrieve the VM's configured dns and verify it matches the one
+ configured for the subnet.
+ 3. update subnet's dns
+ 4. retrieve the VM's configured dns and verify it matches the new one
+ configured for the subnet.
+
+ TODO(yfried): add host_routes
+
+ any resolution check would be testing either:
+ * l3 forwarding (tested in test_network_basic_ops)
+ * Name resolution of an external DNS nameserver - out of scope for
+ Tempest
+ """
+ # this test check only updates (no actual resolution) so using
+ # arbitrary ip addresses as nameservers, instead of parsing CONF
+ initial_dns_server = '1.2.3.4'
+ alt_dns_server = '9.8.7.6'
+ self._setup_network_and_servers(dns_nameservers=[initial_dns_server])
+ self.check_public_network_connectivity(should_connect=True)
+
+ floating_ip, server = self.floating_ip_tuple
+ ip_address = floating_ip.floating_ip_address
+ private_key = self._get_server_key(server)
+ ssh_client = self._ssh_to_server(ip_address, private_key)
+
+ self._check_dns_server(ssh_client, [initial_dns_server])
+
+ self.subnet.update(dns_nameservers=[alt_dns_server])
+ # asserts that Neutron DB has updated the nameservers
+ self.assertEqual([alt_dns_server], self.subnet.dns_nameservers,
+ "Failed to update subnet's nameservers")
+
+ # server needs to renew its dhcp lease in order to get the new dns
+ # definitions from subnet
+ ssh_client.renew_lease(fixed_ip=floating_ip['fixed_ip_address'])
+ self._check_dns_server(ssh_client, [alt_dns_server])
diff --git a/tempest/services/compute/json/agents_client.py b/tempest/services/compute/json/agents_client.py
index eacd367..95d7880 100644
--- a/tempest/services/compute/json/agents_client.py
+++ b/tempest/services/compute/json/agents_client.py
@@ -17,6 +17,7 @@
from tempest.api_schema.response.compute import agents as common_schema
from tempest.api_schema.response.compute.v2 import agents as schema
+from tempest.common import service_client
from tempest.services.compute.json import base
@@ -33,7 +34,7 @@
resp, body = self.get(url)
body = json.loads(body)
self.validate_response(common_schema.list_agents, resp, body)
- return resp, body['agents']
+ return service_client.ResponseBodyList(resp, body['agents'])
def create_agent(self, **kwargs):
"""Create an agent build."""
@@ -41,16 +42,16 @@
resp, body = self.post('os-agents', post_body)
body = json.loads(body)
self.validate_response(schema.create_agent, resp, body)
- return resp, body['agent']
+ return service_client.ResponseBody(resp, body['agent'])
def delete_agent(self, agent_id):
"""Delete an existing agent build."""
resp, body = self.delete("os-agents/%s" % str(agent_id))
self.validate_response(schema.delete_agent, resp, body)
- return resp, body
+ return service_client.ResponseBody(resp, body)
def update_agent(self, agent_id, **kwargs):
"""Update an agent build."""
put_body = json.dumps({'para': kwargs})
resp, body = self.put('os-agents/%s' % str(agent_id), put_body)
- return resp, self._parse_resp(body)
+ return service_client.ResponseBody(resp, self._parse_resp(body))
diff --git a/tempest/services/compute/json/aggregates_client.py b/tempest/services/compute/json/aggregates_client.py
index 1539259..47dd401 100644
--- a/tempest/services/compute/json/aggregates_client.py
+++ b/tempest/services/compute/json/aggregates_client.py
@@ -17,6 +17,7 @@
from tempest.api_schema.response.compute import aggregates as schema
from tempest.api_schema.response.compute.v2 import aggregates as v2_schema
+from tempest.common import service_client
from tempest import exceptions
from tempest.services.compute.json import base
@@ -28,14 +29,14 @@
resp, body = self.get("os-aggregates")
body = json.loads(body)
self.validate_response(schema.list_aggregates, resp, body)
- return resp, body['aggregates']
+ return service_client.ResponseBodyList(resp, body['aggregates'])
def get_aggregate(self, aggregate_id):
"""Get details of the given aggregate."""
resp, body = self.get("os-aggregates/%s" % str(aggregate_id))
body = json.loads(body)
self.validate_response(schema.get_aggregate, resp, body)
- return resp, body['aggregate']
+ return service_client.ResponseBody(resp, body['aggregate'])
def create_aggregate(self, **kwargs):
"""Creates a new aggregate."""
@@ -44,7 +45,7 @@
body = json.loads(body)
self.validate_response(v2_schema.create_aggregate, resp, body)
- return resp, body['aggregate']
+ return service_client.ResponseBody(resp, body['aggregate'])
def update_aggregate(self, aggregate_id, name, availability_zone=None):
"""Update a aggregate."""
@@ -57,13 +58,13 @@
body = json.loads(body)
self.validate_response(schema.update_aggregate, resp, body)
- return resp, body['aggregate']
+ return service_client.ResponseBody(resp, body['aggregate'])
def delete_aggregate(self, aggregate_id):
"""Deletes the given aggregate."""
resp, body = self.delete("os-aggregates/%s" % str(aggregate_id))
self.validate_response(v2_schema.delete_aggregate, resp, body)
- return resp, body
+ return service_client.ResponseBody(resp, body)
def is_resource_deleted(self, id):
try:
@@ -87,7 +88,7 @@
post_body)
body = json.loads(body)
self.validate_response(schema.aggregate_add_remove_host, resp, body)
- return resp, body['aggregate']
+ return service_client.ResponseBody(resp, body['aggregate'])
def remove_host(self, aggregate_id, host):
"""Removes a host from the given aggregate."""
@@ -99,7 +100,7 @@
post_body)
body = json.loads(body)
self.validate_response(schema.aggregate_add_remove_host, resp, body)
- return resp, body['aggregate']
+ return service_client.ResponseBody(resp, body['aggregate'])
def set_metadata(self, aggregate_id, meta):
"""Replaces the aggregate's existing metadata with new metadata."""
@@ -111,4 +112,4 @@
post_body)
body = json.loads(body)
self.validate_response(schema.aggregate_set_metadata, resp, body)
- return resp, body['aggregate']
+ return service_client.ResponseBody(resp, body['aggregate'])
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index 5d306f9..f4e1f12 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -17,6 +17,7 @@
from tempest.api_schema.response.compute import hosts as schema
from tempest.api_schema.response.compute.v2 import hosts as v2_schema
+from tempest.common import service_client
from tempest.services.compute.json import base
@@ -32,7 +33,7 @@
resp, body = self.get(url)
body = json.loads(body)
self.validate_response(schema.list_hosts, resp, body)
- return resp, body['hosts']
+ return service_client.ResponseBodyList(resp, body['hosts'])
def show_host_detail(self, hostname):
"""Show detail information for the host."""
@@ -40,7 +41,7 @@
resp, body = self.get("os-hosts/%s" % str(hostname))
body = json.loads(body)
self.validate_response(schema.show_host_detail, resp, body)
- return resp, body['host']
+ return service_client.ResponseBodyList(resp, body['host'])
def update_host(self, hostname, **kwargs):
"""Update a host."""
@@ -55,7 +56,7 @@
resp, body = self.put("os-hosts/%s" % str(hostname), request_body)
body = json.loads(body)
self.validate_response(v2_schema.update_host, resp, body)
- return resp, body
+ return service_client.ResponseBody(resp, body)
def startup_host(self, hostname):
"""Startup a host."""
@@ -63,7 +64,7 @@
resp, body = self.get("os-hosts/%s/startup" % str(hostname))
body = json.loads(body)
self.validate_response(v2_schema.startup_host, resp, body)
- return resp, body['host']
+ return service_client.ResponseBody(resp, body['host'])
def shutdown_host(self, hostname):
"""Shutdown a host."""
@@ -71,7 +72,7 @@
resp, body = self.get("os-hosts/%s/shutdown" % str(hostname))
body = json.loads(body)
self.validate_response(v2_schema.shutdown_host, resp, body)
- return resp, body['host']
+ return service_client.ResponseBody(resp, body['host'])
def reboot_host(self, hostname):
"""reboot a host."""
@@ -79,4 +80,4 @@
resp, body = self.get("os-hosts/%s/reboot" % str(hostname))
body = json.loads(body)
self.validate_response(v2_schema.reboot_host, resp, body)
- return resp, body['host']
+ return service_client.ResponseBody(resp, body['host'])
diff --git a/tempest/services/compute/json/hypervisor_client.py b/tempest/services/compute/json/hypervisor_client.py
index 52b50c8..37be874 100644
--- a/tempest/services/compute/json/hypervisor_client.py
+++ b/tempest/services/compute/json/hypervisor_client.py
@@ -17,6 +17,7 @@
from tempest.api_schema.response.compute import hypervisors as common_schema
from tempest.api_schema.response.compute.v2 import hypervisors as v2schema
+from tempest.common import service_client
from tempest.services.compute.json import base
@@ -28,7 +29,7 @@
body = json.loads(body)
self.validate_response(common_schema.common_hypervisors_detail,
resp, body)
- return resp, body['hypervisors']
+ return service_client.ResponseBodyList(resp, body['hypervisors'])
def get_hypervisor_list_details(self):
"""Show detailed hypervisors information."""
@@ -36,7 +37,7 @@
body = json.loads(body)
self.validate_response(common_schema.common_list_hypervisors_detail,
resp, body)
- return resp, body['hypervisors']
+ return service_client.ResponseBodyList(resp, body['hypervisors'])
def get_hypervisor_show_details(self, hyper_id):
"""Display the details of the specified hypervisor."""
@@ -44,28 +45,28 @@
body = json.loads(body)
self.validate_response(common_schema.common_show_hypervisor,
resp, body)
- return resp, body['hypervisor']
+ return service_client.ResponseBody(resp, body['hypervisor'])
def get_hypervisor_servers(self, hyper_name):
"""List instances belonging to the specified hypervisor."""
resp, body = self.get('os-hypervisors/%s/servers' % hyper_name)
body = json.loads(body)
self.validate_response(v2schema.hypervisors_servers, resp, body)
- return resp, body['hypervisors']
+ return service_client.ResponseBodyList(resp, body['hypervisors'])
def get_hypervisor_stats(self):
"""Get hypervisor statistics over all compute nodes."""
resp, body = self.get('os-hypervisors/statistics')
body = json.loads(body)
self.validate_response(common_schema.hypervisor_statistics, resp, body)
- return resp, body['hypervisor_statistics']
+ return service_client.ResponseBody(resp, body['hypervisor_statistics'])
def get_hypervisor_uptime(self, hyper_id):
"""Display the uptime of the specified hypervisor."""
resp, body = self.get('os-hypervisors/%s/uptime' % hyper_id)
body = json.loads(body)
self.validate_response(common_schema.hypervisor_uptime, resp, body)
- return resp, body['hypervisor']
+ return service_client.ResponseBody(resp, body['hypervisor'])
def search_hypervisor(self, hyper_name):
"""Search specified hypervisor."""
@@ -73,4 +74,4 @@
body = json.loads(body)
self.validate_response(common_schema.common_hypervisors_detail,
resp, body)
- return resp, body['hypervisors']
+ return service_client.ResponseBodyList(resp, body['hypervisors'])
diff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py
index 8d73c37..52662fa 100644
--- a/tempest/services/compute/json/services_client.py
+++ b/tempest/services/compute/json/services_client.py
@@ -18,6 +18,7 @@
import urllib
from tempest.api_schema.response.compute import services as schema
+from tempest.common import service_client
from tempest.services.compute.json import base
@@ -31,7 +32,7 @@
resp, body = self.get(url)
body = json.loads(body)
self.validate_response(schema.list_services, resp, body)
- return resp, body['services']
+ return service_client.ResponseBodyList(resp, body['services'])
def enable_service(self, host_name, binary):
"""
@@ -43,7 +44,7 @@
resp, body = self.put('os-services/enable', post_body)
body = json.loads(body)
self.validate_response(schema.enable_service, resp, body)
- return resp, body['service']
+ return service_client.ResponseBody(resp, body['service'])
def disable_service(self, host_name, binary):
"""
@@ -54,4 +55,4 @@
post_body = json.dumps({'binary': binary, 'host': host_name})
resp, body = self.put('os-services/disable', post_body)
body = json.loads(body)
- return resp, body['service']
+ return service_client.ResponseBody(resp, body['service'])
diff --git a/tempest/services/network/resources.py b/tempest/services/network/resources.py
index 513d2cf..4d45515 100644
--- a/tempest/services/network/resources.py
+++ b/tempest/services/network/resources.py
@@ -82,8 +82,10 @@
self._router_ids = set()
def update(self, *args, **kwargs):
- result = self.client.update_subnet(subnet=self.id, *args, **kwargs)
- super(DeletableSubnet, self).update(**result['subnet'])
+ result = self.client.update_subnet(self.id,
+ *args,
+ **kwargs)
+ return super(DeletableSubnet, self).update(**result['subnet'])
def add_to_router(self, router_id):
self._router_ids.add(router_id)
diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py
index 5574198..c813977 100644
--- a/tempest/services/orchestration/json/orchestration_client.py
+++ b/tempest/services/orchestration/json/orchestration_client.py
@@ -19,23 +19,11 @@
import urllib
from tempest.common import service_client
-from tempest import config
from tempest import exceptions
-CONF = config.CONF
-
class OrchestrationClient(service_client.ServiceClient):
- def __init__(self, auth_provider):
- super(OrchestrationClient, self).__init__(
- auth_provider,
- CONF.orchestration.catalog_type,
- CONF.orchestration.region or CONF.identity.region,
- endpoint_type=CONF.orchestration.endpoint_type,
- build_interval=CONF.orchestration.build_interval,
- build_timeout=CONF.orchestration.build_timeout)
-
def list_stacks(self, params=None):
"""Lists all stacks for a user."""
diff --git a/tempest/services/volume/json/admin/volume_quotas_client.py b/tempest/services/volume/json/admin/volume_quotas_client.py
index 1a21a2c..88df69f 100644
--- a/tempest/services/volume/json/admin/volume_quotas_client.py
+++ b/tempest/services/volume/json/admin/volume_quotas_client.py
@@ -75,6 +75,7 @@
"""Delete the tenant's quota set."""
resp, body = self.delete('os-quota-sets/%s' % tenant_id)
self.expected_success(200, resp.status)
+ return service_client.ResponseBody(resp, body)
class VolumeQuotasClientJSON(BaseVolumeQuotasClientJSON):
diff --git a/tempest/services/volume/json/admin/volume_types_client.py b/tempest/services/volume/json/admin/volume_types_client.py
index 67f12d6..b3b4ae6 100644
--- a/tempest/services/volume/json/admin/volume_types_client.py
+++ b/tempest/services/volume/json/admin/volume_types_client.py
@@ -91,6 +91,7 @@
"""Deletes the Specified Volume_type."""
resp, body = self.delete("types/%s" % str(volume_id))
self.expected_success(202, resp.status)
+ return service_client.ResponseBody(resp, body)
def list_volume_types_extra_specs(self, vol_type_id, params=None):
"""List all the volume_types extra specs created."""
@@ -130,6 +131,7 @@
resp, body = self.delete("types/%s/extra_specs/%s" % (
(str(vol_id)), str(extra_spec_name)))
self.expected_success(202, resp.status)
+ return service_client.ResponseBody(resp, body)
def update_volume_type_extra_specs(self, vol_type_id, extra_spec_name,
extra_spec):
@@ -183,6 +185,7 @@
resp, body = self.delete(
"/types/%s/encryption/provider" % str(vol_type_id))
self.expected_success(202, resp.status)
+ return service_client.ResponseBody(resp, body)
class VolumeTypesClientJSON(BaseVolumeTypesClientJSON):
diff --git a/tempest/services/volume/json/qos_client.py b/tempest/services/volume/json/qos_client.py
index f14c8b4..32555eb 100644
--- a/tempest/services/volume/json/qos_client.py
+++ b/tempest/services/volume/json/qos_client.py
@@ -85,6 +85,7 @@
resp, body = self.delete(
"qos-specs/%s?force=%s" % (str(qos_id), force))
self.expected_success(202, resp.status)
+ return service_client.ResponseBody(resp, body)
def list_qos(self):
"""List all the QoS specifications created."""
@@ -119,15 +120,17 @@
keys : it is the array of the keys to unset
"""
put_body = json.dumps({'keys': keys})
- resp, _ = self.put('qos-specs/%s/delete_keys' % qos_id, put_body)
+ resp, body = self.put('qos-specs/%s/delete_keys' % qos_id, put_body)
self.expected_success(202, resp.status)
+ return service_client.ResponseBody(resp, body)
def associate_qos(self, qos_id, vol_type_id):
"""Associate the specified QoS with specified volume-type."""
url = "qos-specs/%s/associate" % str(qos_id)
url += "?vol_type_id=%s" % vol_type_id
- resp, _ = self.get(url)
+ resp, body = self.get(url)
self.expected_success(202, resp.status)
+ return service_client.ResponseBody(resp, body)
def get_association_qos(self, qos_id):
"""Get the association of the specified QoS specification."""
@@ -141,14 +144,16 @@
"""Disassociate the specified QoS with specified volume-type."""
url = "qos-specs/%s/disassociate" % str(qos_id)
url += "?vol_type_id=%s" % vol_type_id
- resp, _ = self.get(url)
+ resp, body = self.get(url)
self.expected_success(202, resp.status)
+ return service_client.ResponseBody(resp, body)
def disassociate_all_qos(self, qos_id):
"""Disassociate the specified QoS with all associations."""
url = "qos-specs/%s/disassociate_all" % str(qos_id)
- resp, _ = self.get(url)
+ resp, body = self.get(url)
self.expected_success(202, resp.status)
+ return service_client.ResponseBody(resp, body)
class QosSpecsClientJSON(BaseQosSpecsClientJSON):
diff --git a/tempest/services/volume/json/snapshots_client.py b/tempest/services/volume/json/snapshots_client.py
index a27370d..cd115df 100644
--- a/tempest/services/volume/json/snapshots_client.py
+++ b/tempest/services/volume/json/snapshots_client.py
@@ -123,6 +123,7 @@
"""Delete Snapshot."""
resp, body = self.delete("snapshots/%s" % str(snapshot_id))
self.expected_success(202, resp.status)
+ return service_client.ResponseBody(resp, body)
def is_resource_deleted(self, id):
try:
@@ -195,6 +196,7 @@
url = "snapshots/%s/metadata/%s" % (str(snapshot_id), str(id))
resp, body = self.delete(url)
self.expected_success(200, resp.status)
+ return service_client.ResponseBody(resp, body)
def force_delete_snapshot(self, snapshot_id):
"""Force Delete Snapshot."""
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index b12852f..c0f81fe 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -102,6 +102,7 @@
"""Deletes the Specified Volume."""
resp, body = self.delete("volumes/%s" % str(volume_id))
self.expected_success(202, resp.status)
+ return service_client.ResponseBody(resp, body)
def upload_volume(self, volume_id, image_name, disk_format):
"""Uploads a volume in Glance."""
@@ -259,6 +260,7 @@
"""Delete a volume transfer."""
resp, body = self.delete("os-volume-transfer/%s" % str(transfer_id))
self.expected_success(202, resp.status)
+ return service_client.ResponseBody(resp, body)
def accept_volume_transfer(self, transfer_id, transfer_auth_key):
"""Accept a volume transfer."""
@@ -330,6 +332,7 @@
url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
resp, body = self.delete(url)
self.expected_success(200, resp.status)
+ return service_client.ResponseBody(resp, body)
class VolumesClientJSON(BaseVolumesClientJSON):
diff --git a/tempest/tests/test_rest_client.py b/tempest/tests/test_rest_client.py
deleted file mode 100644
index 6a95a80..0000000
--- a/tempest/tests/test_rest_client.py
+++ /dev/null
@@ -1,470 +0,0 @@
-# Copyright 2013 IBM Corp.
-#
-# 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 json
-
-import httplib2
-from oslotest import mockpatch
-import six
-
-from tempest.common import rest_client
-from tempest import exceptions
-from tempest.tests import base
-from tempest.tests import fake_auth_provider
-from tempest.tests import fake_http
-
-
-class BaseRestClientTestClass(base.TestCase):
-
- url = 'fake_endpoint'
-
- def setUp(self):
- super(BaseRestClientTestClass, self).setUp()
- self.rest_client = rest_client.RestClient(
- fake_auth_provider.FakeAuthProvider(), None, None)
- self.stubs.Set(httplib2.Http, 'request', self.fake_http.request)
- self.useFixture(mockpatch.PatchObject(self.rest_client,
- '_log_request'))
-
-
-class TestRestClientHTTPMethods(BaseRestClientTestClass):
- def setUp(self):
- self.fake_http = fake_http.fake_httplib2()
- super(TestRestClientHTTPMethods, self).setUp()
- self.useFixture(mockpatch.PatchObject(self.rest_client,
- '_error_checker'))
-
- def test_post(self):
- __, return_dict = self.rest_client.post(self.url, {}, {})
- self.assertEqual('POST', return_dict['method'])
-
- def test_get(self):
- __, return_dict = self.rest_client.get(self.url)
- self.assertEqual('GET', return_dict['method'])
-
- def test_delete(self):
- __, return_dict = self.rest_client.delete(self.url)
- self.assertEqual('DELETE', return_dict['method'])
-
- def test_patch(self):
- __, return_dict = self.rest_client.patch(self.url, {}, {})
- self.assertEqual('PATCH', return_dict['method'])
-
- def test_put(self):
- __, return_dict = self.rest_client.put(self.url, {}, {})
- self.assertEqual('PUT', return_dict['method'])
-
- def test_head(self):
- self.useFixture(mockpatch.PatchObject(self.rest_client,
- 'response_checker'))
- __, return_dict = self.rest_client.head(self.url)
- self.assertEqual('HEAD', return_dict['method'])
-
- def test_copy(self):
- __, return_dict = self.rest_client.copy(self.url)
- self.assertEqual('COPY', return_dict['method'])
-
-
-class TestRestClientNotFoundHandling(BaseRestClientTestClass):
- def setUp(self):
- self.fake_http = fake_http.fake_httplib2(404)
- super(TestRestClientNotFoundHandling, self).setUp()
-
- def test_post(self):
- self.assertRaises(exceptions.NotFound, self.rest_client.post,
- self.url, {}, {})
-
-
-class TestRestClientHeadersJSON(TestRestClientHTTPMethods):
- TYPE = "json"
-
- def _verify_headers(self, resp):
- self.assertEqual(self.rest_client._get_type(), self.TYPE)
- resp = dict((k.lower(), v) for k, v in six.iteritems(resp))
- self.assertEqual(self.header_value, resp['accept'])
- self.assertEqual(self.header_value, resp['content-type'])
-
- def setUp(self):
- super(TestRestClientHeadersJSON, self).setUp()
- self.rest_client.TYPE = self.TYPE
- self.header_value = 'application/%s' % self.rest_client._get_type()
-
- def test_post(self):
- resp, __ = self.rest_client.post(self.url, {})
- self._verify_headers(resp)
-
- def test_get(self):
- resp, __ = self.rest_client.get(self.url)
- self._verify_headers(resp)
-
- def test_delete(self):
- resp, __ = self.rest_client.delete(self.url)
- self._verify_headers(resp)
-
- def test_patch(self):
- resp, __ = self.rest_client.patch(self.url, {})
- self._verify_headers(resp)
-
- def test_put(self):
- resp, __ = self.rest_client.put(self.url, {})
- self._verify_headers(resp)
-
- def test_head(self):
- self.useFixture(mockpatch.PatchObject(self.rest_client,
- 'response_checker'))
- resp, __ = self.rest_client.head(self.url)
- self._verify_headers(resp)
-
- def test_copy(self):
- resp, __ = self.rest_client.copy(self.url)
- self._verify_headers(resp)
-
-
-class TestRestClientUpdateHeaders(BaseRestClientTestClass):
- def setUp(self):
- self.fake_http = fake_http.fake_httplib2()
- super(TestRestClientUpdateHeaders, self).setUp()
- self.useFixture(mockpatch.PatchObject(self.rest_client,
- '_error_checker'))
- self.headers = {'X-Configuration-Session': 'session_id'}
-
- def test_post_update_headers(self):
- __, return_dict = self.rest_client.post(self.url, {},
- extra_headers=True,
- headers=self.headers)
-
- self.assertDictContainsSubset(
- {'X-Configuration-Session': 'session_id',
- 'Content-Type': 'application/json',
- 'Accept': 'application/json'},
- return_dict['headers']
- )
-
- def test_get_update_headers(self):
- __, return_dict = self.rest_client.get(self.url,
- extra_headers=True,
- headers=self.headers)
-
- self.assertDictContainsSubset(
- {'X-Configuration-Session': 'session_id',
- 'Content-Type': 'application/json',
- 'Accept': 'application/json'},
- return_dict['headers']
- )
-
- def test_delete_update_headers(self):
- __, return_dict = self.rest_client.delete(self.url,
- extra_headers=True,
- headers=self.headers)
-
- self.assertDictContainsSubset(
- {'X-Configuration-Session': 'session_id',
- 'Content-Type': 'application/json',
- 'Accept': 'application/json'},
- return_dict['headers']
- )
-
- def test_patch_update_headers(self):
- __, return_dict = self.rest_client.patch(self.url, {},
- extra_headers=True,
- headers=self.headers)
-
- self.assertDictContainsSubset(
- {'X-Configuration-Session': 'session_id',
- 'Content-Type': 'application/json',
- 'Accept': 'application/json'},
- return_dict['headers']
- )
-
- def test_put_update_headers(self):
- __, return_dict = self.rest_client.put(self.url, {},
- extra_headers=True,
- headers=self.headers)
-
- self.assertDictContainsSubset(
- {'X-Configuration-Session': 'session_id',
- 'Content-Type': 'application/json',
- 'Accept': 'application/json'},
- return_dict['headers']
- )
-
- def test_head_update_headers(self):
- self.useFixture(mockpatch.PatchObject(self.rest_client,
- 'response_checker'))
-
- __, return_dict = self.rest_client.head(self.url,
- extra_headers=True,
- headers=self.headers)
-
- self.assertDictContainsSubset(
- {'X-Configuration-Session': 'session_id',
- 'Content-Type': 'application/json',
- 'Accept': 'application/json'},
- return_dict['headers']
- )
-
- def test_copy_update_headers(self):
- __, return_dict = self.rest_client.copy(self.url,
- extra_headers=True,
- headers=self.headers)
-
- self.assertDictContainsSubset(
- {'X-Configuration-Session': 'session_id',
- 'Content-Type': 'application/json',
- 'Accept': 'application/json'},
- return_dict['headers']
- )
-
-
-class TestRestClientParseRespJSON(BaseRestClientTestClass):
- TYPE = "json"
-
- keys = ["fake_key1", "fake_key2"]
- values = ["fake_value1", "fake_value2"]
- item_expected = dict((key, value) for (key, value) in zip(keys, values))
- list_expected = {"body_list": [
- {keys[0]: values[0]},
- {keys[1]: values[1]},
- ]}
- dict_expected = {"body_dict": {
- keys[0]: values[0],
- keys[1]: values[1],
- }}
-
- def setUp(self):
- self.fake_http = fake_http.fake_httplib2()
- super(TestRestClientParseRespJSON, self).setUp()
- self.rest_client.TYPE = self.TYPE
-
- def test_parse_resp_body_item(self):
- body = self.rest_client._parse_resp(json.dumps(self.item_expected))
- self.assertEqual(self.item_expected, body)
-
- def test_parse_resp_body_list(self):
- body = self.rest_client._parse_resp(json.dumps(self.list_expected))
- self.assertEqual(self.list_expected["body_list"], body)
-
- def test_parse_resp_body_dict(self):
- body = self.rest_client._parse_resp(json.dumps(self.dict_expected))
- self.assertEqual(self.dict_expected["body_dict"], body)
-
- def test_parse_resp_two_top_keys(self):
- dict_two_keys = self.dict_expected.copy()
- dict_two_keys.update({"second_key": ""})
- body = self.rest_client._parse_resp(json.dumps(dict_two_keys))
- self.assertEqual(dict_two_keys, body)
-
- def test_parse_resp_one_top_key_without_list_or_dict(self):
- data = {"one_top_key": "not_list_or_dict_value"}
- body = self.rest_client._parse_resp(json.dumps(data))
- self.assertEqual(data, body)
-
-
-class TestRestClientErrorCheckerJSON(base.TestCase):
- c_type = "application/json"
-
- def set_data(self, r_code, enc=None, r_body=None):
- if enc is None:
- enc = self.c_type
- resp_dict = {'status': r_code, 'content-type': enc}
- resp = httplib2.Response(resp_dict)
- data = {
- "method": "fake_method",
- "url": "fake_url",
- "headers": "fake_headers",
- "body": "fake_body",
- "resp": resp,
- "resp_body": '{"resp_body": "fake_resp_body"}',
- }
- if r_body is not None:
- data.update({"resp_body": r_body})
- return data
-
- def setUp(self):
- super(TestRestClientErrorCheckerJSON, self).setUp()
- self.rest_client = rest_client.RestClient(
- fake_auth_provider.FakeAuthProvider(), None, None)
-
- def test_response_less_than_400(self):
- self.rest_client._error_checker(**self.set_data("399"))
-
- def test_response_400(self):
- self.assertRaises(exceptions.BadRequest,
- self.rest_client._error_checker,
- **self.set_data("400"))
-
- def test_response_401(self):
- self.assertRaises(exceptions.Unauthorized,
- self.rest_client._error_checker,
- **self.set_data("401"))
-
- def test_response_403(self):
- self.assertRaises(exceptions.Unauthorized,
- self.rest_client._error_checker,
- **self.set_data("403"))
-
- def test_response_404(self):
- self.assertRaises(exceptions.NotFound,
- self.rest_client._error_checker,
- **self.set_data("404"))
-
- def test_response_409(self):
- self.assertRaises(exceptions.Conflict,
- self.rest_client._error_checker,
- **self.set_data("409"))
-
- def test_response_413(self):
- self.assertRaises(exceptions.OverLimit,
- self.rest_client._error_checker,
- **self.set_data("413"))
-
- def test_response_415(self):
- self.assertRaises(exceptions.InvalidContentType,
- self.rest_client._error_checker,
- **self.set_data("415"))
-
- def test_response_422(self):
- self.assertRaises(exceptions.UnprocessableEntity,
- self.rest_client._error_checker,
- **self.set_data("422"))
-
- def test_response_500_with_text(self):
- # _parse_resp is expected to return 'str'
- self.assertRaises(exceptions.ServerFault,
- self.rest_client._error_checker,
- **self.set_data("500"))
-
- def test_response_501_with_text(self):
- self.assertRaises(exceptions.NotImplemented,
- self.rest_client._error_checker,
- **self.set_data("501"))
-
- def test_response_500_with_dict(self):
- r_body = '{"resp_body": {"err": "fake_resp_body"}}'
- self.assertRaises(exceptions.ServerFault,
- self.rest_client._error_checker,
- **self.set_data("500", r_body=r_body))
-
- def test_response_501_with_dict(self):
- r_body = '{"resp_body": {"err": "fake_resp_body"}}'
- self.assertRaises(exceptions.NotImplemented,
- self.rest_client._error_checker,
- **self.set_data("501", r_body=r_body))
-
- def test_response_bigger_than_400(self):
- # Any response code, that bigger than 400, and not in
- # (401, 403, 404, 409, 413, 422, 500, 501)
- self.assertRaises(exceptions.UnexpectedResponseCode,
- self.rest_client._error_checker,
- **self.set_data("402"))
-
-
-class TestRestClientErrorCheckerTEXT(TestRestClientErrorCheckerJSON):
- c_type = "text/plain"
-
- def test_fake_content_type(self):
- # This test is required only in one exemplar
- # Any response code, that bigger than 400, and not in
- # (401, 403, 404, 409, 413, 422, 500, 501)
- self.assertRaises(exceptions.InvalidContentType,
- self.rest_client._error_checker,
- **self.set_data("405", enc="fake_enc"))
-
-
-class TestRestClientUtils(BaseRestClientTestClass):
-
- def _is_resource_deleted(self, resource_id):
- if not isinstance(self.retry_pass, int):
- return False
- if self.retry_count >= self.retry_pass:
- return True
- self.retry_count = self.retry_count + 1
- return False
-
- def setUp(self):
- self.fake_http = fake_http.fake_httplib2()
- super(TestRestClientUtils, self).setUp()
- self.retry_count = 0
- self.retry_pass = None
- self.original_deleted_method = self.rest_client.is_resource_deleted
- self.rest_client.is_resource_deleted = self._is_resource_deleted
-
- def test_wait_for_resource_deletion(self):
- self.retry_pass = 2
- # Ensure timeout long enough for loop execution to hit retry count
- self.rest_client.build_timeout = 500
- sleep_mock = self.patch('time.sleep')
- self.rest_client.wait_for_resource_deletion('1234')
- self.assertEqual(len(sleep_mock.mock_calls), 2)
-
- def test_wait_for_resource_deletion_not_deleted(self):
- self.patch('time.sleep')
- # Set timeout to be very quick to force exception faster
- self.rest_client.build_timeout = 1
- self.assertRaises(exceptions.TimeoutException,
- self.rest_client.wait_for_resource_deletion,
- '1234')
-
- def test_wait_for_deletion_with_unimplemented_deleted_method(self):
- self.rest_client.is_resource_deleted = self.original_deleted_method
- self.assertRaises(NotImplementedError,
- self.rest_client.wait_for_resource_deletion,
- '1234')
-
-
-class TestExpectedSuccess(BaseRestClientTestClass):
-
- def setUp(self):
- self.fake_http = fake_http.fake_httplib2()
- super(TestExpectedSuccess, self).setUp()
-
- def test_expected_succes_int_match(self):
- expected_code = 202
- read_code = 202
- resp = self.rest_client.expected_success(expected_code, read_code)
- # Assert None resp on success
- self.assertFalse(resp)
-
- def test_expected_succes_int_no_match(self):
- expected_code = 204
- read_code = 202
- self.assertRaises(exceptions.InvalidHttpSuccessCode,
- self.rest_client.expected_success,
- expected_code, read_code)
-
- def test_expected_succes_list_match(self):
- expected_code = [202, 204]
- read_code = 202
- resp = self.rest_client.expected_success(expected_code, read_code)
- # Assert None resp on success
- self.assertFalse(resp)
-
- def test_expected_succes_list_no_match(self):
- expected_code = [202, 204]
- read_code = 200
- self.assertRaises(exceptions.InvalidHttpSuccessCode,
- self.rest_client.expected_success,
- expected_code, read_code)
-
- def test_non_success_expected_int(self):
- expected_code = 404
- read_code = 202
- self.assertRaises(AssertionError, self.rest_client.expected_success,
- expected_code, read_code)
-
- def test_non_success_expected_list(self):
- expected_code = [404, 202]
- read_code = 202
- self.assertRaises(AssertionError, self.rest_client.expected_success,
- expected_code, read_code)
diff --git a/tempest/tests/test_tenant_isolation.py b/tempest/tests/test_tenant_isolation.py
index f6779c6..58a8060 100644
--- a/tempest/tests/test_tenant_isolation.py
+++ b/tempest/tests/test_tenant_isolation.py
@@ -110,7 +110,7 @@
return_value={'router': {'id': id, 'name': name}}))
return router_fix
- @mock.patch('tempest.common.rest_client.RestClient')
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_primary_creds(self, MockRestClient):
cfg.CONF.set_default('neutron', False, 'service_available')
iso_creds = isolated_creds.IsolatedCreds('test class',
@@ -126,7 +126,7 @@
self.assertEqual(primary_creds.tenant_id, '1234')
self.assertEqual(primary_creds.user_id, '1234')
- @mock.patch('tempest.common.rest_client.RestClient')
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_admin_creds(self, MockRestClient):
cfg.CONF.set_default('neutron', False, 'service_available')
iso_creds = isolated_creds.IsolatedCreds('test class',
@@ -151,7 +151,7 @@
self.assertEqual(admin_creds.tenant_id, '1234')
self.assertEqual(admin_creds.user_id, '1234')
- @mock.patch('tempest.common.rest_client.RestClient')
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_all_cred_cleanup(self, MockRestClient):
cfg.CONF.set_default('neutron', False, 'service_available')
iso_creds = isolated_creds.IsolatedCreds('test class',
@@ -195,7 +195,7 @@
self.assertIn('12345', args)
self.assertIn('123456', args)
- @mock.patch('tempest.common.rest_client.RestClient')
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_alt_creds(self, MockRestClient):
cfg.CONF.set_default('neutron', False, 'service_available')
iso_creds = isolated_creds.IsolatedCreds('test class',
@@ -211,7 +211,7 @@
self.assertEqual(alt_creds.tenant_id, '1234')
self.assertEqual(alt_creds.user_id, '1234')
- @mock.patch('tempest.common.rest_client.RestClient')
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_network_creation(self, MockRestClient):
iso_creds = isolated_creds.IsolatedCreds('test class',
password='fake_password')
@@ -237,7 +237,7 @@
self.assertEqual(router['id'], '1234')
self.assertEqual(router['name'], 'fake_router')
- @mock.patch('tempest.common.rest_client.RestClient')
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_network_cleanup(self, MockRestClient):
def side_effect(**args):
return {"security_groups": [{"tenant_id": args['tenant_id'],
@@ -360,7 +360,7 @@
self.assertIn('12345', args)
self.assertIn('123456', args)
- @mock.patch('tempest.common.rest_client.RestClient')
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_network_alt_creation(self, MockRestClient):
iso_creds = isolated_creds.IsolatedCreds('test class',
password='fake_password')
@@ -386,7 +386,7 @@
self.assertEqual(router['id'], '1234')
self.assertEqual(router['name'], 'fake_alt_router')
- @mock.patch('tempest.common.rest_client.RestClient')
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_network_admin_creation(self, MockRestClient):
iso_creds = isolated_creds.IsolatedCreds('test class',
password='fake_password')
@@ -412,7 +412,7 @@
self.assertEqual(router['id'], '1234')
self.assertEqual(router['name'], 'fake_admin_router')
- @mock.patch('tempest.common.rest_client.RestClient')
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_no_network_resources(self, MockRestClient):
net_dict = {
'network': False,
@@ -448,7 +448,7 @@
self.assertIsNone(subnet)
self.assertIsNone(router)
- @mock.patch('tempest.common.rest_client.RestClient')
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_router_without_network(self, MockRestClient):
net_dict = {
'network': False,
@@ -466,7 +466,7 @@
self.assertRaises(exceptions.InvalidConfiguration,
iso_creds.get_primary_creds)
- @mock.patch('tempest.common.rest_client.RestClient')
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_subnet_without_network(self, MockRestClient):
net_dict = {
'network': False,
@@ -484,7 +484,7 @@
self.assertRaises(exceptions.InvalidConfiguration,
iso_creds.get_primary_creds)
- @mock.patch('tempest.common.rest_client.RestClient')
+ @mock.patch('tempest_lib.common.rest_client.RestClient')
def test_dhcp_without_subnet(self, MockRestClient):
net_dict = {
'network': False,