Merge "Add an internal test method for rebooting a server"
diff --git a/HACKING.rst b/HACKING.rst
index 025bf74..29d5bf4 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -227,3 +227,48 @@
2. The unit tests cannot use setUpClass, instead fixtures and testresources
should be used for shared state between tests.
+
+
+.. _TestDocumentation:
+
+Test Documentation
+------------------
+For tests being added we need to require inline documentation in the form of
+docstings to explain what is being tested. In API tests for a new API a class
+level docstring should be added to an API reference doc. If one doesn't exist
+a TODO comment should be put indicating that the reference needs to be added.
+For individual API test cases a method level docstring should be used to
+explain the functionality being tested if the test name isn't descriptive
+enough. For example::
+
+ def test_get_role_by_id(self):
+ """Get a role by its id."""
+
+the docstring there is superfluous and shouldn't be added. but for a method
+like::
+
+ def test_volume_backup_create_get_detailed_list_restore_delete(self):
+ pass
+
+a docstring would be useful because while the test title is fairly descriptive
+the operations being performed are complex enough that a bit more explanation
+will help people figure out the intent of the test.
+
+For scenario tests a class level docstring describing the steps in the scenario
+is required. If there is more than one test case in the class individual
+docstrings for the workflow in each test methods can be used instead. A good
+example of this would be::
+
+ class TestVolumeBootPattern(manager.OfficialClientTest):
+ """
+ This test case attempts to reproduce the following steps:
+
+ * Create in Cinder some bootable volume importing a Glance image
+ * Boot an instance from the bootable volume
+ * Write content to the volume
+ * Delete an instance and Boot a new instance from the volume
+ * Check written content in the instance
+ * Create a volume snapshot while the instance is running
+ * Boot an additional instance from the new snapshot based volume
+ * Check written content in the instance booted from snapshot
+ """
diff --git a/REVIEWING.rst b/REVIEWING.rst
index d6dc83e..74bd2ad 100644
--- a/REVIEWING.rst
+++ b/REVIEWING.rst
@@ -51,6 +51,15 @@
whether to skip or not.
+Test Documentation
+------------------
+When a new test is being added refer to the :ref:`TestDocumentation` section in
+hacking to see if the requirements are being met. With the exception of a class
+level docstring linking to the API ref doc in the API tests and a docstring for
+scenario tests this is up to the reviewers discretion whether a docstring is
+required or not.
+
+
When to approve
---------------
* Every patch needs two +2s before being approved.
diff --git a/requirements.txt b/requirements.txt
index 9a3b74d..708ede3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,25 +1,28 @@
+# The order of packages is significant, because pip processes them in the order
+# of appearance. Changing the order has an impact on the overall integration
+# process, which may cause wedges in the gate later.
pbr>=0.6,!=0.7,<1.0
anyjson>=0.3.3
httplib2>=0.7.5
jsonschema>=2.0.0,<3.0.0
testtools>=0.9.34
lxml>=2.3
-boto>=2.12.0,!=2.13.0
+boto>=2.32.1
paramiko>=1.13.0
-netaddr>=0.7.6
+netaddr>=0.7.12
python-ceilometerclient>=1.0.6
-python-glanceclient>=0.13.1
-python-keystoneclient>=0.9.0
-python-novaclient>=2.17.0
-python-neutronclient>=2.3.5,<3
-python-cinderclient>=1.0.7
+python-glanceclient>=0.14.0
+python-keystoneclient>=0.10.0
+python-novaclient>=2.18.0
+python-neutronclient>=2.3.6,<3
+python-cinderclient>=1.1.0
python-heatclient>=0.2.9
-python-ironicclient
-python-saharaclient>=0.6.0
-python-swiftclient>=2.0.2
+python-ironicclient>=0.2.1
+python-saharaclient>=0.7.3
+python-swiftclient>=2.2.0
testresources>=0.2.4
testrepository>=0.0.18
-oslo.config>=1.2.1
+oslo.config>=1.4.0 # Apache-2.0
six>=1.7.0
iso8601>=0.1.9
fixtures>=0.3.14
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index 634bc01..6a5da58 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -70,6 +70,18 @@
self.assertEqual('204', resp['status'])
self.client.wait_for_server_termination(server['id'])
+ @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
+ 'Suspend is not available.')
+ @test.attr(type='gate')
+ def test_delete_server_while_in_suspended_state(self):
+ # Delete a server while it's VM state is Suspended
+ _, server = self.create_test_server(wait_until='ACTIVE')
+ self.client.suspend_server(server['id'])
+ self.client.wait_for_server_status(server['id'], 'SUSPENDED')
+ resp, _ = self.client.delete_server(server['id'])
+ self.assertEqual('204', resp['status'])
+ self.client.wait_for_server_termination(server['id'])
+
@testtools.skipUnless(CONF.compute_feature_enabled.shelve,
'Shelve is not available.')
@test.attr(type='gate')
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 6032976..98fe387 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -233,6 +233,30 @@
self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
@test.attr(type='gate')
+ def test_list_servers_filtered_by_name_regex(self):
+ # list of regex that should match s1, s2 and s3
+ regexes = ['^.*\-instance\-[0-9]+$', '^.*\-instance\-.*$']
+ for regex in regexes:
+ params = {'name': regex}
+ resp, body = self.client.list_servers(params)
+ servers = body['servers']
+
+ self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
+ self.assertIn(self.s2_name, map(lambda x: x['name'], servers))
+ self.assertIn(self.s3_name, map(lambda x: x['name'], servers))
+
+ # Let's take random part of name and try to search it
+ part_name = self.s1_name[-10:]
+
+ params = {'name': part_name}
+ resp, body = self.client.list_servers(params)
+ servers = body['servers']
+
+ self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
+ self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
+ self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
+
+ @test.attr(type='gate')
def test_list_servers_filtered_by_ip(self):
# Filter servers by ip
# Here should be listed 1 server
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index 25f24b9..a984ade 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -64,7 +64,8 @@
def resource_cleanup(cls):
# Deleting the floating IP which is created in this method
cls.floating_ips_client.delete_floating_ip(cls.floating_ip_id)
- cls.delete_volume(cls.volume['id'])
+ if getattr(cls, 'volume', None):
+ cls.delete_volume(cls.volume['id'])
resp, cls.sg = cls.security_groups_client.delete_security_group(
cls.sg_id)
super(ServerRescueTestJSON, cls).resource_cleanup()
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index aa406f7..0d29968 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -56,7 +56,8 @@
@classmethod
def resource_cleanup(cls):
- cls.delete_volume(cls.volume['id'])
+ if getattr(cls, 'volume', None):
+ cls.delete_volume(cls.volume['id'])
super(ServerRescueNegativeTestJSON, cls).resource_cleanup()
def _detach(self, server_id, volume_id):
diff --git a/tempest/api/messaging/base.py b/tempest/api/messaging/base.py
index 0e062c5..58511a9 100644
--- a/tempest/api/messaging/base.py
+++ b/tempest/api/messaging/base.py
@@ -35,8 +35,8 @@
"""
@classmethod
- def setUpClass(cls):
- super(BaseMessagingTest, cls).setUpClass()
+ def resource_setup(cls):
+ super(BaseMessagingTest, cls).resource_setup()
if not CONF.service_available.zaqar:
raise cls.skipException("Zaqar support is required")
os = cls.get_client_manager()
diff --git a/tempest/api/messaging/test_claims.py b/tempest/api/messaging/test_claims.py
index 885f00e..1b004dd 100644
--- a/tempest/api/messaging/test_claims.py
+++ b/tempest/api/messaging/test_claims.py
@@ -30,8 +30,8 @@
_interface = 'json'
@classmethod
- def setUpClass(cls):
- super(TestClaims, cls).setUpClass()
+ def resource_setup(cls):
+ super(TestClaims, cls).resource_setup()
cls.queue_name = data_utils.rand_name('Queues-Test')
# Create Queue
cls.create_queue(cls.queue_name)
@@ -118,6 +118,6 @@
self.client.delete_messages(message_uri)
@classmethod
- def tearDownClass(cls):
+ def resource_cleanup(cls):
cls.delete_queue(cls.queue_name)
- super(TestClaims, cls).tearDownClass()
+ super(TestClaims, cls).resource_cleanup()
diff --git a/tempest/api/messaging/test_messages.py b/tempest/api/messaging/test_messages.py
index 3217361..3c27ac2 100644
--- a/tempest/api/messaging/test_messages.py
+++ b/tempest/api/messaging/test_messages.py
@@ -29,8 +29,8 @@
_interface = 'json'
@classmethod
- def setUpClass(cls):
- super(TestMessages, cls).setUpClass()
+ def resource_setup(cls):
+ super(TestMessages, cls).resource_setup()
cls.queue_name = data_utils.rand_name('Queues-Test')
# Create Queue
cls.client.create_queue(cls.queue_name)
@@ -117,6 +117,6 @@
self.assertEqual('204', resp['status'])
@classmethod
- def tearDownClass(cls):
+ def resource_cleanup(cls):
cls.delete_queue(cls.queue_name)
- super(TestMessages, cls).tearDownClass()
+ super(TestMessages, cls).resource_cleanup()
diff --git a/tempest/api/messaging/test_queues.py b/tempest/api/messaging/test_queues.py
index edfe10e..ab099ff 100644
--- a/tempest/api/messaging/test_queues.py
+++ b/tempest/api/messaging/test_queues.py
@@ -44,8 +44,8 @@
_interface = 'json'
@classmethod
- def setUpClass(cls):
- super(TestManageQueue, cls).setUpClass()
+ def resource_setup(cls):
+ super(TestManageQueue, cls).resource_setup()
cls.queues = list()
for _ in moves.xrange(5):
queue_name = data_utils.rand_name('Queues-Test')
@@ -125,7 +125,7 @@
self.assertThat(body, matchers.Equals(req_body))
@classmethod
- def tearDownClass(cls):
+ def resource_cleanup(cls):
for queue_name in cls.queues:
cls.client.delete_queue(queue_name)
- super(TestManageQueue, cls).tearDownClass()
+ super(TestManageQueue, cls).resource_cleanup()
diff --git a/tempest/api/network/test_fwaas_extensions.py b/tempest/api/network/test_fwaas_extensions.py
index 193bf76..11588d6 100644
--- a/tempest/api/network/test_fwaas_extensions.py
+++ b/tempest/api/network/test_fwaas_extensions.py
@@ -86,7 +86,6 @@
(fw_id, target_states))
raise exceptions.TimeoutException(m)
- @test.attr(type='smoke')
def test_list_firewall_rules(self):
# List firewall rules
_, fw_rules = self.client.list_firewall_rules()
@@ -104,7 +103,6 @@
m['ip_version'],
m['enabled']) for m in fw_rules])
- @test.attr(type='smoke')
def test_create_update_delete_firewall_rule(self):
# Create firewall rule
_, body = self.client.create_firewall_rule(
@@ -125,14 +123,12 @@
self.assertNotIn(fw_rule_id,
[m['id'] for m in fw_rules['firewall_rules']])
- @test.attr(type='smoke')
def test_show_firewall_rule(self):
# show a created firewall rule
_, fw_rule = self.client.show_firewall_rule(self.fw_rule['id'])
for key, value in fw_rule['firewall_rule'].iteritems():
self.assertEqual(self.fw_rule[key], value)
- @test.attr(type='smoke')
def test_list_firewall_policies(self):
_, fw_policies = self.client.list_firewall_policies()
fw_policies = fw_policies['firewall_policies']
@@ -143,7 +139,6 @@
m['name'],
m['firewall_rules']) for m in fw_policies])
- @test.attr(type='smoke')
def test_create_update_delete_firewall_policy(self):
# Create firewall policy
_, body = self.client.create_firewall_policy(
@@ -166,7 +161,6 @@
fw_policies = fw_policies['firewall_policies']
self.assertNotIn(fw_policy_id, [m['id'] for m in fw_policies])
- @test.attr(type='smoke')
def test_show_firewall_policy(self):
# show a created firewall policy
_, fw_policy = self.client.show_firewall_policy(self.fw_policy['id'])
@@ -174,7 +168,6 @@
for key, value in fw_policy.iteritems():
self.assertEqual(self.fw_policy[key], value)
- @test.attr(type='smoke')
def test_create_show_delete_firewall(self):
# Create tenant network resources required for an ACTIVE firewall
network = self.create_network()
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index e1eb48d..986a2c8 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -17,6 +17,7 @@
import testtools
from tempest.api.network import base
+from tempest.common import custom_matchers
from tempest.common.utils import data_utils
from tempest import config
from tempest import exceptions
@@ -65,13 +66,94 @@
cls.name = cls.network['name']
cls.subnet = cls.create_subnet(cls.network)
cls.cidr = cls.subnet['cidr']
+ cls._subnet_data = {6: {'gateway':
+ str(cls._get_gateway_from_tempest_conf(6)),
+ 'allocation_pools':
+ cls._get_allocation_pools_from_gateway(6),
+ 'dns_nameservers': ['2001:4860:4860::8844',
+ '2001:4860:4860::8888'],
+ 'host_routes': [{'destination': '2001::/64',
+ 'nexthop': '2003::1'}],
+ 'new_host_routes': [{'destination':
+ '2001::/64',
+ 'nexthop': '2005::1'}],
+ 'new_dns_nameservers':
+ ['2001:4860:4860::7744',
+ '2001:4860:4860::7888']},
+ 4: {'gateway':
+ str(cls._get_gateway_from_tempest_conf(4)),
+ 'allocation_pools':
+ cls._get_allocation_pools_from_gateway(4),
+ 'dns_nameservers': ['8.8.4.4', '8.8.8.8'],
+ 'host_routes': [{'destination': '10.20.0.0/32',
+ 'nexthop': '10.100.1.1'}],
+ 'new_host_routes': [{'destination':
+ '10.20.0.0/32',
+ 'nexthop':
+ '10.100.1.2'}],
+ 'new_dns_nameservers': ['7.8.8.8', '7.8.4.4']}}
+
+ @classmethod
+ def _get_gateway_from_tempest_conf(cls, ip_version):
+ """Return first subnet gateway for configured CIDR """
+ if ip_version == 4:
+ cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
+ mask_bits = CONF.network.tenant_network_mask_bits
+ elif ip_version == 6:
+ cidr = netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr)
+ mask_bits = CONF.network.tenant_network_v6_mask_bits
+
+ if mask_bits >= cidr.prefixlen:
+ return netaddr.IPAddress(cidr) + 1
+ else:
+ for subnet in cidr.subnet(mask_bits):
+ return netaddr.IPAddress(subnet) + 1
+
+ @classmethod
+ def _get_allocation_pools_from_gateway(cls, ip_version):
+ """Return allocation range for subnet of given gateway"""
+ gateway = cls._get_gateway_from_tempest_conf(ip_version)
+ return [{'start': str(gateway + 2), 'end': str(gateway + 3)}]
+
+ def subnet_dict(self, include_keys):
+ """Return a subnet dict which has include_keys and their corresponding
+ value from self._subnet_data
+ """
+ return dict((key, self._subnet_data[self._ip_version][key])
+ for key in include_keys)
+
+ def _compare_resource_attrs(self, actual, expected):
+ exclude_keys = set(actual).symmetric_difference(expected)
+ self.assertThat(actual, custom_matchers.MatchesDictExceptForKeys(
+ expected, exclude_keys))
+
+ def _create_verify_delete_subnet(self, cidr=None, mask_bits=None,
+ **kwargs):
+ network = self.create_network()
+ net_id = network['id']
+ gateway = kwargs.pop('gateway', None)
+ subnet = self.create_subnet(network, gateway, cidr, mask_bits,
+ **kwargs)
+ compare_args_full = dict(gateway_ip=gateway, cidr=cidr,
+ mask_bits=mask_bits, **kwargs)
+ compare_args = dict((k, v) for k, v in compare_args_full.iteritems()
+ if v is not None)
+
+ if 'dns_nameservers' in set(subnet).intersection(compare_args):
+ self.assertEqual(sorted(compare_args['dns_nameservers']),
+ sorted(subnet['dns_nameservers']))
+ del subnet['dns_nameservers'], compare_args['dns_nameservers']
+
+ self._compare_resource_attrs(subnet, compare_args)
+ self.client.delete_network(net_id)
+ self.networks.pop()
+ self.subnets.pop()
@test.attr(type='smoke')
def test_create_update_delete_network_subnet(self):
# Create a network
name = data_utils.rand_name('network-')
- _, body = self.client.create_network(name=name)
- network = body['network']
+ network = self.create_network(network_name=name)
net_id = network['id']
self.assertEqual('ACTIVE', network['status'])
# Verify network update
@@ -87,11 +169,6 @@
_, body = self.client.update_subnet(subnet_id, name=new_name)
updated_subnet = body['subnet']
self.assertEqual(updated_subnet['name'], new_name)
- # Delete subnet and network
- _, body = self.client.delete_subnet(subnet_id)
- # Remove subnet from cleanup list
- self.subnets.pop()
- _, body = self.client.delete_network(net_id)
@test.attr(type='smoke')
def test_show_network(self):
@@ -204,32 +281,65 @@
@test.attr(type='smoke')
def test_create_delete_subnet_with_gw(self):
- gateway = '10.100.0.13'
- name = data_utils.rand_name('network-')
- _, body = self.client.create_network(name=name)
- network = body['network']
- net_id = network['id']
- subnet = self.create_subnet(network, gateway)
- # Verifies Subnet GW in IPv4
- self.assertEqual(subnet['gateway_ip'], gateway)
- # Delete network and subnet
- self.client.delete_network(net_id)
- self.subnets.pop()
+ self._create_verify_delete_subnet(
+ **self.subnet_dict(['gateway']))
@test.attr(type='smoke')
- def test_create_delete_subnet_without_gw(self):
- net = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
- gateway_ip = str(netaddr.IPAddress(net.first + 1))
- name = data_utils.rand_name('network-')
- _, body = self.client.create_network(name=name)
- network = body['network']
- net_id = network['id']
- subnet = self.create_subnet(network)
- # Verifies Subnet GW in IPv4
- self.assertEqual(subnet['gateway_ip'], gateway_ip)
- # Delete network and subnet
- self.client.delete_network(net_id)
- self.subnets.pop()
+ def test_create_delete_subnet_with_allocation_pools(self):
+ self._create_verify_delete_subnet(
+ **self.subnet_dict(['allocation_pools']))
+
+ @test.attr(type='smoke')
+ def test_create_delete_subnet_with_gw_and_allocation_pools(self):
+ self._create_verify_delete_subnet(**self.subnet_dict(
+ ['gateway', 'allocation_pools']))
+
+ @test.attr(type='smoke')
+ def test_create_delete_subnet_with_host_routes_and_dns_nameservers(self):
+ self._create_verify_delete_subnet(
+ **self.subnet_dict(['host_routes', 'dns_nameservers']))
+
+ @test.attr(type='smoke')
+ def test_create_delete_subnet_with_dhcp_enabled(self):
+ self._create_verify_delete_subnet(enable_dhcp=True)
+
+ @test.attr(type='smoke')
+ def test_update_subnet_gw_dns_host_routes_dhcp(self):
+ network = self.create_network()
+
+ subnet = self.create_subnet(
+ network, **self.subnet_dict(['gateway', 'host_routes',
+ 'dns_nameservers',
+ 'allocation_pools']))
+ subnet_id = subnet['id']
+ new_gateway = str(netaddr.IPAddress(
+ self._subnet_data[self._ip_version]['gateway']) + 1)
+ # Verify subnet update
+ new_host_routes = self._subnet_data[self._ip_version][
+ 'new_host_routes']
+
+ new_dns_nameservers = self._subnet_data[self._ip_version][
+ 'new_dns_nameservers']
+ kwargs = {'host_routes': new_host_routes,
+ 'dns_nameservers': new_dns_nameservers,
+ 'gateway_ip': new_gateway, 'enable_dhcp': True}
+
+ new_name = "New_subnet"
+ _, body = self.client.update_subnet(subnet_id, name=new_name,
+ **kwargs)
+ updated_subnet = body['subnet']
+ kwargs['name'] = new_name
+ self.assertEqual(sorted(updated_subnet['dns_nameservers']),
+ sorted(kwargs['dns_nameservers']))
+ del subnet['dns_nameservers'], kwargs['dns_nameservers']
+
+ self._compare_resource_attrs(updated_subnet, kwargs)
+
+ @test.attr(type='smoke')
+ def test_create_delete_subnet_all_attributes(self):
+ self._create_verify_delete_subnet(
+ enable_dhcp=True,
+ **self.subnet_dict(['gateway', 'host_routes', 'dns_nameservers']))
class NetworksTestXML(NetworksTestJSON):
@@ -376,51 +486,30 @@
net = netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr)
gateway = str(netaddr.IPAddress(net.first + 2))
name = data_utils.rand_name('network-')
- _, body = self.client.create_network(name=name)
- network = body['network']
- net_id = network['id']
+ network = self.create_network(network_name=name)
subnet = self.create_subnet(network, gateway)
# Verifies Subnet GW in IPv6
self.assertEqual(subnet['gateway_ip'], gateway)
- # Delete network and subnet
- self.client.delete_network(net_id)
- self.subnets.pop()
@test.attr(type='smoke')
def test_create_delete_subnet_without_gw(self):
net = netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr)
gateway_ip = str(netaddr.IPAddress(net.first + 1))
name = data_utils.rand_name('network-')
- _, body = self.client.create_network(name=name)
- network = body['network']
- net_id = network['id']
+ network = self.create_network(network_name=name)
subnet = self.create_subnet(network)
# Verifies Subnet GW in IPv6
self.assertEqual(subnet['gateway_ip'], gateway_ip)
- # Delete network and subnet
- _, body = self.client.delete_network(net_id)
- self.subnets.pop()
@testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
"IPv6 extended attributes for subnets not "
"available")
@test.attr(type='smoke')
def test_create_delete_subnet_with_v6_attributes(self):
- name = data_utils.rand_name('network-')
- _, body = self.client.create_network(name=name)
- network = body['network']
- net_id = network['id']
- subnet = self.create_subnet(network,
- gateway='fe80::1',
- ipv6_ra_mode='slaac',
- ipv6_address_mode='slaac')
- # Verifies Subnet GW in IPv6
- self.assertEqual(subnet['gateway_ip'], 'fe80::1')
- self.assertEqual(subnet['ipv6_ra_mode'], 'slaac')
- self.assertEqual(subnet['ipv6_address_mode'], 'slaac')
- # Delete network and subnet
- self.client.delete_network(net_id)
- self.subnets.pop()
+ self._create_verify_delete_subnet(
+ gateway=self._subnet_data[self._ip_version]['gateway'],
+ ipv6_ra_mode='slaac',
+ ipv6_address_mode='slaac')
class NetworksIpV6TestXML(NetworksIpV6TestJSON):
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
index 0b22de5..5a586fc 100644
--- a/tempest/api/orchestration/base.py
+++ b/tempest/api/orchestration/base.py
@@ -30,8 +30,8 @@
"""Base test case class for all Orchestration API tests."""
@classmethod
- def setUpClass(cls):
- super(BaseOrchestrationTest, cls).setUpClass()
+ def resource_setup(cls):
+ super(BaseOrchestrationTest, cls).resource_setup()
cls.os = clients.Manager()
if not CONF.service_available.heat:
raise cls.skipException("Heat support is required")
@@ -146,11 +146,11 @@
return yaml.safe_load(f)
@classmethod
- def tearDownClass(cls):
+ def resource_cleanup(cls):
cls._clear_stacks()
cls._clear_keypairs()
cls._clear_images()
- super(BaseOrchestrationTest, cls).tearDownClass()
+ super(BaseOrchestrationTest, cls).resource_cleanup()
@staticmethod
def stack_output(stack, output_key):
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index ffadb16..f1a4f85 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -30,9 +30,8 @@
class NeutronResourcesTestJSON(base.BaseOrchestrationTest):
@classmethod
- @test.safe_setup
- def setUpClass(cls):
- super(NeutronResourcesTestJSON, cls).setUpClass()
+ def resource_setup(cls):
+ super(NeutronResourcesTestJSON, cls).resource_setup()
if not CONF.orchestration.image_ref:
raise cls.skipException("No image available to test")
os = clients.Manager()
diff --git a/tempest/api/orchestration/stacks/test_non_empty_stack.py b/tempest/api/orchestration/stacks/test_non_empty_stack.py
index 72ad5f5..759cbbe 100644
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ b/tempest/api/orchestration/stacks/test_non_empty_stack.py
@@ -25,8 +25,8 @@
class StacksTestJSON(base.BaseOrchestrationTest):
@classmethod
- def setUpClass(cls):
- super(StacksTestJSON, cls).setUpClass()
+ def resource_setup(cls):
+ super(StacksTestJSON, cls).resource_setup()
cls.stack_name = data_utils.rand_name('heat')
template = cls.read_template('non_empty_stack')
image_id = (CONF.orchestration.image_ref or
diff --git a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
index 2f58611..1da340c 100644
--- a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
+++ b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
@@ -27,8 +27,8 @@
_type = 'type'
@classmethod
- def setUpClass(cls):
- super(NovaKeyPairResourcesYAMLTest, cls).setUpClass()
+ def resource_setup(cls):
+ super(NovaKeyPairResourcesYAMLTest, cls).resource_setup()
cls.stack_name = data_utils.rand_name('heat')
template = cls.read_template('nova_keypair', ext=cls._tpl_type)
diff --git a/tempest/api/orchestration/stacks/test_stacks.py b/tempest/api/orchestration/stacks/test_stacks.py
index 8023f2c..d7fbd65 100644
--- a/tempest/api/orchestration/stacks/test_stacks.py
+++ b/tempest/api/orchestration/stacks/test_stacks.py
@@ -23,8 +23,8 @@
empty_template = "HeatTemplateFormatVersion: '2012-12-12'\n"
@classmethod
- def setUpClass(cls):
- super(StacksTestJSON, cls).setUpClass()
+ def resource_setup(cls):
+ super(StacksTestJSON, cls).resource_setup()
@test.attr(type='smoke')
def test_stack_list_responds(self):
diff --git a/tempest/api/orchestration/stacks/test_swift_resources.py b/tempest/api/orchestration/stacks/test_swift_resources.py
index d7c2a0d..307468e 100644
--- a/tempest/api/orchestration/stacks/test_swift_resources.py
+++ b/tempest/api/orchestration/stacks/test_swift_resources.py
@@ -26,9 +26,8 @@
class SwiftResourcesTestJSON(base.BaseOrchestrationTest):
@classmethod
- @test.safe_setup
- def setUpClass(cls):
- super(SwiftResourcesTestJSON, cls).setUpClass()
+ def resource_setup(cls):
+ super(SwiftResourcesTestJSON, cls).resource_setup()
cls.stack_name = data_utils.rand_name('heat')
template = cls.read_template('swift_basic')
os = clients.Manager()
diff --git a/tempest/api/orchestration/stacks/test_templates.py b/tempest/api/orchestration/stacks/test_templates.py
index 0d6060d..262c576 100644
--- a/tempest/api/orchestration/stacks/test_templates.py
+++ b/tempest/api/orchestration/stacks/test_templates.py
@@ -26,9 +26,8 @@
"""
@classmethod
- @test.safe_setup
- def setUpClass(cls):
- super(TemplateYAMLTestJSON, cls).setUpClass()
+ def resource_setup(cls):
+ super(TemplateYAMLTestJSON, cls).resource_setup()
cls.stack_name = data_utils.rand_name('heat')
cls.stack_identifier = cls.create_stack(cls.stack_name, cls.template)
cls.client.wait_for_stack_status(cls.stack_identifier,
diff --git a/tempest/api/orchestration/stacks/test_templates_negative.py b/tempest/api/orchestration/stacks/test_templates_negative.py
index b325104..9082107 100644
--- a/tempest/api/orchestration/stacks/test_templates_negative.py
+++ b/tempest/api/orchestration/stacks/test_templates_negative.py
@@ -30,8 +30,8 @@
invalid_template_url = 'http://www.example.com/template.yaml'
@classmethod
- def setUpClass(cls):
- super(TemplateYAMLNegativeTestJSON, cls).setUpClass()
+ def resource_setup(cls):
+ super(TemplateYAMLNegativeTestJSON, cls).resource_setup()
cls.parameters = {}
@test.attr(type=['gate', 'negative'])
diff --git a/tempest/api/orchestration/stacks/test_volumes.py b/tempest/api/orchestration/stacks/test_volumes.py
index f371370..f47078c 100644
--- a/tempest/api/orchestration/stacks/test_volumes.py
+++ b/tempest/api/orchestration/stacks/test_volumes.py
@@ -26,8 +26,8 @@
class CinderResourcesTest(base.BaseOrchestrationTest):
@classmethod
- def setUpClass(cls):
- super(CinderResourcesTest, cls).setUpClass()
+ def resource_setup(cls):
+ super(CinderResourcesTest, cls).resource_setup()
if not CONF.service_available.cinder:
raise cls.skipException('Cinder support is required')
diff --git a/tempest/api/telemetry/base.py b/tempest/api/telemetry/base.py
index 8c2f37b..769c201 100644
--- a/tempest/api/telemetry/base.py
+++ b/tempest/api/telemetry/base.py
@@ -26,11 +26,11 @@
"""Base test case class for all Telemetry API tests."""
@classmethod
- def setUpClass(cls):
+ def resource_setup(cls):
if not CONF.service_available.ceilometer:
raise cls.skipException("Ceilometer support is required")
cls.set_network_resources()
- super(BaseTelemetryTest, cls).setUpClass()
+ super(BaseTelemetryTest, cls).resource_setup()
os = cls.get_client_manager()
cls.telemetry_client = os.telemetry_client
cls.servers_client = os.servers_client
@@ -84,12 +84,12 @@
pass
@classmethod
- def tearDownClass(cls):
+ def resource_cleanup(cls):
cls.cleanup_resources(cls.telemetry_client.delete_alarm, cls.alarm_ids)
cls.cleanup_resources(cls.servers_client.delete_server, cls.server_ids)
cls.cleanup_resources(cls.image_client.delete_image, cls.image_ids)
cls.clear_isolated_creds()
- super(BaseTelemetryTest, cls).tearDownClass()
+ super(BaseTelemetryTest, cls).resource_cleanup()
def await_samples(self, metric, query):
"""
diff --git a/tempest/api/telemetry/test_telemetry_alarming_api.py b/tempest/api/telemetry/test_telemetry_alarming_api.py
index 95758e8..b45d545 100644
--- a/tempest/api/telemetry/test_telemetry_alarming_api.py
+++ b/tempest/api/telemetry/test_telemetry_alarming_api.py
@@ -20,8 +20,8 @@
_interface = 'json'
@classmethod
- def setUpClass(cls):
- super(TelemetryAlarmingAPITestJSON, cls).setUpClass()
+ def resource_setup(cls):
+ super(TelemetryAlarmingAPITestJSON, cls).resource_setup()
cls.rule = {'meter_name': 'cpu_util',
'comparison_operator': 'gt',
'threshold': 80.0,
diff --git a/tempest/api/telemetry/test_telemetry_notification_api.py b/tempest/api/telemetry/test_telemetry_notification_api.py
index 9b15c51..3782b70 100644
--- a/tempest/api/telemetry/test_telemetry_notification_api.py
+++ b/tempest/api/telemetry/test_telemetry_notification_api.py
@@ -23,11 +23,11 @@
_interface = 'json'
@classmethod
- def setUpClass(cls):
+ def resource_setup(cls):
if CONF.telemetry.too_slow_to_test:
raise cls.skipException("Ceilometer feature for fast work mysql "
"is disabled")
- super(TelemetryNotificationAPITestJSON, cls).setUpClass()
+ super(TelemetryNotificationAPITestJSON, cls).resource_setup()
@test.attr(type="gate")
@testtools.skipIf(not CONF.service_available.nova,
diff --git a/tempest/cli/simple_read_only/compute/test_nova_manage.py b/tempest/cli/simple_read_only/compute/test_nova_manage.py
index c27b12e..a4c7aa1 100644
--- a/tempest/cli/simple_read_only/compute/test_nova_manage.py
+++ b/tempest/cli/simple_read_only/compute/test_nova_manage.py
@@ -65,20 +65,17 @@
self.nova_manage('', '--version', merge_stderr=True))
def test_debug_flag(self):
- self.assertNotEqual("", self.nova_manage('flavor list',
+ self.assertNotEqual("", self.nova_manage('service list',
'--debug'))
def test_verbose_flag(self):
- self.assertNotEqual("", self.nova_manage('flavor list',
+ self.assertNotEqual("", self.nova_manage('service list',
'--verbose'))
# test actions
def test_version(self):
self.assertNotEqual("", self.nova_manage('version'))
- def test_flavor_list(self):
- self.assertNotEqual("", self.nova_manage('flavor list'))
-
def test_db_sync(self):
# make sure command doesn't error out
self.nova_manage('db sync')
diff --git a/tempest/clients.py b/tempest/clients.py
index 89cffba..1dda66a 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -13,9 +13,6 @@
# License for the specific language governing permissions and limitations
# under the License.
-import keystoneclient.exceptions
-import keystoneclient.v2_0.client
-
from tempest import auth
from tempest.common import rest_client
from tempest import config
@@ -488,290 +485,3 @@
credentials=auth.get_default_credentials('compute_admin'),
interface=interface,
service=service)
-
-
-class OfficialClientManager(manager.Manager):
- """
- Manager that provides access to the official python clients for
- calling various OpenStack APIs.
- """
-
- NOVACLIENT_VERSION = '2'
- CINDERCLIENT_VERSION = '1'
- HEATCLIENT_VERSION = '1'
- IRONICCLIENT_VERSION = '1'
- SAHARACLIENT_VERSION = '1.1'
- CEILOMETERCLIENT_VERSION = '2'
-
- def __init__(self, credentials):
- # FIXME(andreaf) Auth provider for client_type 'official' is
- # not implemented yet, setting to 'tempest' for now.
- self.client_type = 'tempest'
- self.interface = None
- # super cares for credentials validation
- super(OfficialClientManager, self).__init__(credentials=credentials)
- self.baremetal_client = self._get_baremetal_client()
- self.compute_client = self._get_compute_client(credentials)
- self.identity_client = self._get_identity_client(credentials)
- self.image_client = self._get_image_client()
- self.network_client = self._get_network_client()
- self.volume_client = self._get_volume_client(credentials)
- self.object_storage_client = self._get_object_storage_client(
- credentials)
- self.orchestration_client = self._get_orchestration_client(
- credentials)
- self.data_processing_client = self._get_data_processing_client(
- credentials)
- self.ceilometer_client = self._get_ceilometer_client(
- credentials)
-
- def _get_roles(self):
- admin_credentials = auth.get_default_credentials('identity_admin')
- keystone_admin = self._get_identity_client(admin_credentials)
-
- username = self.credentials.username
- tenant_name = self.credentials.tenant_name
- user_id = keystone_admin.users.find(name=username).id
- tenant_id = keystone_admin.tenants.find(name=tenant_name).id
-
- roles = keystone_admin.roles.roles_for_user(
- user=user_id, tenant=tenant_id)
-
- return [r.name for r in roles]
-
- def _get_compute_client(self, credentials):
- # Novaclient will not execute operations for anyone but the
- # identified user, so a new client needs to be created for
- # each user that operations need to be performed for.
- if not CONF.service_available.nova:
- return None
- import novaclient.client
-
- auth_url = CONF.identity.uri
- dscv = CONF.identity.disable_ssl_certificate_validation
- region = CONF.identity.region
-
- client_args = (credentials.username, credentials.password,
- credentials.tenant_name, auth_url)
-
- # Create our default Nova client to use in testing
- service_type = CONF.compute.catalog_type
- endpoint_type = CONF.compute.endpoint_type
- return novaclient.client.Client(self.NOVACLIENT_VERSION,
- *client_args,
- service_type=service_type,
- endpoint_type=endpoint_type,
- region_name=region,
- no_cache=True,
- insecure=dscv,
- http_log_debug=True)
-
- def _get_image_client(self):
- if not CONF.service_available.glance:
- return None
- import glanceclient
- token = self.identity_client.auth_token
- region = CONF.identity.region
- endpoint_type = CONF.image.endpoint_type
- endpoint = self.identity_client.service_catalog.url_for(
- attr='region', filter_value=region,
- service_type=CONF.image.catalog_type, endpoint_type=endpoint_type)
- dscv = CONF.identity.disable_ssl_certificate_validation
- return glanceclient.Client('1', endpoint=endpoint, token=token,
- insecure=dscv)
-
- def _get_volume_client(self, credentials):
- if not CONF.service_available.cinder:
- return None
- import cinderclient.client
- auth_url = CONF.identity.uri
- region = CONF.identity.region
- endpoint_type = CONF.volume.endpoint_type
- dscv = CONF.identity.disable_ssl_certificate_validation
- return cinderclient.client.Client(self.CINDERCLIENT_VERSION,
- credentials.username,
- credentials.password,
- credentials.tenant_name,
- auth_url,
- region_name=region,
- endpoint_type=endpoint_type,
- insecure=dscv,
- http_log_debug=True)
-
- def _get_object_storage_client(self, credentials):
- if not CONF.service_available.swift:
- return None
- import swiftclient
- auth_url = CONF.identity.uri
- # add current tenant to swift operator role group.
- admin_credentials = auth.get_default_credentials('identity_admin')
- keystone_admin = self._get_identity_client(admin_credentials)
-
- # enable test user to operate swift by adding operator role to him.
- roles = keystone_admin.roles.list()
- operator_role = CONF.object_storage.operator_role
- member_role = [role for role in roles if role.name == operator_role][0]
- # NOTE(maurosr): This is surrounded in the try-except block cause
- # neutron tests doesn't have tenant isolation.
- try:
- keystone_admin.roles.add_user_role(self.identity_client.user_id,
- member_role.id,
- self.identity_client.tenant_id)
- except keystoneclient.exceptions.Conflict:
- pass
-
- endpoint_type = CONF.object_storage.endpoint_type
- os_options = {'endpoint_type': endpoint_type}
- return swiftclient.Connection(auth_url, credentials.username,
- credentials.password,
- tenant_name=credentials.tenant_name,
- auth_version='2',
- os_options=os_options)
-
- def _get_orchestration_client(self, credentials):
- if not CONF.service_available.heat:
- return None
- import heatclient.client
-
- keystone = self._get_identity_client(credentials)
- region = CONF.identity.region
- endpoint_type = CONF.orchestration.endpoint_type
- token = keystone.auth_token
- service_type = CONF.orchestration.catalog_type
- try:
- endpoint = keystone.service_catalog.url_for(
- attr='region',
- filter_value=region,
- service_type=service_type,
- endpoint_type=endpoint_type)
- except keystoneclient.exceptions.EndpointNotFound:
- return None
- else:
- return heatclient.client.Client(self.HEATCLIENT_VERSION,
- endpoint,
- token=token,
- username=credentials.username,
- password=credentials.password)
-
- def _get_identity_client(self, credentials):
- # This identity client is not intended to check the security
- # of the identity service, so use admin credentials by default.
-
- auth_url = CONF.identity.uri
- dscv = CONF.identity.disable_ssl_certificate_validation
-
- return keystoneclient.v2_0.client.Client(
- username=credentials.username,
- password=credentials.password,
- tenant_name=credentials.tenant_name,
- auth_url=auth_url,
- insecure=dscv)
-
- def _get_baremetal_client(self):
- # ironic client is currently intended to by used by admin users
- if not CONF.service_available.ironic:
- return None
- import ironicclient.client
- roles = self._get_roles()
- if CONF.identity.admin_role not in roles:
- return None
-
- auth_url = CONF.identity.uri
- api_version = self.IRONICCLIENT_VERSION
- insecure = CONF.identity.disable_ssl_certificate_validation
- service_type = CONF.baremetal.catalog_type
- endpoint_type = CONF.baremetal.endpoint_type
- creds = {
- 'os_username': self.credentials.username,
- 'os_password': self.credentials.password,
- 'os_tenant_name': self.credentials.tenant_name
- }
-
- try:
- return ironicclient.client.get_client(
- api_version=api_version,
- os_auth_url=auth_url,
- insecure=insecure,
- os_service_type=service_type,
- os_endpoint_type=endpoint_type,
- **creds)
- except keystoneclient.exceptions.EndpointNotFound:
- return None
-
- def _get_network_client(self):
- # The intended configuration is for the network client to have
- # admin privileges and indicate for whom resources are being
- # created via a 'tenant_id' parameter. This will often be
- # preferable to authenticating as a specific user because
- # working with certain resources (public routers and networks)
- # often requires admin privileges anyway.
- if not CONF.service_available.neutron:
- return None
- import neutronclient.v2_0.client
-
- credentials = auth.get_default_credentials('identity_admin')
-
- auth_url = CONF.identity.uri
- dscv = CONF.identity.disable_ssl_certificate_validation
- endpoint_type = CONF.network.endpoint_type
-
- return neutronclient.v2_0.client.Client(
- username=credentials.username,
- password=credentials.password,
- tenant_name=credentials.tenant_name,
- endpoint_type=endpoint_type,
- auth_url=auth_url,
- insecure=dscv)
-
- def _get_data_processing_client(self, credentials):
- if not CONF.service_available.sahara:
- # Sahara isn't available
- return None
-
- import saharaclient.client
-
- endpoint_type = CONF.data_processing.endpoint_type
- catalog_type = CONF.data_processing.catalog_type
- auth_url = CONF.identity.uri
-
- client = saharaclient.client.Client(
- self.SAHARACLIENT_VERSION,
- credentials.username,
- credentials.password,
- project_name=credentials.tenant_name,
- endpoint_type=endpoint_type,
- service_type=catalog_type,
- auth_url=auth_url)
-
- return client
-
- def _get_ceilometer_client(self, credentials):
- if not CONF.service_available.ceilometer:
- return None
-
- import ceilometerclient.client
-
- keystone = self._get_identity_client(credentials)
- region = CONF.identity.region
-
- endpoint_type = CONF.telemetry.endpoint_type
- service_type = CONF.telemetry.catalog_type
- auth_url = CONF.identity.uri
-
- try:
- keystone.service_catalog.url_for(
- attr='region',
- filter_value=region,
- service_type=service_type,
- endpoint_type=endpoint_type)
- except keystoneclient.exceptions.EndpointNotFound:
- return None
- else:
- return ceilometerclient.client.get_client(
- self.CEILOMETERCLIENT_VERSION,
- os_username=credentials.username,
- os_password=credentials.password,
- os_tenant_name=credentials.tenant_name,
- os_auth_url=auth_url,
- os_service_type=service_type,
- os_endpoint_type=endpoint_type)
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index bf0cc70..3c41dd9 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -184,7 +184,9 @@
def destroy_users(users):
admin = keystone_admin()
for user in users:
- user_id = admin.identity.get_user_by_name(user['name'])['id']
+ tenant_id = admin.identity.get_tenant_by_name(user['tenant'])['id']
+ user_id = admin.identity.get_user_by_username(tenant_id,
+ user['name'])['id']
r, body = admin.identity.delete_user(user_id)
@@ -525,7 +527,8 @@
for volume in volumes:
client = client_for_user(volume['owner'])
volume_id = _get_volume_by_name(client, volume['name'])['id']
- r, body = client.volumes.delete_volume(volume_id)
+ client.volumes.detach_volume(volume_id)
+ client.volumes.delete_volume(volume_id)
def attach_volumes(volumes):
diff --git a/tempest/common/cred_provider.py b/tempest/common/cred_provider.py
index 9808ed1..56d34a5 100644
--- a/tempest/common/cred_provider.py
+++ b/tempest/common/cred_provider.py
@@ -24,8 +24,8 @@
@six.add_metaclass(abc.ABCMeta)
class CredentialProvider(object):
- def __init__(self, name, tempest_client=True, interface='json',
- password='pass', network_resources=None):
+ def __init__(self, name, interface='json', password='pass',
+ network_resources=None):
self.name = name
@abc.abstractmethod
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index 02c50e4..b2edfee 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -13,7 +13,6 @@
# under the License.
import netaddr
-from neutronclient.common import exceptions as n_exc
from tempest import auth
from tempest import clients
@@ -29,15 +28,14 @@
class IsolatedCreds(cred_provider.CredentialProvider):
- def __init__(self, name, tempest_client=True, interface='json',
- password='pass', network_resources=None):
- super(IsolatedCreds, self).__init__(name, tempest_client, interface,
- password, network_resources)
+ def __init__(self, name, interface='json', password='pass',
+ network_resources=None):
+ super(IsolatedCreds, self).__init__(name, interface, password,
+ network_resources)
self.network_resources = network_resources
self.isolated_creds = {}
self.isolated_net_resources = {}
self.ports = []
- self.tempest_client = tempest_client
self.interface = interface
self.password = password
self.identity_admin_client, self.network_admin_client = (
@@ -50,96 +48,50 @@
identity
network
"""
- if self.tempest_client:
- os = clients.AdminManager(interface=self.interface)
- else:
- os = clients.OfficialClientManager(
- auth.get_default_credentials('identity_admin')
- )
+ os = clients.AdminManager(interface=self.interface)
return os.identity_client, os.network_client
def _create_tenant(self, name, description):
- if self.tempest_client:
- _, tenant = self.identity_admin_client.create_tenant(
- name=name, description=description)
- else:
- tenant = self.identity_admin_client.tenants.create(
- name,
- description=description)
+ _, tenant = self.identity_admin_client.create_tenant(
+ name=name, description=description)
return tenant
def _get_tenant_by_name(self, name):
- if self.tempest_client:
- _, tenant = self.identity_admin_client.get_tenant_by_name(name)
- else:
- tenants = self.identity_admin_client.tenants.list()
- for ten in tenants:
- if ten['name'] == name:
- tenant = ten
- break
- else:
- raise exceptions.NotFound('No such tenant')
+ _, tenant = self.identity_admin_client.get_tenant_by_name(name)
return tenant
def _create_user(self, username, password, tenant, email):
- if self.tempest_client:
- _, user = self.identity_admin_client.create_user(username,
- password,
- tenant['id'],
- email)
- else:
- user = self.identity_admin_client.users.create(username, password,
- email,
- tenant_id=tenant.id)
+ _, user = self.identity_admin_client.create_user(
+ username, password, tenant['id'], email)
return user
def _get_user(self, tenant, username):
- if self.tempest_client:
- _, user = self.identity_admin_client.get_user_by_username(
- tenant['id'],
- username)
- else:
- user = self.identity_admin_client.users.get(username)
+ _, user = self.identity_admin_client.get_user_by_username(
+ tenant['id'], username)
return user
def _list_roles(self):
- if self.tempest_client:
- _, roles = self.identity_admin_client.list_roles()
- else:
- roles = self.identity_admin_client.roles.list()
+ _, roles = self.identity_admin_client.list_roles()
return roles
def _assign_user_role(self, tenant, user, role_name):
role = None
try:
roles = self._list_roles()
- if self.tempest_client:
- role = next(r for r in roles if r['name'] == role_name)
- else:
- role = next(r for r in roles if r.name == role_name)
+ role = next(r for r in roles if r['name'] == role_name)
except StopIteration:
msg = 'No "%s" role found' % role_name
raise exceptions.NotFound(msg)
- if self.tempest_client:
- self.identity_admin_client.assign_user_role(tenant['id'],
- user['id'], role['id'])
- else:
- self.identity_admin_client.roles.add_user_role(user.id, role.id,
- tenant.id)
+ self.identity_admin_client.assign_user_role(tenant['id'], user['id'],
+ role['id'])
def _delete_user(self, user):
- if self.tempest_client:
- self.identity_admin_client.delete_user(user)
- else:
- self.identity_admin_client.users.delete(user)
+ self.identity_admin_client.delete_user(user)
def _delete_tenant(self, tenant):
if CONF.service_available.neutron:
self._cleanup_default_secgroup(tenant)
- if self.tempest_client:
- self.identity_admin_client.delete_tenant(tenant)
- else:
- self.identity_admin_client.tenants.delete(tenant)
+ self.identity_admin_client.delete_tenant(tenant)
def _create_creds(self, suffix="", admin=False):
"""Create random credentials under the following schema.
@@ -175,15 +127,9 @@
return self._get_credentials(user, tenant)
def _get_credentials(self, user, tenant):
- if self.tempest_client:
- user_get = user.get
- tenant_get = tenant.get
- else:
- user_get = user.__dict__.get
- tenant_get = tenant.__dict__.get
return auth.get_credentials(
- username=user_get('name'), user_id=user_get('id'),
- tenant_name=tenant_get('name'), tenant_id=tenant_get('id'),
+ username=user['name'], user_id=user['id'],
+ tenant_name=tenant['name'], tenant_id=tenant['id'],
password=self.password)
def _create_network_resources(self, tenant_id):
@@ -228,45 +174,32 @@
return network, subnet, router
def _create_network(self, name, tenant_id):
- if self.tempest_client:
- resp, resp_body = self.network_admin_client.create_network(
- name=name, tenant_id=tenant_id)
- else:
- body = {'network': {'tenant_id': tenant_id, 'name': name}}
- resp_body = self.network_admin_client.create_network(body)
+ _, resp_body = self.network_admin_client.create_network(
+ name=name, tenant_id=tenant_id)
return resp_body['network']
def _create_subnet(self, subnet_name, tenant_id, network_id):
- if not self.tempest_client:
- body = {'subnet': {'name': subnet_name, 'tenant_id': tenant_id,
- 'network_id': network_id, 'ip_version': 4}}
- if self.network_resources:
- body['enable_dhcp'] = self.network_resources['dhcp']
base_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
mask_bits = CONF.network.tenant_network_mask_bits
for subnet_cidr in base_cidr.subnet(mask_bits):
try:
- if self.tempest_client:
- if self.network_resources:
- resp, resp_body = self.network_admin_client.\
- create_subnet(
- network_id=network_id, cidr=str(subnet_cidr),
- name=subnet_name,
- tenant_id=tenant_id,
- enable_dhcp=self.network_resources['dhcp'],
- ip_version=4)
- else:
- resp, resp_body = self.network_admin_client.\
- create_subnet(network_id=network_id,
- cidr=str(subnet_cidr),
- name=subnet_name,
- tenant_id=tenant_id,
- ip_version=4)
+ if self.network_resources:
+ _, resp_body = self.network_admin_client.\
+ create_subnet(
+ network_id=network_id, cidr=str(subnet_cidr),
+ name=subnet_name,
+ tenant_id=tenant_id,
+ enable_dhcp=self.network_resources['dhcp'],
+ ip_version=4)
else:
- body['subnet']['cidr'] = str(subnet_cidr)
- resp_body = self.network_admin_client.create_subnet(body)
+ _, resp_body = self.network_admin_client.\
+ create_subnet(network_id=network_id,
+ cidr=str(subnet_cidr),
+ name=subnet_name,
+ tenant_id=tenant_id,
+ ip_version=4)
break
- except (n_exc.BadRequest, exceptions.BadRequest) as e:
+ except exceptions.BadRequest as e:
if 'overlaps with another subnet' not in str(e):
raise
else:
@@ -278,25 +211,15 @@
def _create_router(self, router_name, tenant_id):
external_net_id = dict(
network_id=CONF.network.public_network_id)
- if self.tempest_client:
- resp, resp_body = self.network_admin_client.create_router(
- router_name,
- external_gateway_info=external_net_id,
- tenant_id=tenant_id)
- else:
- body = {'router': {'name': router_name, 'tenant_id': tenant_id,
- 'external_gateway_info': external_net_id,
- 'admin_state_up': True}}
- resp_body = self.network_admin_client.create_router(body)
+ _, resp_body = self.network_admin_client.create_router(
+ router_name,
+ external_gateway_info=external_net_id,
+ tenant_id=tenant_id)
return resp_body['router']
def _add_router_interface(self, router_id, subnet_id):
- if self.tempest_client:
- self.network_admin_client.add_router_interface_with_subnet_id(
- router_id, subnet_id)
- else:
- body = {'subnet_id': subnet_id}
- self.network_admin_client.add_interface_router(router_id, body)
+ self.network_admin_client.add_router_interface_with_subnet_id(
+ router_id, subnet_id)
def get_primary_network(self):
return self.isolated_net_resources.get('primary')[0]
@@ -380,12 +303,8 @@
def _cleanup_default_secgroup(self, tenant):
net_client = self.network_admin_client
- if self.tempest_client:
- resp, resp_body = net_client.list_security_groups(tenant_id=tenant,
- name="default")
- else:
- resp_body = net_client.list_security_groups(tenant_id=tenant,
- name="default")
+ _, resp_body = net_client.list_security_groups(tenant_id=tenant,
+ name="default")
secgroups_to_delete = resp_body['security_groups']
for secgroup in secgroups_to_delete:
try:
@@ -404,12 +323,8 @@
if (not self.network_resources or
self.network_resources.get('router')):
try:
- if self.tempest_client:
- net_client.remove_router_interface_with_subnet_id(
- router['id'], subnet['id'])
- else:
- body = {'subnet_id': subnet['id']}
- net_client.remove_interface_router(router['id'], body)
+ net_client.remove_router_interface_with_subnet_id(
+ router['id'], subnet['id'])
except exceptions.NotFound:
LOG.warn('router with name: %s not found for delete' %
router['name'])
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index abc60cb..55cc89b 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -106,20 +106,6 @@
"T107: service tag should not be in path")
-def no_official_client_manager_in_api_tests(physical_line, filename):
- """Check that the OfficialClientManager isn't used in the api tests
-
- The api tests should not use the official clients.
-
- T108: Can not use OfficialClientManager in the API tests
- """
- if 'tempest/api' in filename:
- if 'OfficialClientManager' in physical_line:
- return (physical_line.find('OfficialClientManager'),
- 'T108: OfficialClientManager can not be used in the api '
- 'tests')
-
-
def no_mutable_default_args(logical_line):
"""Check that mutable object isn't used as default argument
@@ -136,5 +122,4 @@
register(no_setupclass_for_unit_tests)
register(no_vi_headers)
register(service_tags_not_in_module_path)
- register(no_official_client_manager_in_api_tests)
register(no_mutable_default_args)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 9933646..93712fc 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -47,23 +47,14 @@
class ScenarioTest(tempest.test.BaseTestCase):
- """Replaces the OfficialClientTest base class.
-
- Uses tempest own clients as opposed to OfficialClients.
-
- Common differences:
- - replace resource.attribute with resource['attribute']
- - replace resouce.delete with delete_callable(resource['id'])
- - replace local waiters with common / rest_client waiters
- """
+ """Base class for scenario tests. Uses tempest own clients. """
@classmethod
def setUpClass(cls):
super(ScenarioTest, cls).setUpClass()
# Using tempest client for isolated credentials as well
cls.isolated_creds = isolated_creds.IsolatedCreds(
- cls.__name__, tempest_client=True,
- network_resources=cls.network_resources)
+ cls.__name__, network_resources=cls.network_resources)
cls.manager = clients.Manager(
credentials=cls.credentials()
)
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index c764b39..0277593 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -92,6 +92,7 @@
self.servers_client.wait_for_server_status(self.server['id'], 'ACTIVE')
self._check_network_connectivity()
+ @test.skip_because(bug="1323658")
@test.services('compute', 'network')
def test_server_connectivity_stop_start(self):
self._setup_network_and_servers()
@@ -139,6 +140,7 @@
self.servers_client.resume_server(self.server['id'])
self._wait_server_status_and_check_network_connectivity()
+ @test.skip_because(bug="1323658")
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
'Resize is not available.')
@test.services('compute', 'network')
diff --git a/tempest/scenario/utils.py b/tempest/scenario/utils.py
index e2adb34..c20f20c 100644
--- a/tempest/scenario/utils.py
+++ b/tempest/scenario/utils.py
@@ -40,33 +40,33 @@
self.non_ssh_image_pattern = \
CONF.input_scenario.non_ssh_image_regex
# Setup clients
- ocm = clients.OfficialClientManager(
- auth.get_default_credentials('user'))
- self.client = ocm.compute_client
+ os = clients.Manager()
+ self.images_client = os.images_client
+ self.flavors_client = os.flavors_client
def ssh_user(self, image_id):
- _image = self.client.images.get(image_id)
+ _, _image = self.images_client.get_image(image_id)
for regex, user in self.ssh_users:
# First match wins
- if re.match(regex, _image.name) is not None:
+ if re.match(regex, _image['name']) is not None:
return user
else:
return self.default_ssh_user
def _is_sshable_image(self, image):
return not re.search(pattern=self.non_ssh_image_pattern,
- string=str(image.name))
+ string=str(image['name']))
def is_sshable_image(self, image_id):
- _image = self.client.images.get(image_id)
+ _, _image = self.images_client.get_image(image_id)
return self._is_sshable_image(_image)
def _is_flavor_enough(self, flavor, image):
- return image.minDisk <= flavor.disk
+ return image['minDisk'] <= flavor['disk']
def is_flavor_enough(self, flavor_id, image_id):
- _image = self.client.images.get(image_id)
- _flavor = self.client.flavors.get(flavor_id)
+ _, _image = self.images_client.get_image(image_id)
+ _, _flavor = self.flavors_client.get_flavor_details(flavor_id)
return self._is_flavor_enough(_flavor, _image)
@@ -81,7 +81,7 @@
load_tests = testscenarios.load_tests_apply_scenarios
- class TestInputScenario(manager.OfficialClientTest):
+ class TestInputScenario(manager.ScenarioTest):
scenario_utils = utils.InputScenarioUtils()
scenario_flavor = scenario_utils.scenario_flavors
@@ -91,17 +91,18 @@
def test_create_server_metadata(self):
name = rand_name('instance')
- _ = self.compute_client.servers.create(name=name,
- flavor=self.flavor_ref,
- image=self.image_ref)
+ self.servers_client.create_server(name=name,
+ flavor_ref=self.flavor_ref,
+ image_ref=self.image_ref)
"""
validchars = "-_.{ascii}{digit}".format(ascii=string.ascii_letters,
digit=string.digits)
def __init__(self):
- ocm = clients.OfficialClientManager(
+ os = clients.Manager(
auth.get_default_credentials('user', fill_in=False))
- self.client = ocm.compute_client
+ self.images_client = os.images_client
+ self.flavors_client = os.flavors_client
self.image_pattern = CONF.input_scenario.image_regex
self.flavor_pattern = CONF.input_scenario.flavor_regex
@@ -118,10 +119,11 @@
if not CONF.service_available.glance:
return []
if not hasattr(self, '_scenario_images'):
- images = self.client.images.list(detailed=False)
+ _, images = self.images_client.list_images()
self._scenario_images = [
- (self._normalize_name(i.name), dict(image_ref=i.id))
- for i in images if re.search(self.image_pattern, str(i.name))
+ (self._normalize_name(i['name']), dict(image_ref=i['id']))
+ for i in images if re.search(self.image_pattern,
+ str(i['name']))
]
return self._scenario_images
@@ -131,10 +133,11 @@
:return: a scenario with name and uuid of flavors
"""
if not hasattr(self, '_scenario_flavors'):
- flavors = self.client.flavors.list(detailed=False)
+ _, flavors = self.flavors_client.list_flavors()
self._scenario_flavors = [
- (self._normalize_name(f.name), dict(flavor_ref=f.id))
- for f in flavors if re.search(self.flavor_pattern, str(f.name))
+ (self._normalize_name(f['name']), dict(flavor_ref=f['id']))
+ for f in flavors if re.search(self.flavor_pattern,
+ str(f['name']))
]
return self._scenario_flavors
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index 9c13013..37ad18e 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -100,14 +100,6 @@
self.assertFalse(checks.service_tags_not_in_module_path(
"@test.services('compute')", './tempest/api/image/fake_test.py'))
- def test_no_official_client_manager_in_api_tests(self):
- self.assertTrue(checks.no_official_client_manager_in_api_tests(
- "cls.official_client = clients.OfficialClientManager(credentials)",
- "tempest/api/compute/base.py"))
- self.assertFalse(checks.no_official_client_manager_in_api_tests(
- "cls.official_client = clients.OfficialClientManager(credentials)",
- "tempest/scenario/fake_test.py"))
-
def test_no_mutable_default_args(self):
self.assertEqual(1, len(list(checks.no_mutable_default_args(
" def function1(para={}):"))))
diff --git a/tempest/tests/test_tenant_isolation.py b/tempest/tests/test_tenant_isolation.py
index 48c523e..27c45c2 100644
--- a/tempest/tests/test_tenant_isolation.py
+++ b/tempest/tests/test_tenant_isolation.py
@@ -12,12 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-import keystoneclient.v2_0.client as keystoneclient
import mock
-import neutronclient.v2_0.client as neutronclient
from oslo.config import cfg
-from tempest import clients
from tempest.common import http
from tempest.common import isolated_creds
from tempest import config
@@ -52,24 +49,6 @@
self.assertTrue(isinstance(iso_creds.network_admin_client,
json_network_client.NetworkClientJSON))
- def test_official_client(self):
- self.useFixture(mockpatch.PatchObject(keystoneclient.Client,
- 'authenticate'))
- self.useFixture(mockpatch.PatchObject(clients.OfficialClientManager,
- '_get_image_client'))
- self.useFixture(mockpatch.PatchObject(clients.OfficialClientManager,
- '_get_object_storage_client'))
- self.useFixture(mockpatch.PatchObject(clients.OfficialClientManager,
- '_get_orchestration_client'))
- self.useFixture(mockpatch.PatchObject(clients.OfficialClientManager,
- '_get_ceilometer_client'))
- iso_creds = isolated_creds.IsolatedCreds('test class',
- tempest_client=False)
- self.assertTrue(isinstance(iso_creds.identity_admin_client,
- keystoneclient.Client))
- self.assertTrue(isinstance(iso_creds.network_admin_client,
- neutronclient.Client))
-
def test_tempest_client_xml(self):
iso_creds = isolated_creds.IsolatedCreds('test class', interface='xml')
self.assertEqual(iso_creds.interface, 'xml')
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index ee904c7..c0d3f7a 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -200,29 +200,6 @@
instance.terminate()
self.assertInstanceStateWait(instance, '_GONE')
- def test_run_reboot_terminate_instance(self):
- # EC2 run, await till it reaches to running state, then reboot,
- # and wait untill its state is running, and then terminate
- image_ami = self.ec2_client.get_image(self.images["ami"]
- ["image_id"])
- reservation = image_ami.run(kernel_id=self.images["aki"]["image_id"],
- ramdisk_id=self.images["ari"]["image_id"],
- instance_type=self.instance_type)
-
- self.assertEqual(1, len(reservation.instances))
-
- instance = reservation.instances[0]
- if instance.state != "running":
- self.assertInstanceStateWait(instance, "running")
-
- instance.reboot()
- if instance.state != "running":
- self.assertInstanceStateWait(instance, "running")
- LOG.debug("Instance rebooted - state: %s", instance.state)
-
- instance.terminate()
- self.assertInstanceStateWait(instance, '_GONE')
-
def test_compute_with_volumes(self):
# EC2 1. integration test (not strict)
image_ami = self.ec2_client.get_image(self.images["ami"]["image_id"])
diff --git a/test-requirements.txt b/test-requirements.txt
index cd8154b..ba70259 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,10 +1,13 @@
+# The order of packages is significant, because pip processes them in the order
+# of appearance. Changing the order has an impact on the overall integration
+# process, which may cause wedges in the gate later.
hacking>=0.9.2,<0.10
# needed for doc build
sphinx>=1.1.2,!=1.2.0,<1.3
python-subunit>=0.0.18
-oslosphinx
+oslosphinx>=2.2.0 # Apache-2.0
mox>=0.5.3
mock>=1.0
coverage>=3.6
-oslotest
-stevedore>=0.14
+oslotest>=1.1.0 # Apache-2.0
+stevedore>=1.0.0 # Apache-2.0