Merge "Trim object storage smoke tests to a small set"
diff --git a/README.rst b/README.rst
index ba93712..94a5352 100644
--- a/README.rst
+++ b/README.rst
@@ -18,7 +18,7 @@
incorrect assessment of their cloud. Explicit is always better.
- Tempest uses OpenStack public interfaces. Tests in Tempest should
only touch public interfaces, API calls (native or 3rd party),
- public CLI or libraries.
+ or libraries.
- Tempest should not touch private or implementation specific
interfaces. This means not directly going to the database, not
directly hitting the hypervisors, not testing extensions not
diff --git a/doc/source/field_guide/cli.rst b/doc/source/field_guide/cli.rst
deleted file mode 120000
index 13caef5..0000000
--- a/doc/source/field_guide/cli.rst
+++ /dev/null
@@ -1 +0,0 @@
-../../../tempest/cli/README.rst
\ No newline at end of file
diff --git a/etc/logging.conf.sample b/etc/logging.conf.sample
index cdeedef..36cd324 100644
--- a/etc/logging.conf.sample
+++ b/etc/logging.conf.sample
@@ -34,7 +34,7 @@
formatter=simple
[formatter_tests]
-class = tempest.openstack.common.log.ContextFormatter
+class = oslo_log.formatters.ContextFormatter
[formatter_simple]
format=%(asctime)s.%(msecs)03d %(process)d %(levelname)s: %(message)s
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 2a72635..4418b9d 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -201,27 +201,6 @@
#build_interval = 1
-[cli]
-
-#
-# From tempest.config
-#
-
-# enable cli tests (boolean value)
-#enabled = true
-
-# directory where python client binaries are located (string value)
-#cli_dir = /usr/local/bin
-
-# Whether the tempest run location has access to the *-manage
-# commands. In a pure blackbox environment it will not. (boolean
-# value)
-#has_manage = true
-
-# Number of seconds to wait on a CLI timeout (integer value)
-#timeout = 15
-
-
[compute]
#
@@ -396,6 +375,11 @@
# https://bugs.launchpad.net/nova/+bug/1398999 (boolean value)
#block_migrate_cinder_iscsi = false
+# Does the test system allow live-migration of paused instances? Note,
+# this is more than just the ANDing of paused and live_migrate, but
+# all 3 should be set to True to run those tests (boolean value)
+#live_migrate_paused_instances = false
+
# Enable VNC console. This configuration value should be same as
# [nova.vnc]->vnc_enabled in nova.conf (boolean value)
#vnc_console = false
diff --git a/requirements.txt b/requirements.txt
index 0d7fc0d..3a32b69 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,10 +9,8 @@
boto>=2.32.1
paramiko>=1.13.0
netaddr>=0.7.12
-python-glanceclient>=0.15.0
-python-cinderclient>=1.1.0
-python-heatclient>=0.3.0
testrepository>=0.0.18
+pyOpenSSL>=0.11
oslo.concurrency>=1.8.0,<1.9.0 # Apache-2.0
oslo.config>=1.9.3,<1.10.0 # Apache-2.0
oslo.i18n>=1.5.0,<1.6.0 # Apache-2.0
@@ -23,4 +21,5 @@
iso8601>=0.1.9
fixtures>=0.3.14
testscenarios>=0.4
-tempest-lib>=0.4.0
+tempest-lib>=0.5.0
+PyYAML>=3.1.0
diff --git a/tempest/README.rst b/tempest/README.rst
index d28c3f9..fec2874 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -14,7 +14,6 @@
| tempest/
| api/ - API tests
-| cli/ - CLI tests
| scenario/ - complex scenario tests
| stress/ - stress tests
| thirdparty/ - 3rd party api tests
@@ -38,16 +37,6 @@
frameworks.
-:ref:`cli_field_guide`
-----------------------
-
-CLI tests use the openstack CLI to interact with the OpenStack
-cloud. CLI testing in unit tests is somewhat difficult because unlike
-server testing, there is no access to server code to
-instantiate. Tempest seems like a logical place for this, as it
-prereqs having a running OpenStack cloud.
-
-
:ref:`scenario_field_guide`
---------------------------
diff --git a/tempest/api/baremetal/admin/test_chassis.py b/tempest/api/baremetal/admin/test_chassis.py
index e9068f3..5ad05cc 100644
--- a/tempest/api/baremetal/admin/test_chassis.py
+++ b/tempest/api/baremetal/admin/test_chassis.py
@@ -11,6 +11,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -28,7 +29,7 @@
def _assertExpected(self, expected, actual):
# Check if not expected keys/values exists in actual response body
- for key, value in expected.iteritems():
+ for key, value in six.iteritems(expected):
if key not in ('created_at', 'updated_at'):
self.assertIn(key, actual)
self.assertEqual(value, actual[key])
diff --git a/tempest/api/baremetal/admin/test_ports.py b/tempest/api/baremetal/admin/test_ports.py
index ee6bb9c..ece4471 100644
--- a/tempest/api/baremetal/admin/test_ports.py
+++ b/tempest/api/baremetal/admin/test_ports.py
@@ -10,6 +10,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import decorators
from tempest_lib import exceptions as lib_exc
@@ -31,7 +32,7 @@
def _assertExpected(self, expected, actual):
# Check if not expected keys/values exists in actual response body
- for key, value in expected.iteritems():
+ for key, value in six.iteritems(expected):
if key not in ('created_at', 'updated_at'):
self.assertIn(key, actual)
self.assertEqual(value, actual[key])
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log.py b/tempest/api/compute/admin/test_instance_usage_audit_log.py
index 6634290..9da7901 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log.py
@@ -14,7 +14,8 @@
# under the License.
import datetime
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api.compute import base
from tempest import test
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
index ec9ad19..97d665b 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
@@ -14,8 +14,8 @@
# under the License.
import datetime
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api.compute import base
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 8a92326..d3b1f5e 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -84,10 +84,15 @@
self.volumes_client.wait_for_volume_status(volume_id, 'available')
self.volumes_client.delete_volume(volume_id)
- @test.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b')
- @testtools.skipIf(not CONF.compute_feature_enabled.live_migration,
- 'Live migration not available')
- def test_live_block_migration(self):
+ def _test_live_block_migration(self, state='ACTIVE'):
+ """Tests live block migration between two hosts.
+
+ Requires CONF.compute_feature_enabled.live_migration to be True.
+
+ :param state: The vm_state the migrated server should be in before and
+ after the live migration. Supported values are 'ACTIVE'
+ and 'PAUSED'.
+ """
# Live block migrate an instance to another host
if len(self._get_compute_hostnames()) < 2:
raise self.skipTest(
@@ -95,10 +100,33 @@
server_id = self._get_an_active_server()
actual_host = self._get_host_for_server(server_id)
target_host = self._get_host_other_than(actual_host)
+
+ if state == 'PAUSED':
+ self.admin_servers_client.pause_server(server_id)
+ self.admin_servers_client.wait_for_server_status(server_id, state)
+
self._migrate_server_to(server_id, target_host)
- self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+ self.servers_client.wait_for_server_status(server_id, state)
self.assertEqual(target_host, self._get_host_for_server(server_id))
+ @test.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b')
+ @testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
+ 'Live migration not available')
+ def test_live_block_migration(self):
+ self._test_live_block_migration()
+
+ @test.idempotent_id('1e107f21-61b2-4988-8f22-b196e938ab88')
+ @testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
+ 'Live migration not available')
+ @testtools.skipUnless(CONF.compute_feature_enabled.pause,
+ 'Pause is not available.')
+ @testtools.skipUnless(CONF.compute_feature_enabled
+ .live_migrate_paused_instances,
+ 'Live migration of paused instances is not '
+ 'available.')
+ def test_live_block_migration_paused(self):
+ self._test_live_block_migration(state='PAUSED')
+
@test.idempotent_id('e19c0cc6-6720-4ed8-be83-b6603ed5c812')
@testtools.skipIf(not CONF.compute_feature_enabled.live_migration or not
CONF.compute_feature_enabled.
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index eca634d..26d6661 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -334,6 +334,15 @@
return server['id']
@classmethod
+ def delete_server(cls, server_id):
+ """Deletes an existing server and waits for it to be gone."""
+ try:
+ cls.servers_client.delete_server(server_id)
+ cls.servers_client.wait_for_server_termination(server_id)
+ except Exception:
+ LOG.exception('Failed to delete server %s' % server_id)
+
+ @classmethod
def delete_volume(cls, volume_id):
"""Deletes the given volume and waits for it to be gone."""
cls._delete_volume(cls.volumes_extensions_client, volume_id)
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index 0178c9e..fd4d902 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -21,7 +21,6 @@
class ListServersNegativeTestJSON(base.BaseV2ComputeTest):
- force_tenant_isolation = True
@classmethod
def setup_clients(cls):
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 3871db1..dbfdbdb 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -181,27 +181,16 @@
self.client.wait_for_server_status(self.server_id, 'SHUTOFF')
self.client.start(self.server_id)
- def _detect_server_image_flavor(self, server_id):
- # Detects the current server image flavor ref.
- server = self.client.get_server(server_id)
- current_flavor = server['flavor']['id']
- new_flavor_ref = self.flavor_ref_alt \
- if current_flavor == self.flavor_ref else self.flavor_ref
- return current_flavor, new_flavor_ref
-
def _test_resize_server_confirm(self, stop=False):
# The server's RAM and disk space should be modified to that of
# the provided flavor
- previous_flavor_ref, new_flavor_ref = \
- self._detect_server_image_flavor(self.server_id)
-
if stop:
self.servers_client.stop(self.server_id)
self.servers_client.wait_for_server_status(self.server_id,
'SHUTOFF')
- self.client.resize(self.server_id, new_flavor_ref)
+ self.client.resize(self.server_id, self.flavor_ref_alt)
self.client.wait_for_server_status(self.server_id, 'VERIFY_RESIZE')
self.client.confirm_resize(self.server_id)
@@ -209,12 +198,16 @@
self.client.wait_for_server_status(self.server_id, expected_status)
server = self.client.get_server(self.server_id)
- self.assertEqual(new_flavor_ref, server['flavor']['id'])
+ self.assertEqual(self.flavor_ref_alt, server['flavor']['id'])
if stop:
# NOTE(mriedem): tearDown requires the server to be started.
self.client.start(self.server_id)
+ # NOTE(jlk): Explicitly delete the server to get a new one for later
+ # tests. Avoids resize down race issues.
+ self.addCleanup(self.delete_server, self.server_id)
+
@test.idempotent_id('1499262a-9328-4eda-9068-db1ac57498d2')
@testtools.skipUnless(CONF.compute_feature_enabled.resize,
'Resize not available.')
@@ -234,17 +227,14 @@
# The server's RAM and disk space should return to its original
# values after a resize is reverted
- previous_flavor_ref, new_flavor_ref = \
- self._detect_server_image_flavor(self.server_id)
-
- self.client.resize(self.server_id, new_flavor_ref)
+ self.client.resize(self.server_id, self.flavor_ref_alt)
self.client.wait_for_server_status(self.server_id, 'VERIFY_RESIZE')
self.client.revert_resize(self.server_id)
self.client.wait_for_server_status(self.server_id, 'ACTIVE')
server = self.client.get_server(self.server_id)
- self.assertEqual(previous_flavor_ref, server['flavor']['id'])
+ self.assertEqual(self.flavor_ref, server['flavor']['id'])
@test.idempotent_id('b963d4f1-94b3-4c40-9e97-7b583f46e470')
@testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index d0dfc87..a17f581 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
+
from tempest.api.compute import base
from tempest import test
@@ -48,7 +50,7 @@
# We do not know the exact network configuration, but an instance
# should at least have a single public or private address
self.assertTrue(len(addresses) >= 1)
- for network_name, network_addresses in addresses.iteritems():
+ for network_name, network_addresses in six.iteritems(addresses):
self.assertTrue(len(network_addresses) >= 1)
for address in network_addresses:
self.assertTrue(address['addr'])
diff --git a/tempest/api/identity/admin/v3/test_default_project_id.py b/tempest/api/identity/admin/v3/test_default_project_id.py
index 95ba885..0b9d60e 100644
--- a/tempest/api/identity/admin/v3/test_default_project_id.py
+++ b/tempest/api/identity/admin/v3/test_default_project_id.py
@@ -10,10 +10,10 @@
# License for the specific language governing permissions and limitations
# under the License.
+from tempest_lib import auth
from tempest_lib.common.utils import data_utils
from tempest.api.identity import base
-from tempest import auth
from tempest import clients
from tempest import config
from tempest import manager
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 86fbc54..46d6651 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest.api.network import base
@@ -62,7 +63,7 @@
quota_set = self.admin_client.update_quotas(tenant_id,
**new_quotas)
self.addCleanup(self.admin_client.reset_quotas, tenant_id)
- for key, value in new_quotas.iteritems():
+ for key, value in six.iteritems(new_quotas):
self.assertEqual(value, quota_set[key])
# Confirm our tenant is listed among tenants with non default quotas
@@ -76,7 +77,7 @@
# Confirm from API quotas were changed as requested for tenant
quota_set = self.admin_client.show_quotas(tenant_id)
quota_set = quota_set['quota']
- for key, value in new_quotas.iteritems():
+ for key, value in six.iteritems(new_quotas):
self.assertEqual(value, quota_set[key])
# Reset quotas to default and confirm
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index 253d779..ca08fbd 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -16,6 +16,7 @@
import netaddr
import random
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -127,7 +128,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ kwargs = {k: v for k, v in six.iteritems(kwargs) if v}
real_ip, eui_ip = self._get_ips_from_subnet(**kwargs)
self._clean_network()
self.assertEqual(eui_ip, real_ip,
@@ -203,8 +204,8 @@
real_ips = dict([(k['subnet_id'], k['ip_address'])
for k in port['fixed_ips']])
real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
- for sub in subnet_dhcp,
- subnet_slaac]
+ for sub in [subnet_dhcp,
+ subnet_slaac]]
self.client.delete_port(port['id'])
self.ports.pop()
body = self.client.list_ports()
@@ -256,8 +257,8 @@
real_ips = dict([(k['subnet_id'], k['ip_address'])
for k in port['fixed_ips']])
real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
- for sub in subnet_dhcp,
- subnet_slaac]
+ for sub in [subnet_dhcp,
+ subnet_slaac]]
self._clean_network()
self.assertTrue({real_eui_ip,
real_dhcp_ip}.issubset([eui_ip] + dhcp_ip))
@@ -284,7 +285,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ kwargs = {k: v for k, v in six.iteritems(kwargs) if v}
subnet = self.create_subnet(self.network, **kwargs)
port = self.create_port(self.network)
port_ip = next(iter(port['fixed_ips']), None)['ip_address']
@@ -311,7 +312,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ kwargs = {k: v for k, v in six.iteritems(kwargs) if v}
subnet = self.create_subnet(self.network, **kwargs)
ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"],
subnet["allocation_pools"][0]["end"])
@@ -389,7 +390,7 @@
):
kwargs = {'ipv6_ra_mode': ra_mode,
'ipv6_address_mode': add_mode}
- kwargs = {k: v for k, v in kwargs.iteritems() if v}
+ kwargs = {k: v for k, v in six.iteritems(kwargs) if v}
subnet, port = self._create_subnet_router(kwargs)
port_ip = next(iter(port['fixed_ips']), None)['ip_address']
self._clean_network()
diff --git a/tempest/api/network/test_fwaas_extensions.py b/tempest/api/network/test_fwaas_extensions.py
index d007fb0..0622e87 100644
--- a/tempest/api/network/test_fwaas_extensions.py
+++ b/tempest/api/network/test_fwaas_extensions.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -145,7 +146,7 @@
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():
+ for key, value in six.iteritems(fw_rule['firewall_rule']):
self.assertEqual(self.fw_rule[key], value)
@test.idempotent_id('1086dd93-a4c0-4bbb-a1bd-6d4bc62c199f')
@@ -187,7 +188,7 @@
# show a created firewall policy
fw_policy = self.client.show_firewall_policy(self.fw_policy['id'])
fw_policy = fw_policy['firewall_policy']
- for key, value in fw_policy.iteritems():
+ for key, value in six.iteritems(fw_policy):
self.assertEqual(self.fw_policy[key], value)
@test.idempotent_id('02082a03-3cdd-4789-986a-1327dd80bfb7')
@@ -216,7 +217,7 @@
firewall = self.client.show_firewall(firewall_id)
firewall = firewall['firewall']
- for key, value in firewall.iteritems():
+ for key, value in six.iteritems(firewall):
if key == 'status':
continue
self.assertEqual(created_firewall[key], value)
diff --git a/tempest/api/network/test_load_balancer.py b/tempest/api/network/test_load_balancer.py
index ace9f61..38a6fe9 100644
--- a/tempest/api/network/test_load_balancer.py
+++ b/tempest/api/network/test_load_balancer.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import decorators
@@ -75,7 +76,7 @@
body = create_obj(**kwargs)
obj = body[obj_name]
self.addCleanup(delete_obj, obj['id'])
- for key, value in obj.iteritems():
+ for key, value in six.iteritems(obj):
# It is not relevant to filter by all arguments. That is why
# there is a list of attr to except
if key not in attr_exceptions:
@@ -168,7 +169,7 @@
# Verifies the details of a vip
body = self.client.show_vip(self.vip['id'])
vip = body['vip']
- for key, value in vip.iteritems():
+ for key, value in six.iteritems(vip):
# 'status' should not be confirmed in api tests
if key != 'status':
self.assertEqual(self.vip[key], value)
@@ -185,7 +186,7 @@
# Verifies the details of a pool
body = self.client.show_pool(pool['id'])
shown_pool = body['pool']
- for key, value in pool.iteritems():
+ for key, value in six.iteritems(pool):
# 'status' should not be confirmed in api tests
if key != 'status':
self.assertEqual(value, shown_pool[key])
@@ -243,7 +244,7 @@
# Verifies the details of a member
body = self.client.show_member(self.member['id'])
member = body['member']
- for key, value in member.iteritems():
+ for key, value in six.iteritems(member):
# 'status' should not be confirmed in api tests
if key != 'status':
self.assertEqual(self.member[key], value)
@@ -316,7 +317,7 @@
# Verifies the details of a health_monitor
body = self.client.show_health_monitor(self.health_monitor['id'])
health_monitor = body['health_monitor']
- for key, value in health_monitor.iteritems():
+ for key, value in six.iteritems(health_monitor):
# 'status' should not be confirmed in api tests
if key != 'status':
self.assertEqual(self.health_monitor[key], value)
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 97273a6..5e3e374 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -15,6 +15,7 @@
import itertools
import netaddr
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -162,7 +163,7 @@
**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()
+ compare_args = dict((k, v) for k, v in six.iteritems(compare_args_full)
if v is not None)
if 'dns_nameservers' in set(subnet).intersection(compare_args):
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 4362926..35072b4 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -14,6 +14,7 @@
# under the License.
import netaddr
+import six
from tempest_lib.common.utils import data_utils
from tempest.api.network import base_routers as base
@@ -176,7 +177,7 @@
self.assertIsNone(actual_ext_gw_info)
return
# Verify only keys passed in exp_ext_gw_info
- for k, v in exp_ext_gw_info.iteritems():
+ for k, v in six.iteritems(exp_ext_gw_info):
self.assertEqual(v, actual_ext_gw_info[k])
def _verify_gateway_port(self, router_id):
diff --git a/tempest/api/network/test_vpnaas_extensions.py b/tempest/api/network/test_vpnaas_extensions.py
index 718168b..9fe2a56 100644
--- a/tempest/api/network/test_vpnaas_extensions.py
+++ b/tempest/api/network/test_vpnaas_extensions.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest_lib import exceptions as lib_exc
@@ -82,7 +83,7 @@
def _assertExpected(self, expected, actual):
# Check if not expected keys/values exists in actual response body
- for key, value in expected.iteritems():
+ for key, value in six.iteritems(expected):
self.assertIn(key, actual)
self.assertEqual(value, actual[key])
@@ -245,7 +246,7 @@
# Confirm that update was successful by verifying using 'show'
body = self.client.show_ikepolicy(ikepolicy['id'])
ike_policy = body['ikepolicy']
- for key, value in new_ike.iteritems():
+ for key, value in six.iteritems(new_ike):
self.assertIn(key, ike_policy)
self.assertEqual(value, ike_policy[key])
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index 814b46d..24c7c63 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import six
from tempest_lib.common.utils import data_utils
from tempest.api.volume import base
@@ -57,7 +58,7 @@
**new_quota_set)
cleanup_quota_set = dict(
- (k, v) for k, v in default_quota_set.iteritems()
+ (k, v) for k, v in six.iteritems(default_quota_set)
if k in QUOTA_KEYS)
self.addCleanup(self.quotas_client.update_quota_set,
self.demo_tenant_id, **cleanup_quota_set)
diff --git a/tempest/auth.py b/tempest/auth.py
deleted file mode 100644
index 113ad69..0000000
--- a/tempest/auth.py
+++ /dev/null
@@ -1,659 +0,0 @@
-# Copyright 2014 Hewlett-Packard Development Company, L.P.
-# 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 abc
-import copy
-import datetime
-import exceptions
-import re
-import urlparse
-
-from oslo_log import log as logging
-import six
-
-from tempest.services.identity.v2.json import token_client as json_v2id
-from tempest.services.identity.v3.json import token_client as json_v3id
-
-
-LOG = logging.getLogger(__name__)
-
-
-@six.add_metaclass(abc.ABCMeta)
-class AuthProvider(object):
- """
- Provide authentication
- """
-
- def __init__(self, credentials):
- """
- :param credentials: credentials for authentication
- """
- if self.check_credentials(credentials):
- self.credentials = credentials
- else:
- raise TypeError("Invalid credentials")
- self.cache = None
- self.alt_auth_data = None
- self.alt_part = None
-
- def __str__(self):
- return "Creds :{creds}, cached auth data: {cache}".format(
- creds=self.credentials, cache=self.cache)
-
- @abc.abstractmethod
- def _decorate_request(self, filters, method, url, headers=None, body=None,
- auth_data=None):
- """
- Decorate request with authentication data
- """
- return
-
- @abc.abstractmethod
- def _get_auth(self):
- return
-
- @abc.abstractmethod
- def _fill_credentials(self, auth_data_body):
- return
-
- def fill_credentials(self):
- """
- Fill credentials object with data from auth
- """
- auth_data = self.get_auth()
- self._fill_credentials(auth_data[1])
- return self.credentials
-
- @classmethod
- def check_credentials(cls, credentials):
- """
- Verify credentials are valid.
- """
- return isinstance(credentials, Credentials) and credentials.is_valid()
-
- @property
- def auth_data(self):
- return self.get_auth()
-
- @auth_data.deleter
- def auth_data(self):
- self.clear_auth()
-
- def get_auth(self):
- """
- Returns auth from cache if available, else auth first
- """
- if self.cache is None or self.is_expired(self.cache):
- self.set_auth()
- return self.cache
-
- def set_auth(self):
- """
- Forces setting auth, ignores cache if it exists.
- Refills credentials
- """
- self.cache = self._get_auth()
- self._fill_credentials(self.cache[1])
-
- def clear_auth(self):
- """
- Can be called to clear the access cache so that next request
- will fetch a new token and base_url.
- """
- self.cache = None
- self.credentials.reset()
-
- @abc.abstractmethod
- def is_expired(self, auth_data):
- return
-
- def auth_request(self, method, url, headers=None, body=None, filters=None):
- """
- Obtains auth data and decorates a request with that.
- :param method: HTTP method of the request
- :param url: relative URL of the request (path)
- :param headers: HTTP headers of the request
- :param body: HTTP body in case of POST / PUT
- :param filters: select a base URL out of the catalog
- :returns a Tuple (url, headers, body)
- """
- orig_req = dict(url=url, headers=headers, body=body)
-
- auth_url, auth_headers, auth_body = self._decorate_request(
- filters, method, url, headers, body)
- auth_req = dict(url=auth_url, headers=auth_headers, body=auth_body)
-
- # Overwrite part if the request if it has been requested
- if self.alt_part is not None:
- if self.alt_auth_data is not None:
- alt_url, alt_headers, alt_body = self._decorate_request(
- filters, method, url, headers, body,
- auth_data=self.alt_auth_data)
- alt_auth_req = dict(url=alt_url, headers=alt_headers,
- body=alt_body)
- auth_req[self.alt_part] = alt_auth_req[self.alt_part]
-
- else:
- # If alt auth data is None, skip auth in the requested part
- auth_req[self.alt_part] = orig_req[self.alt_part]
-
- # Next auth request will be normal, unless otherwise requested
- self.reset_alt_auth_data()
-
- return auth_req['url'], auth_req['headers'], auth_req['body']
-
- def reset_alt_auth_data(self):
- """
- Configure auth provider to provide valid authentication data
- """
- self.alt_part = None
- self.alt_auth_data = None
-
- def set_alt_auth_data(self, request_part, auth_data):
- """
- Configure auth provider to provide alt authentication data
- on a part of the *next* auth_request. If credentials are None,
- set invalid data.
- :param request_part: request part to contain invalid auth: url,
- headers, body
- :param auth_data: alternative auth_data from which to get the
- invalid data to be injected
- """
- self.alt_part = request_part
- self.alt_auth_data = auth_data
-
- @abc.abstractmethod
- def base_url(self, filters, auth_data=None):
- """
- Extracts the base_url based on provided filters
- """
- return
-
-
-class KeystoneAuthProvider(AuthProvider):
-
- token_expiry_threshold = datetime.timedelta(seconds=60)
-
- def __init__(self, credentials, auth_url,
- disable_ssl_certificate_validation=None,
- ca_certs=None, trace_requests=None):
- super(KeystoneAuthProvider, self).__init__(credentials)
- self.dsvm = disable_ssl_certificate_validation
- self.ca_certs = ca_certs
- self.trace_requests = trace_requests
- self.auth_client = self._auth_client(auth_url)
-
- def _decorate_request(self, filters, method, url, headers=None, body=None,
- auth_data=None):
- if auth_data is None:
- auth_data = self.auth_data
- token, _ = auth_data
- base_url = self.base_url(filters=filters, auth_data=auth_data)
- # build authenticated request
- # returns new request, it does not touch the original values
- _headers = copy.deepcopy(headers) if headers is not None else {}
- _headers['X-Auth-Token'] = str(token)
- if url is None or url == "":
- _url = base_url
- else:
- # Join base URL and url, and remove multiple contiguous slashes
- _url = "/".join([base_url, url])
- parts = [x for x in urlparse.urlparse(_url)]
- parts[2] = re.sub("/{2,}", "/", parts[2])
- _url = urlparse.urlunparse(parts)
- # no change to method or body
- return str(_url), _headers, body
-
- @abc.abstractmethod
- def _auth_client(self):
- return
-
- @abc.abstractmethod
- def _auth_params(self):
- return
-
- def _get_auth(self):
- # Bypasses the cache
- auth_func = getattr(self.auth_client, 'get_token')
- auth_params = self._auth_params()
-
- # returns token, auth_data
- token, auth_data = auth_func(**auth_params)
- return token, auth_data
-
- def get_token(self):
- return self.auth_data[0]
-
-
-class KeystoneV2AuthProvider(KeystoneAuthProvider):
-
- EXPIRY_DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
-
- def _auth_client(self, auth_url):
- return json_v2id.TokenClientJSON(
- auth_url, disable_ssl_certificate_validation=self.dsvm,
- ca_certs=self.ca_certs, trace_requests=self.trace_requests)
-
- def _auth_params(self):
- return dict(
- user=self.credentials.username,
- password=self.credentials.password,
- tenant=self.credentials.tenant_name,
- auth_data=True)
-
- def _fill_credentials(self, auth_data_body):
- tenant = auth_data_body['token']['tenant']
- user = auth_data_body['user']
- if self.credentials.tenant_name is None:
- self.credentials.tenant_name = tenant['name']
- if self.credentials.tenant_id is None:
- self.credentials.tenant_id = tenant['id']
- if self.credentials.username is None:
- self.credentials.username = user['name']
- if self.credentials.user_id is None:
- self.credentials.user_id = user['id']
-
- def base_url(self, filters, auth_data=None):
- """
- Filters can be:
- - service: compute, image, etc
- - region: the service region
- - endpoint_type: adminURL, publicURL, internalURL
- - api_version: replace catalog version with this
- - skip_path: take just the base URL
- """
- if auth_data is None:
- auth_data = self.auth_data
- token, _auth_data = auth_data
- service = filters.get('service')
- region = filters.get('region')
- endpoint_type = filters.get('endpoint_type', 'publicURL')
-
- if service is None:
- raise exceptions.EndpointNotFound("No service provided")
-
- _base_url = None
- for ep in _auth_data['serviceCatalog']:
- if ep["type"] == service:
- for _ep in ep['endpoints']:
- if region is not None and _ep['region'] == region:
- _base_url = _ep.get(endpoint_type)
- if not _base_url:
- # No region matching, use the first
- _base_url = ep['endpoints'][0].get(endpoint_type)
- break
- if _base_url is None:
- raise exceptions.EndpointNotFound(service)
-
- parts = urlparse.urlparse(_base_url)
- if filters.get('api_version', None) is not None:
- path = "/" + filters['api_version']
- noversion_path = "/".join(parts.path.split("/")[2:])
- if noversion_path != "":
- path += "/" + noversion_path
- _base_url = _base_url.replace(parts.path, path)
- if filters.get('skip_path', None) is not None and parts.path != '':
- _base_url = _base_url.replace(parts.path, "/")
-
- return _base_url
-
- def is_expired(self, auth_data):
- _, access = auth_data
- expiry = datetime.datetime.strptime(access['token']['expires'],
- self.EXPIRY_DATE_FORMAT)
- return expiry - self.token_expiry_threshold <= \
- datetime.datetime.utcnow()
-
-
-class KeystoneV3AuthProvider(KeystoneAuthProvider):
-
- EXPIRY_DATE_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
-
- def _auth_client(self, auth_url):
- return json_v3id.V3TokenClientJSON(
- auth_url, disable_ssl_certificate_validation=self.dsvm,
- ca_certs=self.ca_certs, trace_requests=self.trace_requests)
-
- def _auth_params(self):
- return dict(
- user_id=self.credentials.user_id,
- username=self.credentials.username,
- password=self.credentials.password,
- project_id=self.credentials.project_id,
- project_name=self.credentials.project_name,
- user_domain_id=self.credentials.user_domain_id,
- user_domain_name=self.credentials.user_domain_name,
- project_domain_id=self.credentials.project_domain_id,
- project_domain_name=self.credentials.project_domain_name,
- domain_id=self.credentials.domain_id,
- domain_name=self.credentials.domain_name,
- auth_data=True)
-
- def _fill_credentials(self, auth_data_body):
- # project or domain, depending on the scope
- project = auth_data_body.get('project', None)
- domain = auth_data_body.get('domain', None)
- # user is always there
- user = auth_data_body['user']
- # Set project fields
- if project is not None:
- if self.credentials.project_name is None:
- self.credentials.project_name = project['name']
- if self.credentials.project_id is None:
- self.credentials.project_id = project['id']
- if self.credentials.project_domain_id is None:
- self.credentials.project_domain_id = project['domain']['id']
- if self.credentials.project_domain_name is None:
- self.credentials.project_domain_name = \
- project['domain']['name']
- # Set domain fields
- if domain is not None:
- if self.credentials.domain_id is None:
- self.credentials.domain_id = domain['id']
- if self.credentials.domain_name is None:
- self.credentials.domain_name = domain['name']
- # Set user fields
- if self.credentials.username is None:
- self.credentials.username = user['name']
- if self.credentials.user_id is None:
- self.credentials.user_id = user['id']
- if self.credentials.user_domain_id is None:
- self.credentials.user_domain_id = user['domain']['id']
- if self.credentials.user_domain_name is None:
- self.credentials.user_domain_name = user['domain']['name']
-
- def base_url(self, filters, auth_data=None):
- """
- Filters can be:
- - service: compute, image, etc
- - region: the service region
- - endpoint_type: adminURL, publicURL, internalURL
- - api_version: replace catalog version with this
- - skip_path: take just the base URL
- """
- if auth_data is None:
- auth_data = self.auth_data
- token, _auth_data = auth_data
- service = filters.get('service')
- region = filters.get('region')
- endpoint_type = filters.get('endpoint_type', 'public')
-
- if service is None:
- raise exceptions.EndpointNotFound("No service provided")
-
- if 'URL' in endpoint_type:
- endpoint_type = endpoint_type.replace('URL', '')
- _base_url = None
- catalog = _auth_data['catalog']
- # Select entries with matching service type
- service_catalog = [ep for ep in catalog if ep['type'] == service]
- if len(service_catalog) > 0:
- service_catalog = service_catalog[0]['endpoints']
- else:
- # No matching service
- raise exceptions.EndpointNotFound(service)
- # Filter by endpoint type (interface)
- filtered_catalog = [ep for ep in service_catalog if
- ep['interface'] == endpoint_type]
- if len(filtered_catalog) == 0:
- # No matching type, keep all and try matching by region at least
- filtered_catalog = service_catalog
- # Filter by region
- filtered_catalog = [ep for ep in filtered_catalog if
- ep['region'] == region]
- if len(filtered_catalog) == 0:
- # No matching region, take the first endpoint
- filtered_catalog = [service_catalog[0]]
- # There should be only one match. If not take the first.
- _base_url = filtered_catalog[0].get('url', None)
- if _base_url is None:
- raise exceptions.EndpointNotFound(service)
-
- parts = urlparse.urlparse(_base_url)
- if filters.get('api_version', None) is not None:
- path = "/" + filters['api_version']
- noversion_path = "/".join(parts.path.split("/")[2:])
- if noversion_path != "":
- path += "/" + noversion_path
- _base_url = _base_url.replace(parts.path, path)
- if filters.get('skip_path', None) is not None:
- _base_url = _base_url.replace(parts.path, "/")
-
- return _base_url
-
- def is_expired(self, auth_data):
- _, access = auth_data
- expiry = datetime.datetime.strptime(access['expires_at'],
- self.EXPIRY_DATE_FORMAT)
- return expiry - self.token_expiry_threshold <= \
- datetime.datetime.utcnow()
-
-
-def is_identity_version_supported(identity_version):
- return identity_version in IDENTITY_VERSION
-
-
-def get_credentials(auth_url, fill_in=True, identity_version='v2',
- disable_ssl_certificate_validation=None, ca_certs=None,
- trace_requests=None, **kwargs):
- """
- Builds a credentials object based on the configured auth_version
-
- :param auth_url (string): Full URI of the OpenStack Identity API(Keystone)
- which is used to fetch the token from Identity service.
- :param fill_in (boolean): obtain a token and fill in all credential
- details provided by the identity service. When fill_in is not
- specified, credentials are not validated. Validation can be invoked
- by invoking ``is_valid()``
- :param identity_version (string): identity API version is used to
- select the matching auth provider and credentials class
- :param disable_ssl_certificate_validation: whether to enforce SSL
- certificate validation in SSL API requests to the auth system
- :param ca_certs: CA certificate bundle for validation of certificates
- in SSL API requests to the auth system
- :param trace_requests: trace in log API requests to the auth system
- :param kwargs (dict): Dict of credential key/value pairs
-
- Examples:
-
- Returns credentials from the provided parameters:
- >>> get_credentials(username='foo', password='bar')
-
- Returns credentials including IDs:
- >>> get_credentials(username='foo', password='bar', fill_in=True)
- """
- if not is_identity_version_supported(identity_version):
- raise exceptions.InvalidIdentityVersion(
- identity_version=identity_version)
-
- credential_class, auth_provider_class = IDENTITY_VERSION.get(
- identity_version)
-
- creds = credential_class(**kwargs)
- # Fill in the credentials fields that were not specified
- if fill_in:
- dsvm = disable_ssl_certificate_validation
- auth_provider = auth_provider_class(
- creds, auth_url, disable_ssl_certificate_validation=dsvm,
- ca_certs=ca_certs, trace_requests=trace_requests)
- creds = auth_provider.fill_credentials()
- return creds
-
-
-class Credentials(object):
- """
- Set of credentials for accessing OpenStack services
-
- ATTRIBUTES: list of valid class attributes representing credentials.
- """
-
- ATTRIBUTES = []
-
- def __init__(self, **kwargs):
- """
- Enforce the available attributes at init time (only).
- Additional attributes can still be set afterwards if tests need
- to do so.
- """
- self._initial = kwargs
- self._apply_credentials(kwargs)
-
- def _apply_credentials(self, attr):
- for key in attr.keys():
- if key in self.ATTRIBUTES:
- setattr(self, key, attr[key])
- else:
- raise exceptions.InvalidCredentials
-
- def __str__(self):
- """
- Represent only attributes included in self.ATTRIBUTES
- """
- _repr = dict((k, getattr(self, k)) for k in self.ATTRIBUTES)
- return str(_repr)
-
- def __eq__(self, other):
- """
- Credentials are equal if attributes in self.ATTRIBUTES are equal
- """
- return str(self) == str(other)
-
- def __getattr__(self, key):
- # If an attribute is set, __getattr__ is not invoked
- # If an attribute is not set, and it is a known one, return None
- if key in self.ATTRIBUTES:
- return None
- else:
- raise AttributeError
-
- def __delitem__(self, key):
- # For backwards compatibility, support dict behaviour
- if key in self.ATTRIBUTES:
- delattr(self, key)
- else:
- raise AttributeError
-
- def get(self, item, default):
- # In this patch act as dict for backward compatibility
- try:
- return getattr(self, item)
- except AttributeError:
- return default
-
- def get_init_attributes(self):
- return self._initial.keys()
-
- def is_valid(self):
- raise NotImplementedError
-
- def reset(self):
- # First delete all known attributes
- for key in self.ATTRIBUTES:
- if getattr(self, key) is not None:
- delattr(self, key)
- # Then re-apply initial setup
- self._apply_credentials(self._initial)
-
-
-class KeystoneV2Credentials(Credentials):
-
- ATTRIBUTES = ['username', 'password', 'tenant_name', 'user_id',
- 'tenant_id']
-
- def is_valid(self):
- """
- Minimum set of valid credentials, are username and password.
- Tenant is optional.
- """
- return None not in (self.username, self.password)
-
-
-class KeystoneV3Credentials(Credentials):
- """
- Credentials suitable for the Keystone Identity V3 API
- """
-
- ATTRIBUTES = ['domain_id', 'domain_name', 'password', 'username',
- 'project_domain_id', 'project_domain_name', 'project_id',
- 'project_name', 'tenant_id', 'tenant_name', 'user_domain_id',
- 'user_domain_name', 'user_id']
-
- def __setattr__(self, key, value):
- parent = super(KeystoneV3Credentials, self)
- # for tenant_* set both project and tenant
- if key == 'tenant_id':
- parent.__setattr__('project_id', value)
- elif key == 'tenant_name':
- parent.__setattr__('project_name', value)
- # for project_* set both project and tenant
- if key == 'project_id':
- parent.__setattr__('tenant_id', value)
- elif key == 'project_name':
- parent.__setattr__('tenant_name', value)
- # for *_domain_* set both user and project if not set yet
- if key == 'user_domain_id':
- if self.project_domain_id is None:
- parent.__setattr__('project_domain_id', value)
- if key == 'project_domain_id':
- if self.user_domain_id is None:
- parent.__setattr__('user_domain_id', value)
- if key == 'user_domain_name':
- if self.project_domain_name is None:
- parent.__setattr__('project_domain_name', value)
- if key == 'project_domain_name':
- if self.user_domain_name is None:
- parent.__setattr__('user_domain_name', value)
- # support domain_name coming from config
- if key == 'domain_name':
- parent.__setattr__('user_domain_name', value)
- parent.__setattr__('project_domain_name', value)
- # finally trigger default behaviour for all attributes
- parent.__setattr__(key, value)
-
- def is_valid(self):
- """
- Valid combinations of v3 credentials (excluding token, scope)
- - User id, password (optional domain)
- - User name, password and its domain id/name
- For the scope, valid combinations are:
- - None
- - Project id (optional domain)
- - Project name and its domain id/name
- - Domain id
- - Domain name
- """
- valid_user_domain = any(
- [self.user_domain_id is not None,
- self.user_domain_name is not None])
- valid_project_domain = any(
- [self.project_domain_id is not None,
- self.project_domain_name is not None])
- valid_user = any(
- [self.user_id is not None,
- self.username is not None and valid_user_domain])
- valid_project_scope = any(
- [self.project_name is None and self.project_id is None,
- self.project_id is not None,
- self.project_name is not None and valid_project_domain])
- valid_domain_scope = any(
- [self.domain_id is None and self.domain_name is None,
- self.domain_id or self.domain_name])
- return all([self.password is not None,
- valid_user,
- valid_project_scope and valid_domain_scope])
-
-
-IDENTITY_VERSION = {'v2': (KeystoneV2Credentials, KeystoneV2AuthProvider),
- 'v3': (KeystoneV3Credentials, KeystoneV3AuthProvider)}
diff --git a/tempest/cli/README.rst b/tempest/cli/README.rst
deleted file mode 100644
index bc18084..0000000
--- a/tempest/cli/README.rst
+++ /dev/null
@@ -1,50 +0,0 @@
-.. _cli_field_guide:
-
-Tempest Field Guide to CLI tests
-================================
-
-
-What are these tests?
----------------------
-The cli tests test the various OpenStack command line interface tools
-to ensure that they minimally function. The current scope is read only
-operations on a cloud that are hard to test via unit tests.
-
-
-Why are these tests in tempest?
--------------------------------
-These tests exist here because it is extremely difficult to build a
-functional enough environment in the python-\*client unit tests to
-provide this kind of testing. Because we already put up a cloud in the
-gate with devstack + tempest it was decided it was better to have
-these as a side tree in tempest instead of another QA effort which
-would split review time.
-
-
-Scope of these tests
---------------------
-This should stay limited to the scope of testing the cli. Functional
-testing of the cloud should be elsewhere, this is about exercising the
-cli code.
-
-
-Example of a good test
-----------------------
-Tests should be isolated to a single command in one of the python
-clients.
-
-Tests should not modify the cloud.
-
-If a test is validating the cli for bad data, it should do it with
-assertRaises.
-
-A reasonable example of an existing test is as follows::
-
- def test_admin_list(self):
- self.nova('list')
- self.nova('list', params='--all-tenants 1')
- self.nova('list', params='--all-tenants 0')
- self.assertRaises(subprocess.CalledProcessError,
- self.nova,
- 'list',
- params='--all-tenants bad')
diff --git a/tempest/cli/__init__.py b/tempest/cli/__init__.py
deleted file mode 100644
index 6733204..0000000
--- a/tempest/cli/__init__.py
+++ /dev/null
@@ -1,126 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# 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 functools
-
-from tempest_lib.cli import base
-from tempest_lib.cli import output_parser
-import testtools
-
-from tempest.common import credentials
-from tempest import config
-from tempest import exceptions
-from tempest.openstack.common import versionutils
-from tempest import test
-
-
-CONF = config.CONF
-
-
-def check_client_version(client, version):
- """Checks if the client's version is compatible with the given version
-
- @param client: The client to check.
- @param version: The version to compare against.
- @return: True if the client version is compatible with the given version
- parameter, False otherwise.
- """
- current_version = base.execute(client, '', params='--version',
- merge_stderr=True, cli_dir=CONF.cli.cli_dir)
-
- if not current_version.strip():
- raise exceptions.TempestException('"%s --version" output was empty' %
- client)
-
- return versionutils.is_compatible(version, current_version,
- same_major=False)
-
-
-def min_client_version(*args, **kwargs):
- """A decorator to skip tests if the client used isn't of the right version.
-
- @param client: The client command to run. For python-novaclient, this is
- 'nova', for python-cinderclient this is 'cinder', etc.
- @param version: The minimum version required to run the CLI test.
- """
- def decorator(func):
- @functools.wraps(func)
- def wrapper(*func_args, **func_kwargs):
- if not check_client_version(kwargs['client'], kwargs['version']):
- msg = "requires %s client version >= %s" % (kwargs['client'],
- kwargs['version'])
- raise testtools.TestCase.skipException(msg)
- return func(*func_args, **func_kwargs)
- return wrapper
- return decorator
-
-
-class ClientTestBase(test.BaseTestCase):
-
- @classmethod
- def skip_checks(cls):
- super(ClientTestBase, cls).skip_checks()
- if not CONF.identity_feature_enabled.api_v2:
- raise cls.skipException("CLI clients rely on identity v2 API, "
- "which is configured as not available")
-
- @classmethod
- def resource_setup(cls):
- if not CONF.cli.enabled:
- msg = "cli testing disabled"
- raise cls.skipException(msg)
- super(ClientTestBase, cls).resource_setup()
- cls.isolated_creds = credentials.get_isolated_credentials(cls.__name__)
- cls.creds = cls.isolated_creds.get_admin_creds()
-
- def _get_clients(self):
- clients = base.CLIClient(self.creds.username,
- self.creds.password,
- self.creds.tenant_name,
- CONF.identity.uri, CONF.cli.cli_dir)
- return clients
-
- # TODO(mtreinish): The following code is basically copied from tempest-lib.
- # The base cli test class in tempest-lib 0.0.1 doesn't work as a mixin like
- # is needed here. The code below should be removed when tempest-lib
- # provides a way to provide this functionality
- def setUp(self):
- super(ClientTestBase, self).setUp()
- self.clients = self._get_clients()
- self.parser = output_parser
-
- def assertTableStruct(self, items, field_names):
- """Verify that all items has keys listed in field_names.
-
- :param items: items to assert are field names in the output table
- :type items: list
- :param field_names: field names from the output table of the cmd
- :type field_names: list
- """
- for item in items:
- for field in field_names:
- self.assertIn(field, item)
-
- def assertFirstLineStartsWith(self, lines, beginning):
- """Verify that the first line starts with a string
-
- :param lines: strings for each line of output
- :type lines: list
- :param beginning: verify this is at the beginning of the first line
- :type beginning: string
- """
- self.assertTrue(lines[0].startswith(beginning),
- msg=('Beginning of first line has invalid content: %s'
- % lines[:3]))
diff --git a/tempest/cli/simple_read_only/README.txt b/tempest/cli/simple_read_only/README.txt
deleted file mode 100644
index ca5fa2f..0000000
--- a/tempest/cli/simple_read_only/README.txt
+++ /dev/null
@@ -1 +0,0 @@
-This directory consists of simple read only python client tests.
diff --git a/tempest/cli/simple_read_only/__init__.py b/tempest/cli/simple_read_only/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/cli/simple_read_only/__init__.py
+++ /dev/null
diff --git a/tempest/cli/simple_read_only/heat_templates/heat_minimal.yaml b/tempest/cli/simple_read_only/heat_templates/heat_minimal.yaml
deleted file mode 100644
index 7dcda39..0000000
--- a/tempest/cli/simple_read_only/heat_templates/heat_minimal.yaml
+++ /dev/null
@@ -1,18 +0,0 @@
-HeatTemplateFormatVersion: '2012-12-12'
-Description: Minimal template to test validation
-Parameters:
- InstanceImage:
- Description: Glance image name
- Type: String
- InstanceType:
- Description: Nova instance type
- Type: String
- Default: m1.small
- AllowedValues: [m1.tiny, m1.small, m1.medium, m1.large, m1.nano, m1.xlarge, m1.micro]
- ConstraintDescription: must be a valid nova instance type.
-Resources:
- InstanceResource:
- Type: OS::Nova::Server
- Properties:
- flavor: {Ref: InstanceType}
- image: {Ref: InstanceImage}
diff --git a/tempest/cli/simple_read_only/heat_templates/heat_minimal_hot.yaml b/tempest/cli/simple_read_only/heat_templates/heat_minimal_hot.yaml
deleted file mode 100644
index 4657bfc..0000000
--- a/tempest/cli/simple_read_only/heat_templates/heat_minimal_hot.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-heat_template_version: 2013-05-23
-description: A minimal HOT test template
-parameters:
- instance_image:
- description: Glance image name
- type: string
- instance_type:
- description: Nova instance type
- type: string
- default: m1.small
- constraints:
- - allowed_values: [m1.small, m1.medium, m1.large]
- description: instance_type must be one of m1.small, m1.medium or m1.large
-resources:
- instance:
- type: OS::Nova::Server
- properties:
- image: { get_param: instance_image }
- flavor: { get_param: instance_type }
diff --git a/tempest/cli/simple_read_only/image/__init__.py b/tempest/cli/simple_read_only/image/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/cli/simple_read_only/image/__init__.py
+++ /dev/null
diff --git a/tempest/cli/simple_read_only/image/test_glance.py b/tempest/cli/simple_read_only/image/test_glance.py
deleted file mode 100644
index e38ca48..0000000
--- a/tempest/cli/simple_read_only/image/test_glance.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# 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 re
-
-from oslo_log import log as logging
-from tempest_lib import exceptions
-
-from tempest import cli
-from tempest import config
-from tempest import test
-
-CONF = config.CONF
-
-LOG = logging.getLogger(__name__)
-
-
-class SimpleReadOnlyGlanceClientTest(cli.ClientTestBase):
- """Basic, read-only tests for Glance CLI client.
-
- Checks return values and output of read-only commands.
- These tests do not presume any content, nor do they create
- their own. They only verify the structure of output if present.
- """
-
- @classmethod
- def resource_setup(cls):
- if not CONF.service_available.glance:
- msg = ("%s skipped as Glance is not available" % cls.__name__)
- raise cls.skipException(msg)
- super(SimpleReadOnlyGlanceClientTest, cls).resource_setup()
-
- def glance(self, *args, **kwargs):
- return self.clients.glance(*args,
- endpoint_type=CONF.image.endpoint_type,
- **kwargs)
-
- @test.idempotent_id('c6bd9bf9-717f-4458-8d74-05b682ea7adf')
- def test_glance_fake_action(self):
- self.assertRaises(exceptions.CommandFailed,
- self.glance,
- 'this-does-not-exist')
-
- @test.idempotent_id('72bcdaf3-11cd-48cb-bb8e-62b329acc1ef')
- def test_glance_image_list(self):
- out = self.glance('image-list')
- endpoints = self.parser.listing(out)
- self.assertTableStruct(endpoints, [
- 'ID', 'Name', 'Disk Format', 'Container Format',
- 'Size', 'Status'])
-
- @test.idempotent_id('965d294c-8772-4899-ba33-26ee23406135')
- def test_glance_member_list(self):
- tenant_name = '--tenant-id %s' % CONF.identity.admin_tenant_name
- out = self.glance('member-list',
- params=tenant_name)
- endpoints = self.parser.listing(out)
- self.assertTableStruct(endpoints,
- ['Image ID', 'Member ID', 'Can Share'])
-
- @test.idempotent_id('43b80ee5-4297-47f3-ab4c-6f81b9c6edb3')
- def test_glance_help(self):
- help_text = self.glance('help')
- lines = help_text.split('\n')
- self.assertFirstLineStartsWith(lines, 'usage: glance')
-
- commands = []
- cmds_start = lines.index('Positional arguments:')
- cmds_end = lines.index('Optional arguments:')
- command_pattern = re.compile('^ {4}([a-z0-9\-\_]+)')
- for line in lines[cmds_start:cmds_end]:
- match = command_pattern.match(line)
- if match:
- commands.append(match.group(1))
- commands = set(commands)
- wanted_commands = set(('image-create', 'image-delete', 'help',
- 'image-download', 'image-show', 'image-update',
- 'member-create', 'member-delete',
- 'member-list', 'image-list'))
- self.assertFalse(wanted_commands - commands)
-
- # Optional arguments:
-
- @test.idempotent_id('3b2359ea-3719-4b47-81e5-44a042572b11')
- def test_glance_version(self):
- self.glance('', flags='--version')
-
- @test.idempotent_id('1a52d3bd-3edf-4d67-b3da-999a5d9e0c5e')
- def test_glance_debug_list(self):
- self.glance('image-list', flags='--debug')
-
- @test.idempotent_id('6f42b076-f9a7-4e2b-a729-579f53e7814e')
- def test_glance_timeout(self):
- self.glance('image-list', flags='--timeout %d' % CONF.cli.timeout)
diff --git a/tempest/cli/simple_read_only/orchestration/__init__.py b/tempest/cli/simple_read_only/orchestration/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/cli/simple_read_only/orchestration/__init__.py
+++ /dev/null
diff --git a/tempest/cli/simple_read_only/orchestration/test_heat.py b/tempest/cli/simple_read_only/orchestration/test_heat.py
deleted file mode 100644
index 8defe51..0000000
--- a/tempest/cli/simple_read_only/orchestration/test_heat.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# 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 os
-
-from oslo_log import log as logging
-import yaml
-
-import tempest.cli
-from tempest import config
-from tempest import test
-
-CONF = config.CONF
-
-LOG = logging.getLogger(__name__)
-
-
-class SimpleReadOnlyHeatClientTest(tempest.cli.ClientTestBase):
- """Basic, read-only tests for Heat CLI client.
-
- Basic smoke test for the heat CLI commands which do not require
- creating or modifying stacks.
- """
-
- @classmethod
- def resource_setup(cls):
- if (not CONF.service_available.heat):
- msg = ("Skipping all Heat cli tests because it is "
- "not available")
- raise cls.skipException(msg)
- super(SimpleReadOnlyHeatClientTest, cls).resource_setup()
- cls.heat_template_path = os.path.join(os.path.dirname(
- os.path.dirname(os.path.realpath(__file__))),
- 'heat_templates/heat_minimal.yaml')
-
- def heat(self, *args, **kwargs):
- return self.clients.heat(
- *args, endpoint_type=CONF.orchestration.endpoint_type, **kwargs)
-
- @test.idempotent_id('0ae034bb-ce35-45e8-b7aa-3e339cd3140f')
- def test_heat_stack_list(self):
- self.heat('stack-list')
-
- @test.idempotent_id('a360d069-7250-4aed-9721-0a6f2db7c3fa')
- def test_heat_stack_list_debug(self):
- self.heat('stack-list', flags='--debug')
-
- @test.idempotent_id('e1b7c177-5ab4-4d3f-8a26-ea01ebbd2b8c')
- def test_heat_resource_template_fmt_default(self):
- ret = self.heat('resource-template OS::Nova::Server')
- self.assertIn('Type: OS::Nova::Server', ret)
-
- @test.idempotent_id('93f82f76-aab2-4910-9359-11cf48f2a46b')
- def test_heat_resource_template_fmt_arg_short_yaml(self):
- ret = self.heat('resource-template -F yaml OS::Nova::Server')
- self.assertIn('Type: OS::Nova::Server', ret)
- self.assertIsInstance(yaml.safe_load(ret), dict)
-
- @test.idempotent_id('7356a98c-e14d-43f0-8c25-c9f7daa0aafa')
- def test_heat_resource_template_fmt_arg_long_json(self):
- ret = self.heat('resource-template --format json OS::Nova::Server')
- self.assertIn('"Type": "OS::Nova::Server"', ret)
- self.assertIsInstance(json.loads(ret), dict)
-
- @test.idempotent_id('2fd99d20-beff-4667-b42e-de9095f671d7')
- def test_heat_resource_type_list(self):
- ret = self.heat('resource-type-list')
- rsrc_types = self.parser.listing(ret)
- self.assertTableStruct(rsrc_types, ['resource_type'])
-
- @test.idempotent_id('62f60dbf-d139-4698-b230-a09fb531d643')
- def test_heat_resource_type_show(self):
- rsrc_schema = self.heat('resource-type-show OS::Nova::Server')
- # resource-type-show returns a json resource schema
- self.assertIsInstance(json.loads(rsrc_schema), dict)
-
- @test.idempotent_id('6ca16ff7-9d5f-4448-a8c2-4cecc7b5ba3a')
- def test_heat_template_validate_yaml(self):
- ret = self.heat('template-validate -f %s' % self.heat_template_path)
- # On success template-validate returns a json representation
- # of the template parameters
- self.assertIsInstance(json.loads(ret), dict)
-
- @test.idempotent_id('35241014-16ea-4cb6-ad3e-4ee5f41446de')
- def test_heat_template_validate_hot(self):
- ret = self.heat('template-validate -f %s' % self.heat_template_path)
- self.assertIsInstance(json.loads(ret), dict)
-
- @test.idempotent_id('34d43e0a-36dc-4ea8-9b85-0189e3de89d8')
- def test_heat_help(self):
- self.heat('help')
-
- @tempest.cli.min_client_version(client='heat', version='0.2.7')
- @test.idempotent_id('c122c08b-839d-49d1-afd1-bc546b2d18d3')
- def test_heat_bash_completion(self):
- self.heat('bash-completion')
-
- @test.idempotent_id('1b045e12-2fa0-4895-9282-00668428dfbe')
- def test_heat_help_cmd(self):
- # Check requesting help for a specific command works
- help_text = self.heat('help resource-template')
- lines = help_text.split('\n')
- self.assertFirstLineStartsWith(lines, 'usage: heat resource-template')
-
- @test.idempotent_id('c7837f8f-d0a8-47fd-b75b-14ba3e3fa9a2')
- def test_heat_version(self):
- self.heat('', flags='--version')
diff --git a/tempest/cli/simple_read_only/volume/__init__.py b/tempest/cli/simple_read_only/volume/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/cli/simple_read_only/volume/__init__.py
+++ /dev/null
diff --git a/tempest/cli/simple_read_only/volume/test_cinder.py b/tempest/cli/simple_read_only/volume/test_cinder.py
deleted file mode 100644
index cb29cc8..0000000
--- a/tempest/cli/simple_read_only/volume/test_cinder.py
+++ /dev/null
@@ -1,220 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# 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 logging
-import re
-
-from tempest_lib import exceptions
-import testtools
-
-from tempest import cli
-from tempest import clients
-from tempest import config
-from tempest import test
-
-
-CONF = config.CONF
-LOG = logging.getLogger(__name__)
-
-
-class SimpleReadOnlyCinderClientTest(cli.ClientTestBase):
- """Basic, read-only tests for Cinder CLI client.
-
- Checks return values and output of read-only commands.
- These tests do not presume any content, nor do they create
- their own. They only verify the structure of output if present.
- """
-
- @classmethod
- def resource_setup(cls):
- if not CONF.service_available.cinder:
- msg = ("%s skipped as Cinder is not available" % cls.__name__)
- raise cls.skipException(msg)
- super(SimpleReadOnlyCinderClientTest, cls).resource_setup()
- id_cl = clients.AdminManager().identity_client
- tenant = id_cl.get_tenant_by_name(CONF.identity.admin_tenant_name)
- cls.admin_tenant_id = tenant['id']
-
- def cinder(self, *args, **kwargs):
- return self.clients.cinder(*args,
- endpoint_type=CONF.volume.endpoint_type,
- **kwargs)
-
- @test.idempotent_id('229bc6dc-d804-4668-b753-b590caf63061')
- def test_cinder_fake_action(self):
- self.assertRaises(exceptions.CommandFailed,
- self.cinder,
- 'this-does-not-exist')
-
- @test.idempotent_id('77140216-14db-4fc5-a246-e2a587e9e99b')
- def test_cinder_absolute_limit_list(self):
- roles = self.parser.listing(self.cinder('absolute-limits'))
- self.assertTableStruct(roles, ['Name', 'Value'])
-
- @test.idempotent_id('2206b9ce-1a36-4a0a-a129-e5afc7cee1dd')
- def test_cinder_backup_list(self):
- backup_list = self.parser.listing(self.cinder('backup-list'))
- self.assertTableStruct(backup_list, ['ID', 'Volume ID', 'Status',
- 'Name', 'Size', 'Object Count',
- 'Container'])
-
- @test.idempotent_id('c7f50346-cd99-4e0b-953f-796ff5f47295')
- def test_cinder_extra_specs_list(self):
- extra_specs_list = self.parser.listing(self.cinder('extra-specs-list'))
- self.assertTableStruct(extra_specs_list, ['ID', 'Name', 'extra_specs'])
-
- @test.idempotent_id('9de694cb-b40b-442c-a30c-5f9873e144f7')
- def test_cinder_volumes_list(self):
- list = self.parser.listing(self.cinder('list'))
- self.assertTableStruct(list, ['ID', 'Status', 'Name', 'Size',
- 'Volume Type', 'Bootable',
- 'Attached to'])
- self.cinder('list', params='--all-tenants 1')
- self.cinder('list', params='--all-tenants 0')
- self.assertRaises(exceptions.CommandFailed,
- self.cinder,
- 'list',
- params='--all-tenants bad')
-
- @test.idempotent_id('56f7c15c-ee82-4f23-bbe8-ce99b66da493')
- def test_cinder_quota_class_show(self):
- """This CLI can accept and string as param."""
- roles = self.parser.listing(self.cinder('quota-class-show',
- params='abc'))
- self.assertTableStruct(roles, ['Property', 'Value'])
-
- @test.idempotent_id('a919a811-b7f0-47a7-b4e5-f3eb674dd200')
- def test_cinder_quota_defaults(self):
- """This CLI can accept and string as param."""
- roles = self.parser.listing(self.cinder('quota-defaults',
- params=self.admin_tenant_id))
- self.assertTableStruct(roles, ['Property', 'Value'])
-
- @test.idempotent_id('18166673-ffa8-4df3-b60c-6375532288bc')
- def test_cinder_quota_show(self):
- """This CLI can accept and string as param."""
- roles = self.parser.listing(self.cinder('quota-show',
- params=self.admin_tenant_id))
- self.assertTableStruct(roles, ['Property', 'Value'])
-
- @test.idempotent_id('b2c66ed9-ca96-4dc4-94cc-8083e664e516')
- def test_cinder_rate_limits(self):
- rate_limits = self.parser.listing(self.cinder('rate-limits'))
- self.assertTableStruct(rate_limits, ['Verb', 'URI', 'Value', 'Remain',
- 'Unit', 'Next_Available'])
-
- @test.idempotent_id('7a19955b-807c-481a-a2ee-9d76733eac28')
- @testtools.skipUnless(CONF.volume_feature_enabled.snapshot,
- 'Volume snapshot not available.')
- def test_cinder_snapshot_list(self):
- snapshot_list = self.parser.listing(self.cinder('snapshot-list'))
- self.assertTableStruct(snapshot_list, ['ID', 'Volume ID', 'Status',
- 'Name', 'Size'])
-
- @test.idempotent_id('6e54ecd9-7ba9-490d-8e3b-294b67139e73')
- def test_cinder_type_list(self):
- type_list = self.parser.listing(self.cinder('type-list'))
- self.assertTableStruct(type_list, ['ID', 'Name'])
-
- @test.idempotent_id('2c363583-24a0-4980-b9cb-b50c0d241e82')
- def test_cinder_list_extensions(self):
- roles = self.parser.listing(self.cinder('list-extensions'))
- self.assertTableStruct(roles, ['Name', 'Summary', 'Alias', 'Updated'])
-
- @test.idempotent_id('691bd6df-30ad-4be7-927b-a02d62aaa38a')
- def test_cinder_credentials(self):
- credentials = self.parser.listing(self.cinder('credentials'))
- self.assertTableStruct(credentials, ['User Credentials', 'Value'])
-
- @test.idempotent_id('5c6d71a3-4904-4a3a-aec9-7fd4aa830e95')
- def test_cinder_availability_zone_list(self):
- zone_list = self.parser.listing(self.cinder('availability-zone-list'))
- self.assertTableStruct(zone_list, ['Name', 'Status'])
-
- @test.idempotent_id('9b0fd5a6-f955-42b9-a42f-6f542a80b9a3')
- def test_cinder_endpoints(self):
- out = self.cinder('endpoints')
- tables = self.parser.tables(out)
- for table in tables:
- headers = table['headers']
- self.assertTrue(2 >= len(headers))
- self.assertEqual('Value', headers[1])
-
- @test.idempotent_id('301b5ae1-9591-4e9f-999c-d525a9bdf822')
- def test_cinder_service_list(self):
- service_list = self.parser.listing(self.cinder('service-list'))
- self.assertTableStruct(service_list, ['Binary', 'Host', 'Zone',
- 'Status', 'State', 'Updated_at'])
-
- @test.idempotent_id('7260ae52-b462-461e-9048-36d0bccf92c6')
- def test_cinder_transfer_list(self):
- transfer_list = self.parser.listing(self.cinder('transfer-list'))
- self.assertTableStruct(transfer_list, ['ID', 'Volume ID', 'Name'])
-
- @test.idempotent_id('0976dea8-14f3-45a9-8495-3617fc4fbb13')
- def test_cinder_bash_completion(self):
- self.cinder('bash-completion')
-
- @test.idempotent_id('b7c00361-be80-4512-8735-5f98fc54f2a9')
- def test_cinder_qos_list(self):
- qos_list = self.parser.listing(self.cinder('qos-list'))
- self.assertTableStruct(qos_list, ['ID', 'Name', 'Consumer', 'specs'])
-
- @test.idempotent_id('2e92dc6e-22b5-4d94-abfc-b543b0c50a89')
- def test_cinder_encryption_type_list(self):
- encrypt_list = self.parser.listing(self.cinder('encryption-type-list'))
- self.assertTableStruct(encrypt_list, ['Volume Type ID', 'Provider',
- 'Cipher', 'Key Size',
- 'Control Location'])
-
- @test.idempotent_id('0ee6cb4c-8de6-4811-a7be-7f4bb75b80cc')
- def test_admin_help(self):
- help_text = self.cinder('help')
- lines = help_text.split('\n')
- self.assertFirstLineStartsWith(lines, 'usage: cinder')
-
- commands = []
- cmds_start = lines.index('Positional arguments:')
- cmds_end = lines.index('Optional arguments:')
- command_pattern = re.compile('^ {4}([a-z0-9\-\_]+)')
- for line in lines[cmds_start:cmds_end]:
- match = command_pattern.match(line)
- if match:
- commands.append(match.group(1))
- commands = set(commands)
- wanted_commands = set(('absolute-limits', 'list', 'help',
- 'quota-show', 'type-list', 'snapshot-list'))
- self.assertFalse(wanted_commands - commands)
-
- # Optional arguments:
-
- @test.idempotent_id('2fd6f530-183c-4bda-8918-1e59e36c26b9')
- def test_cinder_version(self):
- self.cinder('', flags='--version')
-
- @test.idempotent_id('306bac51-c443-4426-a6cf-583a953fcd68')
- def test_cinder_debug_list(self):
- self.cinder('list', flags='--debug')
-
- @test.idempotent_id('6d97fcd2-5dd1-429d-af70-030c949d86cd')
- def test_cinder_retries_list(self):
- self.cinder('list', flags='--retries 3')
-
- @test.idempotent_id('95a2850c-35b4-4159-bb93-51647a5ad232')
- def test_cinder_region_list(self):
- region = CONF.volume.region
- if not region:
- region = CONF.identity.region
- self.cinder('list', flags='--os-region-name ' + region)
diff --git a/tempest/clients.py b/tempest/clients.py
index e1b6eab..a0c9471 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -16,6 +16,8 @@
import copy
from oslo_log import log as logging
+from tempest_lib.services.identity.v2.token_client import TokenClientJSON
+from tempest_lib.services.identity.v3.token_client import V3TokenClientJSON
from tempest.common import cred_provider
from tempest.common import negative_rest_client
@@ -77,7 +79,6 @@
DatabaseVersionsClientJSON
from tempest.services.identity.v2.json.identity_client import \
IdentityClientJSON
-from tempest.services.identity.v2.json.token_client import TokenClientJSON
from tempest.services.identity.v3.json.credentials_client import \
CredentialsClientJSON
from tempest.services.identity.v3.json.endpoints_client import \
@@ -88,7 +89,6 @@
from tempest.services.identity.v3.json.region_client import RegionClientJSON
from tempest.services.identity.v3.json.service_client import \
ServiceClientJSON
-from tempest.services.identity.v3.json.token_client import V3TokenClientJSON
from tempest.services.image.v1.json.image_client import ImageClientJSON
from tempest.services.image.v2.json.image_client import ImageClientV2JSON
from tempest.services.messaging.json.messaging_client import \
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index f84771f..4e2af76 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -114,10 +114,11 @@
import netaddr
from oslo_log import log as logging
from oslo_utils import timeutils
+import six
+from tempest_lib import auth
from tempest_lib import exceptions as lib_exc
import yaml
-import tempest.auth
from tempest import config
from tempest.services.compute.json import flavors_client
from tempest.services.compute.json import floating_ips_client
@@ -175,7 +176,7 @@
}
object_storage_params.update(default_params)
- _creds = tempest.auth.KeystoneV2Credentials(
+ _creds = auth.KeystoneV2Credentials(
username=user,
password=pw,
tenant_name=tenant)
@@ -185,7 +186,7 @@
'ca_certs': CONF.identity.ca_certificates_file,
'trace_requests': CONF.debug.trace_requests
}
- _auth = tempest.auth.KeystoneV2AuthProvider(
+ _auth = auth.KeystoneV2AuthProvider(
_creds, CONF.identity.uri, **auth_provider_params)
self.identity = identity_client.IdentityClientJSON(
_auth,
@@ -416,7 +417,7 @@
that things like tenantId didn't drift across versions.
"""
LOG.info("checking users")
- for name, user in self.users.iteritems():
+ for name, user in six.iteritems(self.users):
client = keystone_admin()
found = client.identity.get_user(user['id'])
self.assertEqual(found['name'], user['name'])
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index f1965bc..70a8594 100755
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -335,25 +335,28 @@
CONF_PARSER.optionxform = str
CONF_PARSER.readfp(conf_file)
icreds = credentials.get_isolated_credentials('verify_tempest_config')
- os = clients.Manager(icreds.get_primary_creds())
- services = check_service_availability(os, update)
- results = {}
- for service in ['nova', 'cinder', 'neutron', 'swift']:
- if service not in services:
- continue
- results = verify_extensions(os, service, results)
+ try:
+ os = clients.Manager(icreds.get_primary_creds())
+ services = check_service_availability(os, update)
+ results = {}
+ for service in ['nova', 'cinder', 'neutron', 'swift']:
+ if service not in services:
+ continue
+ results = verify_extensions(os, service, results)
- # Verify API versions of all services in the keystone catalog and keystone
- # itself.
- services.append('keystone')
- for service in services:
- verify_api_versions(os, service, update)
+ # Verify API versions of all services in the keystone catalog and
+ # keystone itself.
+ services.append('keystone')
+ for service in services:
+ verify_api_versions(os, service, update)
- display_results(results, update, replace)
- if update:
- conf_file.close()
- CONF_PARSER.write(outfile)
- outfile.close()
+ display_results(results, update, replace)
+ if update:
+ conf_file.close()
+ CONF_PARSER.write(outfile)
+ outfile.close()
+ finally:
+ icreds.clear_isolated_creds()
if __name__ == "__main__":
diff --git a/tempest/common/accounts.py b/tempest/common/accounts.py
index 93c8bcf..650faf1 100644
--- a/tempest/common/accounts.py
+++ b/tempest/common/accounts.py
@@ -17,6 +17,7 @@
from oslo_concurrency import lockutils
from oslo_log import log as logging
+import six
import yaml
from tempest import clients
@@ -75,7 +76,7 @@
if 'resources' in account:
resources = account.pop('resources')
temp_hash = hashlib.md5()
- temp_hash.update(str(account))
+ temp_hash.update(six.text_type(account).encode('utf-8'))
temp_hash_key = temp_hash.hexdigest()
hash_dict['creds'][temp_hash_key] = account
for role in roles:
@@ -244,17 +245,19 @@
def get_creds_by_roles(self, roles, force_new=False):
roles = list(set(roles))
- exist_creds = self.isolated_creds.get(str(roles), None)
+ exist_creds = self.isolated_creds.get(six.text_type(roles).encode(
+ 'utf-8'), None)
# The force kwarg is used to allocate an additional set of creds with
# the same role list. The index used for the previously allocation
# in the isolated_creds dict will be moved.
if exist_creds and not force_new:
return exist_creds
elif exist_creds and force_new:
- new_index = str(roles) + '-' + str(len(self.isolated_creds))
+ new_index = six.text_type(roles).encode('utf-8') + '-' + \
+ six.text_type(len(self.isolated_creds)).encode('utf-8')
self.isolated_creds[new_index] = exist_creds
net_creds = self._get_creds(roles=roles)
- self.isolated_creds[str(roles)] = net_creds
+ self.isolated_creds[six.text_type(roles).encode('utf-8')] = net_creds
return net_creds
def clear_isolated_creds(self):
@@ -283,8 +286,11 @@
net_clients = clients.Manager(credentials=credential)
compute_network_client = net_clients.networks_client
net_name = self.hash_dict['networks'].get(hash, None)
- network = fixed_network.get_network_from_name(
- net_name, compute_network_client)
+ try:
+ network = fixed_network.get_network_from_name(
+ net_name, compute_network_client)
+ except exceptions.InvalidConfiguration:
+ network = {}
net_creds.set_resources(network=network)
return net_creds
diff --git a/tempest/common/cred_provider.py b/tempest/common/cred_provider.py
index 3223027..461097f 100644
--- a/tempest/common/cred_provider.py
+++ b/tempest/common/cred_provider.py
@@ -16,8 +16,8 @@
from oslo_log import log as logging
import six
+from tempest_lib import auth
-from tempest import auth
from tempest import config
from tempest import exceptions
diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py
index 298a94e..839088c 100644
--- a/tempest/common/custom_matchers.py
+++ b/tempest/common/custom_matchers.py
@@ -14,6 +14,7 @@
import re
+import six
from testtools import helpers
@@ -121,7 +122,7 @@
"""
def match(self, actual):
- for key, value in actual.iteritems():
+ for key, value in six.iteritems(actual):
if key in ('content-length', 'x-account-bytes-used',
'x-account-container-count', 'x-account-object-count',
'x-container-bytes-used', 'x-container-object-count')\
diff --git a/tempest/common/fixed_network.py b/tempest/common/fixed_network.py
index 1557474..2c6e334 100644
--- a/tempest/common/fixed_network.py
+++ b/tempest/common/fixed_network.py
@@ -17,6 +17,7 @@
from tempest_lib import exceptions as lib_exc
from tempest import config
+from tempest import exceptions
CONF = config.CONF
@@ -29,51 +30,59 @@
:param str name: the name of the network to use
:param NetworksClientJSON compute_networks_client: The network client
object to use for making the network lists api request
- :return: The full dictionary for the network in question, unless the
- network for the supplied name can not be found. In which case a dict
- with just the name will be returned.
+ :return: The full dictionary for the network in question
:rtype: dict
+ :raises InvalidConfiguration: If the name provided is invalid, the networks
+ list returns a 404, there are no found networks, or the found network
+ is invalid
"""
caller = misc_utils.find_test_caller()
+
if not name:
- network = {'name': name}
+ raise exceptions.InvalidConfiguration()
+
+ try:
+ networks = compute_networks_client.list_networks(name=name)
+ except lib_exc.NotFound:
+ # In case of nova network, if the fixed_network_name is not
+ # owned by the tenant, and the network client is not an admin
+ # one, list_networks will not find it
+ msg = ('Unable to find network %s. '
+ 'Starting instance without specifying a network.' %
+ name)
+ if caller:
+ msg = '(%s) %s' % (caller, msg)
+ LOG.info(msg)
+ raise exceptions.InvalidConfiguration()
+
+ # Check that a network exists, else raise an InvalidConfigurationException
+ if len(networks) == 1:
+ network = sorted(networks)[0]
+ elif len(networks) > 1:
+ msg = ("Network with name: %s had multiple matching networks in the "
+ "list response: %s\n Unable to specify a single network" % (
+ name, networks))
+ if caller:
+ msg = '(%s) %s' % (caller, msg)
+ LOG.warn(msg)
+ raise exceptions.InvalidConfiguration()
else:
- try:
- resp = compute_networks_client.list_networks(name=name)
- if isinstance(resp, list):
- networks = resp
- elif isinstance(resp, dict):
- networks = resp['networks']
- else:
- raise lib_exc.NotFound()
- if len(networks) > 0:
- network = networks[0]
- else:
- msg = "Network with name: %s not found" % name
- if caller:
- LOG.warn('(%s) %s' % (caller, msg))
- else:
- LOG.warn(msg)
- raise lib_exc.NotFound()
- # To be consistent with network isolation, add name is only
- # label is available
- name = network.get('name', network.get('label'))
- if name:
- network['name'] = name
- else:
- raise lib_exc.NotFound()
- except lib_exc.NotFound:
- # In case of nova network, if the fixed_network_name is not
- # owned by the tenant, and the network client is not an admin
- # one, list_networks will not find it
- msg = ('Unable to find network %s. '
- 'Starting instance without specifying a network.' %
- name)
- if caller:
- LOG.info('(%s) %s' % (caller, msg))
- else:
- LOG.info(msg)
- network = {'name': name}
+ msg = "Network with name: %s not found" % name
+ if caller:
+ msg = '(%s) %s' % (caller, msg)
+ LOG.warn(msg)
+ raise exceptions.InvalidConfiguration()
+ # To be consistent between neutron and nova network always use name even
+ # if label is used in the api response. If neither is present than then
+ # the returned network is invalid.
+ name = network.get('name') or network.get('label')
+ if not name:
+ msg = "Network found from list doesn't contain a valid name or label"
+ if caller:
+ msg = '(%s) %s' % (caller, msg)
+ LOG.warn(msg)
+ raise exceptions.InvalidConfiguration()
+ network['name'] = name
return network
@@ -97,16 +106,17 @@
msg = ('No valid network provided or created, defaulting to '
'fixed_network_name')
if caller:
- LOG.debug('(%s) %s' % (caller, msg))
- else:
- LOG.debug(msg)
- network = get_network_from_name(fixed_network_name,
- compute_networks_client)
+ msg = '(%s) %s' % (caller, msg)
+ LOG.debug(msg)
+ try:
+ network = get_network_from_name(fixed_network_name,
+ compute_networks_client)
+ except exceptions.InvalidConfiguration:
+ network = {}
msg = ('Found network %s available for tenant' % network)
if caller:
- LOG.info('(%s) %s' % (caller, msg))
- else:
- LOG.info(msg)
+ msg = '(%s) %s' % (caller, msg)
+ LOG.info(msg)
return network
diff --git a/tempest/common/generator/base_generator.py b/tempest/common/generator/base_generator.py
index f81f405..3e09300 100644
--- a/tempest/common/generator/base_generator.py
+++ b/tempest/common/generator/base_generator.py
@@ -17,8 +17,8 @@
import functools
import jsonschema
-
from oslo_log import log as logging
+import six
LOG = logging.getLogger(__name__)
@@ -122,7 +122,7 @@
if schema_type == 'object':
properties = schema["properties"]
- for attribute, definition in properties.iteritems():
+ for attribute, definition in six.iteritems(properties):
current_path = copy.copy(path)
if path is not None:
current_path.append(attribute)
diff --git a/tempest/common/generator/valid_generator.py b/tempest/common/generator/valid_generator.py
index 0c63bf5..2213b4a 100644
--- a/tempest/common/generator/valid_generator.py
+++ b/tempest/common/generator/valid_generator.py
@@ -14,6 +14,7 @@
# under the License.
from oslo_log import log as logging
+import six
import tempest.common.generator.base_generator as base
@@ -51,7 +52,7 @@
@base.simple_generator
def generate_valid_object(self, schema):
obj = {}
- for k, v in schema["properties"].iteritems():
+ for k, v in six.iteritems(schema["properties"]):
obj[k] = self.generate_valid(v)
return obj
diff --git a/tempest/common/ssh.py b/tempest/common/ssh.py
deleted file mode 100644
index d0e484c..0000000
--- a/tempest/common/ssh.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# 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 select
-import socket
-import time
-import warnings
-
-from oslo_log import log as logging
-import six
-from six import moves
-
-from tempest import exceptions
-
-
-with warnings.catch_warnings():
- warnings.simplefilter("ignore")
- import paramiko
-
-
-LOG = logging.getLogger(__name__)
-
-
-class Client(object):
-
- def __init__(self, host, username, password=None, timeout=300, pkey=None,
- channel_timeout=10, look_for_keys=False, key_filename=None):
- self.host = host
- self.username = username
- self.password = password
- if isinstance(pkey, six.string_types):
- pkey = paramiko.RSAKey.from_private_key(
- moves.cStringIO(str(pkey)))
- self.pkey = pkey
- self.look_for_keys = look_for_keys
- self.key_filename = key_filename
- self.timeout = int(timeout)
- self.channel_timeout = float(channel_timeout)
- self.buf_size = 1024
-
- def _get_ssh_connection(self, sleep=1.5, backoff=1):
- """Returns an ssh connection to the specified host."""
- bsleep = sleep
- ssh = paramiko.SSHClient()
- ssh.set_missing_host_key_policy(
- paramiko.AutoAddPolicy())
- _start_time = time.time()
- if self.pkey is not None:
- LOG.info("Creating ssh connection to '%s' as '%s'"
- " with public key authentication",
- self.host, self.username)
- else:
- LOG.info("Creating ssh connection to '%s' as '%s'"
- " with password %s",
- self.host, self.username, str(self.password))
- attempts = 0
- while True:
- try:
- ssh.connect(self.host, username=self.username,
- password=self.password,
- look_for_keys=self.look_for_keys,
- key_filename=self.key_filename,
- timeout=self.channel_timeout, pkey=self.pkey)
- LOG.info("ssh connection to %s@%s successfuly created",
- self.username, self.host)
- return ssh
- except (socket.error,
- paramiko.SSHException) as e:
- if self._is_timed_out(_start_time):
- LOG.exception("Failed to establish authenticated ssh"
- " connection to %s@%s after %d attempts",
- self.username, self.host, attempts)
- raise exceptions.SSHTimeout(host=self.host,
- user=self.username,
- password=self.password)
- bsleep += backoff
- attempts += 1
- LOG.warning("Failed to establish authenticated ssh"
- " connection to %s@%s (%s). Number attempts: %s."
- " Retry after %d seconds.",
- self.username, self.host, e, attempts, bsleep)
- time.sleep(bsleep)
-
- def _is_timed_out(self, start_time):
- return (time.time() - self.timeout) > start_time
-
- def exec_command(self, cmd):
- """
- Execute the specified command on the server.
-
- Note that this method is reading whole command outputs to memory, thus
- shouldn't be used for large outputs.
-
- :returns: data read from standard output of the command.
- :raises: SSHExecCommandFailed if command returns nonzero
- status. The exception contains command status stderr content.
- """
- ssh = self._get_ssh_connection()
- transport = ssh.get_transport()
- channel = transport.open_session()
- channel.fileno() # Register event pipe
- channel.exec_command(cmd)
- channel.shutdown_write()
- out_data = []
- err_data = []
- poll = select.poll()
- poll.register(channel, select.POLLIN)
- start_time = time.time()
-
- while True:
- ready = poll.poll(self.channel_timeout)
- if not any(ready):
- if not self._is_timed_out(start_time):
- continue
- raise exceptions.TimeoutException(
- "Command: '{0}' executed on host '{1}'.".format(
- cmd, self.host))
- if not ready[0]: # If there is nothing to read.
- continue
- out_chunk = err_chunk = None
- if channel.recv_ready():
- out_chunk = channel.recv(self.buf_size)
- out_data += out_chunk,
- if channel.recv_stderr_ready():
- err_chunk = channel.recv_stderr(self.buf_size)
- err_data += err_chunk,
- if channel.closed and not err_chunk and not out_chunk:
- break
- exit_status = channel.recv_exit_status()
- if 0 != exit_status:
- raise exceptions.SSHExecCommandFailed(
- command=cmd, exit_status=exit_status,
- strerror=''.join(err_data))
- return ''.join(out_data)
-
- def test_connection_auth(self):
- """Raises an exception when we can not connect to server via ssh."""
- connection = self._get_ssh_connection()
- connection.close()
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 29fb493..bedff1f 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -15,8 +15,8 @@
import time
import six
+from tempest_lib.common import ssh
-from tempest.common import ssh
from tempest import config
from tempest import exceptions
diff --git a/tempest/config.py b/tempest/config.py
index bcbe41f..a711b33 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -335,6 +335,13 @@
help="Does the test environment block migration support "
"cinder iSCSI volumes. Note, libvirt doesn't support this, "
"see https://bugs.launchpad.net/nova/+bug/1398999"),
+ # TODO(gilliard): Remove live_migrate_paused_instances at juno-eol.
+ cfg.BoolOpt('live_migrate_paused_instances',
+ default=False,
+ help="Does the test system allow live-migration of paused "
+ "instances? Note, this is more than just the ANDing of "
+ "paused and live_migrate, but all 3 should be set to True "
+ "to run those tests"),
cfg.BoolOpt('vnc_console',
default=False,
help='Enable VNC console. This configuration value should '
@@ -1091,25 +1098,6 @@
help="Timeout for unprovisioning an Ironic node.")
]
-cli_group = cfg.OptGroup(name='cli', title="cli Configuration Options")
-
-CLIGroup = [
- cfg.BoolOpt('enabled',
- default=True,
- help="enable cli tests"),
- cfg.StrOpt('cli_dir',
- default='/usr/local/bin',
- help="directory where python client binaries are located"),
- cfg.BoolOpt('has_manage',
- default=True,
- help=("Whether the tempest run location has access to the "
- "*-manage commands. In a pure blackbox environment "
- "it will not.")),
- cfg.IntOpt('timeout',
- default=15,
- help="Number of seconds to wait on a CLI timeout"),
-]
-
negative_group = cfg.OptGroup(name='negative', title="Negative Test Options")
NegativeGroup = [
@@ -1148,7 +1136,6 @@
(debug_group, DebugGroup),
(baremetal_group, BaremetalGroup),
(input_scenario_group, InputScenarioGroup),
- (cli_group, CLIGroup),
(negative_group, NegativeGroup)
]
@@ -1212,7 +1199,6 @@
self.debug = _CONF.debug
self.baremetal = _CONF.baremetal
self.input_scenario = _CONF['input-scenario']
- self.cli = _CONF.cli
self.negative = _CONF.negative
_CONF.set_default('domain_name', self.identity.admin_domain_name,
group='identity')
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 09f7016..15617c6 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -128,17 +128,6 @@
message = "Got identity error"
-class SSHTimeout(TempestException):
- message = ("Connection to the %(host)s via SSH timed out.\n"
- "User: %(user)s, Password: %(password)s")
-
-
-class SSHExecCommandFailed(TempestException):
- """Raised when remotely executed command returns nonzero status."""
- message = ("Command '%(command)s', exit status: %(exit_status)d, "
- "Error:\n%(strerror)s")
-
-
class ServerUnreachable(TempestException):
message = "The server is not reachable via the configured network"
diff --git a/tempest/manager.py b/tempest/manager.py
index 025ce65..c39d3e5 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -13,7 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest import auth
+from tempest_lib import auth
+
from tempest.common import cred_provider
from tempest import config
from tempest import exceptions
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 98bacf0..7e0c3b3 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -381,7 +381,7 @@
def _log_net_info(self, exc):
# network debug is called as part of ssh init
- if not isinstance(exc, exceptions.SSHTimeout):
+ if not isinstance(exc, lib_exc.SSHTimeout):
LOG.debug('Network information on a devstack host')
def create_server_snapshot(self, server, name=None):
@@ -741,7 +741,7 @@
# The target login is assumed to have been configured for
# key-based authentication by cloud-init.
try:
- for net_name, ip_addresses in server['addresses'].iteritems():
+ for net_name, ip_addresses in six.iteritems(server['addresses']):
for ip_address in ip_addresses:
self.check_vm_connectivity(ip_address['addr'],
username,
@@ -766,7 +766,7 @@
def ping_remote():
try:
source.ping_host(dest)
- except exceptions.SSHExecCommandFailed:
+ except lib_exc.SSHExecCommandFailed:
LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
% (dest, source.ssh_client.host))
return not should_succeed
diff --git a/tempest/scenario/test_baremetal_basic_ops.py b/tempest/scenario/test_baremetal_basic_ops.py
index 612a5a2..e54c25a 100644
--- a/tempest/scenario/test_baremetal_basic_ops.py
+++ b/tempest/scenario/test_baremetal_basic_ops.py
@@ -126,8 +126,9 @@
self.boot_instance()
self.validate_ports()
self.verify_connectivity()
- floating_ip = self.add_floating_ip()
- self.verify_connectivity(ip=floating_ip)
+ if CONF.compute.ssh_connect_method == 'floating':
+ floating_ip = self.add_floating_ip()
+ self.verify_connectivity(ip=floating_ip)
vm_client = self.get_remote_client(self.instance)
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
index 5aec01f..eb018eb 100644
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -12,9 +12,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-import HTMLParser
-import urllib
-import urllib2
+from six.moves import html_parser as HTMLParser
+from six.moves.urllib import parse
+from six.moves.urllib import request
from tempest import config
from tempest.scenario import manager
@@ -68,11 +68,11 @@
super(TestDashboardBasicOps, cls).setup_credentials()
def check_login_page(self):
- response = urllib2.urlopen(CONF.dashboard.dashboard_url)
+ response = request.urlopen(CONF.dashboard.dashboard_url)
self.assertIn("id_username", response.read())
def user_login(self, username, password):
- self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor())
+ self.opener = request.build_opener(request.HTTPCookieProcessor())
response = self.opener.open(CONF.dashboard.dashboard_url).read()
# Grab the CSRF token and default region
@@ -80,14 +80,14 @@
parser.feed(response)
# Prepare login form request
- req = urllib2.Request(CONF.dashboard.login_url)
+ req = request.Request(CONF.dashboard.login_url)
req.add_header('Content-type', 'application/x-www-form-urlencoded')
req.add_header('Referer', CONF.dashboard.dashboard_url)
params = {'username': username,
'password': password,
'region': parser.region,
'csrfmiddlewaretoken': parser.csrf_token}
- self.opener.open(req, urllib.urlencode(params))
+ self.opener.open(req, parse.urlencode(params))
def check_home_page(self):
response = self.opener.open(CONF.dashboard.dashboard_url)
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index 8f37d74..691c7c9 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -16,7 +16,9 @@
import tempfile
import time
-import urllib2
+
+import six
+from six.moves.urllib import request as urllib2
from tempest.common import commands
from tempest import config
@@ -158,7 +160,7 @@
1. SSH to the instance
2. Start two http backends listening on ports 80 and 88 respectively
"""
- for server_id, ip in self.server_ips.iteritems():
+ for server_id, ip in six.iteritems(self.server_ips):
private_key = self.servers_keypairs[server_id]['private_key']
server_name = self.servers_client.get_server(server_id)['name']
username = config.scenario.ssh_user
@@ -238,7 +240,7 @@
but with different ports to listen on.
"""
- for server_id, ip in self.server_fixed_ips.iteritems():
+ for server_id, ip in six.iteritems(self.server_fixed_ips):
if len(self.server_fixed_ips) == 1:
member1 = self._create_member(address=ip,
protocol_port=self.port1,
@@ -307,7 +309,7 @@
except urllib2.HTTPError:
continue
# Assert that each member of the pool gets balanced at least once
- for member, counter in counters.iteritems():
+ for member, counter in six.iteritems(counters):
self.assertGreater(counter, 0, 'Member %s never balanced' % member)
@test.idempotent_id('c0c6f1ca-603b-4509-9c0f-2c63f0d838ee')
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 16ff848..6e67c4b 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -16,6 +16,7 @@
import netaddr
from oslo_log import log as logging
+import six
from tempest import config
from tempest.scenario import manager
@@ -93,7 +94,7 @@
@staticmethod
def define_server_ips(srv):
- for net_name, nics in srv['addresses'].iteritems():
+ for net_name, nics in six.iteritems(srv['addresses']):
for nic in nics:
if nic['version'] == 6:
srv['accessIPv6'] = nic['addr']
diff --git a/tempest/scenario/utils.py b/tempest/scenario/utils.py
index 6c00d09..60eb1c3 100644
--- a/tempest/scenario/utils.py
+++ b/tempest/scenario/utils.py
@@ -23,7 +23,7 @@
import testtools
from tempest import clients
-from tempest.common import cred_provider
+from tempest.common import credentials
from tempest import config
from tempest import exceptions
@@ -41,7 +41,10 @@
self.non_ssh_image_pattern = \
CONF.input_scenario.non_ssh_image_regex
# Setup clients
- os = clients.Manager()
+ self.isolated_creds = credentials.get_isolated_credentials(
+ name='ScenarioImageUtils',
+ identity_version=CONF.identity.auth_version)
+ os = clients.Manager(self.isolated_creds.get_primary_creds())
self.images_client = os.images_client
self.flavors_client = os.flavors_client
@@ -100,8 +103,10 @@
digit=string.digits)
def __init__(self):
- os = clients.Manager(
- cred_provider.get_configured_credentials('user', fill_in=False))
+ self.isolated_creds = credentials.get_isolated_credentials(
+ name='InputScenarioUtils',
+ identity_version=CONF.identity.auth_version)
+ os = clients.Manager(self.isolated_creds.get_primary_creds())
self.images_client = os.images_client
self.flavors_client = os.flavors_client
self.image_pattern = CONF.input_scenario.image_regex
@@ -162,7 +167,7 @@
scenario_utils = InputScenarioUtils()
scenario_flavor = scenario_utils.scenario_flavors
scenario_image = scenario_utils.scenario_images
- except exceptions.InvalidConfiguration:
+ except (exceptions.InvalidConfiguration, TypeError):
return standard_tests
for test in testtools.iterate_tests(standard_tests):
setattr(test, 'scenarios', testscenarios.multiply_scenarios(
diff --git a/tempest/services/baremetal/base.py b/tempest/services/baremetal/base.py
index 4c6a5bf..1461198 100644
--- a/tempest/services/baremetal/base.py
+++ b/tempest/services/baremetal/base.py
@@ -12,9 +12,9 @@
import functools
import json
-import urllib
import six
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/compute/json/agents_client.py b/tempest/services/compute/json/agents_client.py
index 403437d..c69e483 100644
--- a/tempest/services/compute/json/agents_client.py
+++ b/tempest/services/compute/json/agents_client.py
@@ -13,7 +13,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute.v2_1 import agents as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/baremetal_nodes_client.py b/tempest/services/compute/json/baremetal_nodes_client.py
index e4a4e88..fa2d7f4 100644
--- a/tempest/services/compute/json/baremetal_nodes_client.py
+++ b/tempest/services/compute/json/baremetal_nodes_client.py
@@ -13,7 +13,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute import baremetal_nodes as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 2de43cf..80cbe4d 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute import flavors_access as schema_access
from tempest.api_schema.response.compute import flavors_extra_specs \
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index 5bad527..9568a5e 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -14,8 +14,8 @@
# under the License.
import json
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import floating_ips as schema
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index 088e695..287482f 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -13,7 +13,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute.v2_1 import hosts as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index 1223fef..5462efc 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -14,8 +14,8 @@
# under the License.
import json
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import images as schema
diff --git a/tempest/services/compute/json/migrations_client.py b/tempest/services/compute/json/migrations_client.py
index a65b655..009992c 100644
--- a/tempest/services/compute/json/migrations_client.py
+++ b/tempest/services/compute/json/migrations_client.py
@@ -13,7 +13,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute import migrations as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index d8c8d63..2855e13 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -14,8 +14,8 @@
# under the License.
import json
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import security_groups as schema
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index c9ba2c3..1af1b37 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -16,8 +16,8 @@
import json
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import servers as schema
diff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py
index fc2274d..e2d959b 100644
--- a/tempest/services/compute/json/services_client.py
+++ b/tempest/services/compute/json/services_client.py
@@ -15,7 +15,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute import services as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/tenant_usages_client.py b/tempest/services/compute/json/tenant_usages_client.py
index ff6e7a2..b7e2b2a 100644
--- a/tempest/services/compute/json/tenant_usages_client.py
+++ b/tempest/services/compute/json/tenant_usages_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.api_schema.response.compute.v2_1 import tenant_usages as schema
from tempest.common import service_client
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index ba5921e..4d7a7aa 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -15,8 +15,8 @@
import json
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.api_schema.response.compute.v2_1 import volumes as schema
diff --git a/tempest/services/database/json/limits_client.py b/tempest/services/database/json/limits_client.py
index ae758bc..f99ceaa 100644
--- a/tempest/services/database/json/limits_client.py
+++ b/tempest/services/database/json/limits_client.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/database/json/versions_client.py b/tempest/services/database/json/versions_client.py
index aa2fef7..0db9c6a 100644
--- a/tempest/services/database/json/versions_client.py
+++ b/tempest/services/database/json/versions_client.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/identity/v2/json/token_client.py b/tempest/services/identity/v2/json/token_client.py
deleted file mode 100644
index e61ac84..0000000
--- a/tempest/services/identity/v2/json/token_client.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# Copyright 2015 NEC Corporation. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import json
-from tempest_lib.common import rest_client
-from tempest_lib import exceptions as lib_exc
-
-from tempest.common import service_client
-from tempest import exceptions
-
-
-class TokenClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_url, disable_ssl_certificate_validation=None,
- ca_certs=None, trace_requests=None):
- dscv = disable_ssl_certificate_validation
- super(TokenClientJSON, self).__init__(
- None, None, None, disable_ssl_certificate_validation=dscv,
- ca_certs=ca_certs, trace_requests=trace_requests)
-
- # Normalize URI to ensure /tokens is in it.
- if 'tokens' not in auth_url:
- auth_url = auth_url.rstrip('/') + '/tokens'
-
- self.auth_url = auth_url
-
- def auth(self, user, password, tenant=None):
- creds = {
- 'auth': {
- 'passwordCredentials': {
- 'username': user,
- 'password': password,
- },
- }
- }
-
- if tenant:
- creds['auth']['tenantName'] = tenant
-
- body = json.dumps(creds)
- resp, body = self.post(self.auth_url, body=body)
- self.expected_success(200, resp.status)
-
- return service_client.ResponseBody(resp, body['access'])
-
- def auth_token(self, token_id, tenant=None):
- creds = {
- 'auth': {
- 'token': {
- 'id': token_id,
- },
- }
- }
-
- if tenant:
- creds['auth']['tenantName'] = tenant
-
- body = json.dumps(creds)
- resp, body = self.post(self.auth_url, body=body)
- self.expected_success(200, resp.status)
-
- return service_client.ResponseBody(resp, body['access'])
-
- def request(self, method, url, extra_headers=False, headers=None,
- body=None):
- """A simple HTTP request interface."""
- if headers is None:
- headers = self.get_headers(accept_type="json")
- elif extra_headers:
- try:
- headers.update(self.get_headers(accept_type="json"))
- except (ValueError, TypeError):
- headers = self.get_headers(accept_type="json")
-
- resp, resp_body = self.raw_request(url, method,
- headers=headers, body=body)
- self._log_request(method, url, resp)
-
- if resp.status in [401, 403]:
- resp_body = json.loads(resp_body)
- raise lib_exc.Unauthorized(resp_body['error']['message'])
- elif resp.status not in [200, 201]:
- raise exceptions.IdentityError(
- 'Unexpected status code {0}'.format(resp.status))
-
- if isinstance(resp_body, str):
- resp_body = json.loads(resp_body)
- return resp, resp_body
-
- def get_token(self, user, password, tenant, auth_data=False):
- """
- Returns (token id, token data) for supplied credentials
- """
- body = self.auth(user, password, tenant)
-
- if auth_data:
- return body['token']['id'], body
- else:
- return body['token']['id']
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index bc90fd1..f3d02a8 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/identity/v3/json/region_client.py b/tempest/services/identity/v3/json/region_client.py
index faaf43c..02df354 100644
--- a/tempest/services/identity/v3/json/region_client.py
+++ b/tempest/services/identity/v3/json/region_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/identity/v3/json/token_client.py b/tempest/services/identity/v3/json/token_client.py
deleted file mode 100644
index 3e37403..0000000
--- a/tempest/services/identity/v3/json/token_client.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# Copyright 2015 NEC Corporation. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import json
-from tempest_lib.common import rest_client
-from tempest_lib import exceptions as lib_exc
-
-from tempest.common import service_client
-from tempest import exceptions
-
-
-class V3TokenClientJSON(rest_client.RestClient):
-
- def __init__(self, auth_url, disable_ssl_certificate_validation=None,
- ca_certs=None, trace_requests=None):
- dscv = disable_ssl_certificate_validation
- super(V3TokenClientJSON, self).__init__(
- None, None, None, disable_ssl_certificate_validation=dscv,
- ca_certs=ca_certs, trace_requests=trace_requests)
- if not auth_url:
- raise exceptions.InvalidConfiguration('you must specify a v3 uri '
- 'if using the v3 identity '
- 'api')
- if 'auth/tokens' not in auth_url:
- auth_url = auth_url.rstrip('/') + '/auth/tokens'
-
- self.auth_url = auth_url
-
- def auth(self, user_id=None, username=None, password=None, project_id=None,
- project_name=None, user_domain_id=None, user_domain_name=None,
- project_domain_id=None, project_domain_name=None, domain_id=None,
- domain_name=None, token=None):
- """
- :param user_id: user id
- :param username: user name
- :param user_domain_id: the user domain id
- :param user_domain_name: the user domain name
- :param project_domain_id: the project domain id
- :param project_domain_name: the project domain name
- :param domain_id: a domain id to scope to
- :param domain_name: a domain name to scope to
- :param project_id: a project id to scope to
- :param project_name: a project name to scope to
- :param token: a token to re-scope.
-
- Accepts different combinations of credentials.
- Sample sample valid combinations:
- - token
- - token, project_name, project_domain_id
- - user_id, password
- - username, password, user_domain_id
- - username, password, project_name, user_domain_id, project_domain_id
- Validation is left to the server side.
- """
- creds = {
- 'auth': {
- 'identity': {
- 'methods': [],
- }
- }
- }
- id_obj = creds['auth']['identity']
- if token:
- id_obj['methods'].append('token')
- id_obj['token'] = {
- 'id': token
- }
-
- if (user_id or username) and password:
- id_obj['methods'].append('password')
- id_obj['password'] = {
- 'user': {
- 'password': password,
- }
- }
- if user_id:
- id_obj['password']['user']['id'] = user_id
- else:
- id_obj['password']['user']['name'] = username
-
- _domain = None
- if user_domain_id is not None:
- _domain = dict(id=user_domain_id)
- elif user_domain_name is not None:
- _domain = dict(name=user_domain_name)
- if _domain:
- id_obj['password']['user']['domain'] = _domain
-
- if (project_id or project_name):
- _project = dict()
-
- if project_id:
- _project['id'] = project_id
- elif project_name:
- _project['name'] = project_name
-
- if project_domain_id is not None:
- _project['domain'] = {'id': project_domain_id}
- elif project_domain_name is not None:
- _project['domain'] = {'name': project_domain_name}
-
- creds['auth']['scope'] = dict(project=_project)
- elif domain_id:
- creds['auth']['scope'] = dict(domain={'id': domain_id})
- elif domain_name:
- creds['auth']['scope'] = dict(domain={'name': domain_name})
-
- body = json.dumps(creds)
- resp, body = self.post(self.auth_url, body=body)
- self.expected_success(201, resp.status)
- return service_client.ResponseBody(resp, body)
-
- def request(self, method, url, extra_headers=False, headers=None,
- body=None):
- """A simple HTTP request interface."""
- if headers is None:
- # Always accept 'json', for xml token client too.
- # Because XML response is not easily
- # converted to the corresponding JSON one
- headers = self.get_headers(accept_type="json")
- elif extra_headers:
- try:
- headers.update(self.get_headers(accept_type="json"))
- except (ValueError, TypeError):
- headers = self.get_headers(accept_type="json")
-
- resp, resp_body = self.raw_request(url, method,
- headers=headers, body=body)
- self._log_request(method, url, resp)
-
- if resp.status in [401, 403]:
- resp_body = json.loads(resp_body)
- raise lib_exc.Unauthorized(resp_body['error']['message'])
- elif resp.status not in [200, 201, 204]:
- raise exceptions.IdentityError(
- 'Unexpected status code {0}'.format(resp.status))
-
- return resp, json.loads(resp_body)
-
- def get_token(self, **kwargs):
- """
- Returns (token id, token data) for supplied credentials
- """
-
- auth_data = kwargs.pop('auth_data', False)
-
- if not (kwargs.get('user_domain_id') or
- kwargs.get('user_domain_name')):
- kwargs['user_domain_name'] = 'Default'
-
- if not (kwargs.get('project_domain_id') or
- kwargs.get('project_domain_name')):
- kwargs['project_domain_name'] = 'Default'
-
- body = self.auth(**kwargs)
-
- token = body.response.get('x-subject-token')
- if auth_data:
- return token, body['token']
- else:
- return token
diff --git a/tempest/services/image/v1/json/image_client.py b/tempest/services/image/v1/json/image_client.py
index ec7900b..5e442fa 100644
--- a/tempest/services/image/v1/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -18,9 +18,10 @@
import json
import os
import time
-import urllib
from oslo_log import log as logging
+import six
+from six.moves.urllib import parse as urllib
from tempest_lib.common.utils import misc as misc_utils
from tempest_lib import exceptions as lib_exc
@@ -54,7 +55,7 @@
def _image_meta_from_headers(self, headers):
meta = {'properties': {}}
- for key, value in headers.iteritems():
+ for key, value in six.iteritems(headers):
if key.startswith('x-image-meta-property-'):
_key = key[22:]
meta['properties'][_key] = value
@@ -80,11 +81,11 @@
copy_from = fields_copy.pop('copy_from', None)
if copy_from is not None:
headers['x-glance-api-copy-from'] = copy_from
- for key, value in fields_copy.pop('properties', {}).iteritems():
+ for key, value in six.iteritems(fields_copy.pop('properties', {})):
headers['x-image-meta-property-%s' % key] = str(value)
- for key, value in fields_copy.pop('api', {}).iteritems():
+ for key, value in six.iteritems(fields_copy.pop('api', {})):
headers['x-glance-api-property-%s' % key] = str(value)
- for key, value in fields_copy.iteritems():
+ for key, value in six.iteritems(fields_copy):
headers['x-image-meta-%s' % key] = str(value)
return headers
diff --git a/tempest/services/image/v2/json/image_client.py b/tempest/services/image/v2/json/image_client.py
index 6b04144..aff8e85 100644
--- a/tempest/services/image/v2/json/image_client.py
+++ b/tempest/services/image/v2/json/image_client.py
@@ -14,9 +14,9 @@
# under the License.
import json
-import urllib
import jsonschema
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import glance_http
diff --git a/tempest/services/messaging/json/messaging_client.py b/tempest/services/messaging/json/messaging_client.py
index 483ba93..5f6c32a 100644
--- a/tempest/services/messaging/json/messaging_client.py
+++ b/tempest/services/messaging/json/messaging_client.py
@@ -14,9 +14,10 @@
# limitations under the License.
import json
-import urllib
import uuid
+from six.moves.urllib import parse as urllib
+
from tempest.api_schema.response.messaging.v1 import queues as queues_schema
from tempest.common import service_client
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 53645a5..e93cc47 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -12,8 +12,8 @@
import json
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib.common.utils import misc
from tempest_lib import exceptions as lib_exc
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index af00eff..dece763 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -14,9 +14,10 @@
# under the License.
import json
-import urllib
from xml.etree import ElementTree as etree
+from six.moves.urllib import parse as urllib
+
from tempest.common import service_client
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index ed74de4..8e225b0 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -14,9 +14,10 @@
# under the License.
import json
-import urllib
from xml.etree import ElementTree as etree
+from six.moves.urllib import parse as urllib
+
from tempest.common import service_client
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 3466c8a..2265587 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -13,8 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
-
+import six
from six.moves import http_client as httplib
from six.moves.urllib import parse as urlparse
@@ -36,7 +35,7 @@
headers[str(key)] = metadata[key]
url = "%s/%s" % (str(container), str(object_name))
if params:
- url += '?%s' % urllib.urlencode(params)
+ url += '?%s' % urlparse.urlencode(params)
resp, body = self.put(url, data, headers)
self.expected_success(201, resp.status)
@@ -52,7 +51,7 @@
"""Delete storage object."""
url = "%s/%s" % (str(container), str(object_name))
if params:
- url += '?%s' % urllib.urlencode(params)
+ url += '?%s' % urlparse.urlencode(params)
resp, body = self.delete(url, headers={})
self.expected_success([200, 204], resp.status)
return resp, body
@@ -234,7 +233,7 @@
headers = {}
if hasattr(contents, 'read'):
conn.putrequest('PUT', path)
- for header, value in headers.iteritems():
+ for header, value in six.iteritems(headers):
conn.putheader(header, value)
if 'Content-Length' not in headers:
if 'Transfer-Encoding' not in headers:
diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py
index debf39b..4d443d3 100644
--- a/tempest/services/orchestration/json/orchestration_client.py
+++ b/tempest/services/orchestration/json/orchestration_client.py
@@ -16,8 +16,8 @@
import json
import re
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import service_client
diff --git a/tempest/services/telemetry/json/telemetry_client.py b/tempest/services/telemetry/json/telemetry_client.py
index 0c01908..554f574 100644
--- a/tempest/services/telemetry/json/telemetry_client.py
+++ b/tempest/services/telemetry/json/telemetry_client.py
@@ -13,9 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
-
from oslo_serialization import jsonutils as json
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/volume/json/admin/volume_hosts_client.py b/tempest/services/volume/json/admin/volume_hosts_client.py
index 1cd92b7..1dfabaf 100644
--- a/tempest/services/volume/json/admin/volume_hosts_client.py
+++ b/tempest/services/volume/json/admin/volume_hosts_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/volume/json/admin/volume_quotas_client.py b/tempest/services/volume/json/admin/volume_quotas_client.py
index 5092afc..cbab3f0 100644
--- a/tempest/services/volume/json/admin/volume_quotas_client.py
+++ b/tempest/services/volume/json/admin/volume_quotas_client.py
@@ -12,9 +12,8 @@
# License for the specific language governing permissions and limitations
# under the License.
-import urllib
-
from oslo_serialization import jsonutils
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/volume/json/admin/volume_services_client.py b/tempest/services/volume/json/admin/volume_services_client.py
index 1c4433f..94792e0 100644
--- a/tempest/services/volume/json/admin/volume_services_client.py
+++ b/tempest/services/volume/json/admin/volume_services_client.py
@@ -14,7 +14,8 @@
# under the License.
import json
-import urllib
+
+from six.moves.urllib import parse as urllib
from tempest.common import service_client
diff --git a/tempest/services/volume/json/admin/volume_types_client.py b/tempest/services/volume/json/admin/volume_types_client.py
index 9366984..2436d88 100644
--- a/tempest/services/volume/json/admin/volume_types_client.py
+++ b/tempest/services/volume/json/admin/volume_types_client.py
@@ -14,8 +14,8 @@
# under the License.
import json
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import service_client
diff --git a/tempest/services/volume/json/snapshots_client.py b/tempest/services/volume/json/snapshots_client.py
index 2140c62..cfa02bd 100644
--- a/tempest/services/volume/json/snapshots_client.py
+++ b/tempest/services/volume/json/snapshots_client.py
@@ -12,9 +12,9 @@
import json
import time
-import urllib
from oslo_log import log as logging
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import service_client
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index a82291a..9a08bbd 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -15,8 +15,8 @@
import json
import time
-import urllib
+from six.moves.urllib import parse as urllib
from tempest_lib import exceptions as lib_exc
from tempest.common import service_client
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index 62e60d6..3f8e537 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -19,12 +19,13 @@
from oslo_log import log as logging
from oslo_utils import importutils
+import six
from six import moves
+from tempest_lib.common import ssh
from tempest_lib.common.utils import data_utils
from tempest import clients
from tempest.common import isolated_creds
-from tempest.common import ssh
from tempest import config
from tempest import exceptions
from tempest.stress import cleanup
@@ -171,7 +172,7 @@
test_run = test_obj(manager, max_runs, stop_on_error)
kwargs = test.get('kwargs', {})
- test_run.setUp(**dict(kwargs.iteritems()))
+ test_run.setUp(**dict(six.iteritems(kwargs)))
LOG.debug("calling Target Object %s" %
test_run.__class__.__name__)
diff --git a/tempest/test_discover/test_discover.py b/tempest/test_discover/test_discover.py
index 3fbb8e1..4a4b43a 100644
--- a/tempest/test_discover/test_discover.py
+++ b/tempest/test_discover/test_discover.py
@@ -25,7 +25,7 @@
suite = unittest.TestSuite()
base_path = os.path.split(os.path.dirname(os.path.abspath(__file__)))[0]
base_path = os.path.split(base_path)[0]
- for test_dir in ['./tempest/api', './tempest/cli', './tempest/scenario',
+ for test_dir in ['./tempest/api', './tempest/scenario',
'./tempest/thirdparty']:
if not pattern:
suite.addTests(loader.discover(test_dir, top_level_dir=base_path))
diff --git a/tempest/tests/cli/__init__.py b/tempest/tests/cli/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/tests/cli/__init__.py
+++ /dev/null
diff --git a/tempest/tests/cli/test_cli.py b/tempest/tests/cli/test_cli.py
deleted file mode 100644
index 8f18dfc..0000000
--- a/tempest/tests/cli/test_cli.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright 2014 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 mock
-from tempest_lib.cli import base as cli_base
-import testtools
-
-from tempest import cli
-from tempest import config
-from tempest import exceptions
-from tempest.tests import base
-from tempest.tests import fake_config
-
-
-class TestMinClientVersion(base.TestCase):
- """Tests for the min_client_version decorator.
- """
-
- def setUp(self):
- super(TestMinClientVersion, self).setUp()
- self.useFixture(fake_config.ConfigFixture())
- self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
-
- def _test_min_version(self, required, installed, expect_skip):
-
- @cli.min_client_version(client='nova', version=required)
- def fake(self, expect_skip):
- if expect_skip:
- # If we got here, the decorator didn't raise a skipException as
- # expected so we need to fail.
- self.fail('Should not have gotten past the decorator.')
-
- with mock.patch.object(cli_base, 'execute',
- return_value=installed) as mock_cmd:
- if expect_skip:
- self.assertRaises(testtools.TestCase.skipException, fake,
- self, expect_skip)
- else:
- fake(self, expect_skip)
- mock_cmd.assert_called_once_with('nova', '', params='--version',
- cli_dir='/usr/local/bin',
- merge_stderr=True)
-
- def test_min_client_version(self):
- # required, installed, expect_skip
- cases = (('2.17.0', '2.17.0', False),
- ('2.17.0', '2.18.0', False),
- ('2.18.0', '2.17.0', True))
-
- for case in cases:
- self._test_min_version(*case)
-
- @mock.patch.object(cli_base, 'execute', return_value=' ')
- def test_check_client_version_empty_output(self, mock_execute):
- # Tests that an exception is raised if the command output is empty.
- self.assertRaises(exceptions.TempestException,
- cli.check_client_version, 'nova', '2.18.0')
diff --git a/tempest/tests/common/test_accounts.py b/tempest/tests/common/test_accounts.py
index b4048ba..87c4bb3 100644
--- a/tempest/tests/common/test_accounts.py
+++ b/tempest/tests/common/test_accounts.py
@@ -20,13 +20,14 @@
from oslo_concurrency import lockutils
from oslo_config import cfg
from oslotest import mockpatch
+import six
+from tempest_lib import auth
+from tempest_lib.services.identity.v2 import token_client
-from tempest import auth
from tempest.common import accounts
from tempest.common import cred_provider
from tempest import config
from tempest import exceptions
-from tempest.services.identity.v2.json import token_client
from tempest.tests import base
from tempest.tests import fake_config
from tempest.tests import fake_http
@@ -79,7 +80,7 @@
hash_list = []
for account in accounts_list:
hash = hashlib.md5()
- hash.update(str(account))
+ hash.update(six.text_type(account).encode('utf-8'))
temp_hash = hash.hexdigest()
hash_list.append(temp_hash)
return hash_list
@@ -265,7 +266,7 @@
'tempest.common.accounts.read_accounts_yaml',
return_value=self.test_accounts))
test_accounts_class = accounts.Accounts('v2', 'test_name')
- hashes = test_accounts_class.hash_dict['creds'].keys()
+ hashes = list(test_accounts_class.hash_dict['creds'].keys())
admin_hashes = test_accounts_class.hash_dict['roles'][
cfg.CONF.identity.admin_role]
temp_hash = hashes[0]
diff --git a/tempest/tests/common/test_cred_provider.py b/tempest/tests/common/test_cred_provider.py
index 76430ac..ed3f931 100644
--- a/tempest/tests/common/test_cred_provider.py
+++ b/tempest/tests/common/test_cred_provider.py
@@ -13,21 +13,21 @@
# under the License.
from oslo_config import cfg
+from tempest_lib import auth
+from tempest_lib import exceptions as lib_exc
+from tempest_lib.services.identity.v2 import token_client as v2_client
+from tempest_lib.services.identity.v3 import token_client as v3_client
-from tempest import auth
+
from tempest.common import cred_provider
from tempest.common import tempest_fixtures as fixtures
from tempest import config
-from tempest.services.identity.v2.json import token_client as v2_client
-from tempest.services.identity.v3.json import token_client as v3_client
+from tempest.tests import base
from tempest.tests import fake_config
from tempest.tests import fake_identity
-# Note(andreaf): once credentials tests move to tempest-lib, I will copy the
-# parts of them required by these here.
-from tempest.tests import test_credentials as test_creds
-class ConfiguredV2CredentialsTests(test_creds.CredentialsTests):
+class ConfiguredV2CredentialsTests(base.TestCase):
attributes = {
'username': 'fake_username',
'password': 'fake_password',
@@ -46,6 +46,23 @@
self.stubs.Set(self.tokenclient_class, 'raw_request',
self.identity_response)
+ def _get_credentials(self, attributes=None):
+ if attributes is None:
+ attributes = self.attributes
+ return self.credentials_class(**attributes)
+
+ def _check(self, credentials, credentials_class, filled):
+ # Check the right version of credentials has been returned
+ self.assertIsInstance(credentials, credentials_class)
+ # Check the id attributes are filled in
+ attributes = [x for x in credentials.ATTRIBUTES if (
+ '_id' in x and x != 'domain_id')]
+ for attr in attributes:
+ if filled:
+ self.assertIsNotNone(getattr(credentials, attr))
+ else:
+ self.assertIsNone(getattr(credentials, attr))
+
def _verify_credentials(self, credentials_class, filled=True,
identity_version=None):
for ctype in cred_provider.CREDENTIAL_TYPES:
@@ -58,6 +75,15 @@
identity_version=identity_version)
self._check(creds, credentials_class, filled)
+ def test_create(self):
+ creds = self._get_credentials()
+ self.assertEqual(self.attributes, creds._initial)
+
+ def test_create_invalid_attr(self):
+ self.assertRaises(lib_exc.InvalidCredentials,
+ self._get_credentials,
+ attributes=dict(invalid='fake'))
+
def test_get_configured_credentials(self):
self.useFixture(fixtures.LockFixture('auth_version'))
self._verify_credentials(credentials_class=self.credentials_class)
diff --git a/tempest/tests/fake_credentials.py b/tempest/tests/fake_credentials.py
deleted file mode 100644
index 649d51d..0000000
--- a/tempest/tests/fake_credentials.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2014 Hewlett-Packard Development Company, L.P.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-from tempest import auth
-
-
-class FakeCredentials(auth.Credentials):
-
- def is_valid(self):
- return True
-
-
-class FakeKeystoneV2Credentials(auth.KeystoneV2Credentials):
-
- def __init__(self):
- creds = dict(
- username='fake_username',
- password='fake_password',
- tenant_name='fake_tenant_name'
- )
- super(FakeKeystoneV2Credentials, self).__init__(**creds)
-
-
-class FakeKeystoneV3Credentials(auth.KeystoneV3Credentials):
- """
- Fake credentials suitable for the Keystone Identity V3 API
- """
-
- def __init__(self):
- creds = dict(
- username='fake_username',
- password='fake_password',
- user_domain_name='fake_domain_name',
- project_name='fake_tenant_name',
- project_domain_name='fake_domain_name'
- )
- super(FakeKeystoneV3Credentials, self).__init__(**creds)
-
-
-class FakeKeystoneV3DomainCredentials(auth.KeystoneV3Credentials):
- """
- Fake credentials suitable for the Keystone Identity V3 API, with no scope
- """
-
- def __init__(self):
- creds = dict(
- username='fake_username',
- password='fake_password',
- user_domain_name='fake_domain_name'
- )
- super(FakeKeystoneV3DomainCredentials, self).__init__(**creds)
diff --git a/tempest/tests/negative/test_negative_generators.py b/tempest/tests/negative/test_negative_generators.py
index 2fa6933..78fd80d 100644
--- a/tempest/tests/negative/test_negative_generators.py
+++ b/tempest/tests/negative/test_negative_generators.py
@@ -17,6 +17,7 @@
import jsonschema
import mock
+import six
from tempest.common.generator import base_generator
from tempest.common.generator import negative_generator
@@ -101,11 +102,11 @@
class fake_test_class(object):
def __init__(self, scenario):
- for k, v in scenario.iteritems():
+ for k, v in six.iteritems(scenario):
setattr(self, k, v)
def _validate_result(self, valid_schema, invalid_schema):
- for k, v in valid_schema.iteritems():
+ for k, v in six.iteritems(valid_schema):
self.assertTrue(k in invalid_schema)
def test_generator_mandatory_functions(self):
diff --git a/tempest/tests/test_auth.py b/tempest/tests/test_auth.py
deleted file mode 100644
index eb63b30..0000000
--- a/tempest/tests/test_auth.py
+++ /dev/null
@@ -1,411 +0,0 @@
-# Copyright 2014 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 copy
-import datetime
-
-from oslotest import mockpatch
-
-from tempest import auth
-from tempest import exceptions
-from tempest.services.identity.v2.json import token_client as v2_client
-from tempest.services.identity.v3.json import token_client as v3_client
-from tempest.tests import base
-from tempest.tests import fake_credentials
-from tempest.tests import fake_http
-from tempest.tests import fake_identity
-
-
-def fake_get_credentials(fill_in=True, identity_version='v2', **kwargs):
- return fake_credentials.FakeCredentials()
-
-
-class BaseAuthTestsSetUp(base.TestCase):
- _auth_provider_class = None
- credentials = fake_credentials.FakeCredentials()
-
- def _auth(self, credentials, auth_url, **params):
- """
- returns auth method according to keystone
- """
- return self._auth_provider_class(credentials, auth_url, **params)
-
- def setUp(self):
- super(BaseAuthTestsSetUp, self).setUp()
- self.fake_http = fake_http.fake_httplib2(return_type=200)
- self.stubs.Set(auth, 'get_credentials', fake_get_credentials)
- self.auth_provider = self._auth(self.credentials,
- fake_identity.FAKE_AUTH_URL)
-
-
-class TestBaseAuthProvider(BaseAuthTestsSetUp):
- """
- This tests auth.AuthProvider class which is base for the other so we
- obviously don't test not implemented method or the ones which strongly
- depends on them.
- """
-
- class FakeAuthProviderImpl(auth.AuthProvider):
- def _decorate_request():
- pass
-
- def _fill_credentials():
- pass
-
- def _get_auth():
- pass
-
- def base_url():
- pass
-
- def is_expired():
- pass
-
- _auth_provider_class = FakeAuthProviderImpl
-
- def _auth(self, credentials, auth_url, **params):
- """
- returns auth method according to keystone
- """
- return self._auth_provider_class(credentials, **params)
-
- def test_check_credentials_bad_type(self):
- self.assertFalse(self.auth_provider.check_credentials([]))
-
- def test_auth_data_property_when_cache_exists(self):
- self.auth_provider.cache = 'foo'
- self.useFixture(mockpatch.PatchObject(self.auth_provider,
- 'is_expired',
- return_value=False))
- self.assertEqual('foo', getattr(self.auth_provider, 'auth_data'))
-
- def test_delete_auth_data_property_through_deleter(self):
- self.auth_provider.cache = 'foo'
- del self.auth_provider.auth_data
- self.assertIsNone(self.auth_provider.cache)
-
- def test_delete_auth_data_property_through_clear_auth(self):
- self.auth_provider.cache = 'foo'
- self.auth_provider.clear_auth()
- self.assertIsNone(self.auth_provider.cache)
-
- def test_set_and_reset_alt_auth_data(self):
- self.auth_provider.set_alt_auth_data('foo', 'bar')
- self.assertEqual(self.auth_provider.alt_part, 'foo')
- self.assertEqual(self.auth_provider.alt_auth_data, 'bar')
-
- self.auth_provider.reset_alt_auth_data()
- self.assertIsNone(self.auth_provider.alt_part)
- self.assertIsNone(self.auth_provider.alt_auth_data)
-
- def test_auth_class(self):
- self.assertRaises(TypeError,
- auth.AuthProvider,
- fake_credentials.FakeCredentials)
-
-
-class TestKeystoneV2AuthProvider(BaseAuthTestsSetUp):
- _endpoints = fake_identity.IDENTITY_V2_RESPONSE['access']['serviceCatalog']
- _auth_provider_class = auth.KeystoneV2AuthProvider
- credentials = fake_credentials.FakeKeystoneV2Credentials()
-
- def setUp(self):
- super(TestKeystoneV2AuthProvider, self).setUp()
- self.stubs.Set(v2_client.TokenClientJSON, 'raw_request',
- fake_identity._fake_v2_response)
- self.target_url = 'test_api'
-
- def _get_fake_alt_identity(self):
- return fake_identity.ALT_IDENTITY_V2_RESPONSE['access']
-
- def _get_result_url_from_endpoint(self, ep, endpoint_type='publicURL',
- replacement=None):
- if replacement:
- return ep[endpoint_type].replace('v2', replacement)
- return ep[endpoint_type]
-
- def _get_token_from_fake_identity(self):
- return fake_identity.TOKEN
-
- def _get_from_fake_identity(self, attr):
- access = fake_identity.IDENTITY_V2_RESPONSE['access']
- if attr == 'user_id':
- return access['user']['id']
- elif attr == 'tenant_id':
- return access['token']['tenant']['id']
-
- def _test_request_helper(self, filters, expected):
- url, headers, body = self.auth_provider.auth_request('GET',
- self.target_url,
- filters=filters)
-
- self.assertEqual(expected['url'], url)
- self.assertEqual(expected['token'], headers['X-Auth-Token'])
- self.assertEqual(expected['body'], body)
-
- def _auth_data_with_expiry(self, date_as_string):
- token, access = self.auth_provider.auth_data
- access['token']['expires'] = date_as_string
- return token, access
-
- def test_request(self):
- filters = {
- 'service': 'compute',
- 'endpoint_type': 'publicURL',
- 'region': 'FakeRegion'
- }
-
- url = self._get_result_url_from_endpoint(
- self._endpoints[0]['endpoints'][1]) + '/' + self.target_url
-
- expected = {
- 'body': None,
- 'url': url,
- 'token': self._get_token_from_fake_identity(),
- }
- self._test_request_helper(filters, expected)
-
- def test_request_with_alt_auth_cleans_alt(self):
- self.auth_provider.set_alt_auth_data(
- 'body',
- (fake_identity.ALT_TOKEN, self._get_fake_alt_identity()))
- self.test_request()
- # Assert alt auth data is clear after it
- self.assertIsNone(self.auth_provider.alt_part)
- self.assertIsNone(self.auth_provider.alt_auth_data)
-
- def test_request_with_alt_part_without_alt_data(self):
- """
- Assert that when alt_part is defined, the corresponding original
- request element is kept the same.
- """
- filters = {
- 'service': 'compute',
- 'endpoint_type': 'publicURL',
- 'region': 'fakeRegion'
- }
- self.auth_provider.set_alt_auth_data('url', None)
-
- url, headers, body = self.auth_provider.auth_request('GET',
- self.target_url,
- filters=filters)
-
- self.assertEqual(url, self.target_url)
- self.assertEqual(self._get_token_from_fake_identity(),
- headers['X-Auth-Token'])
- self.assertEqual(body, None)
-
- def test_request_with_bad_service(self):
- filters = {
- 'service': 'BAD_SERVICE',
- 'endpoint_type': 'publicURL',
- 'region': 'fakeRegion'
- }
- self.assertRaises(exceptions.EndpointNotFound,
- self.auth_provider.auth_request, 'GET',
- self.target_url, filters=filters)
-
- def test_request_without_service(self):
- filters = {
- 'service': None,
- 'endpoint_type': 'publicURL',
- 'region': 'fakeRegion'
- }
- self.assertRaises(exceptions.EndpointNotFound,
- self.auth_provider.auth_request, 'GET',
- self.target_url, filters=filters)
-
- def test_check_credentials_missing_attribute(self):
- for attr in ['username', 'password']:
- cred = copy.copy(self.credentials)
- del cred[attr]
- self.assertFalse(self.auth_provider.check_credentials(cred))
-
- def test_fill_credentials(self):
- self.auth_provider.fill_credentials()
- creds = self.auth_provider.credentials
- for attr in ['user_id', 'tenant_id']:
- self.assertEqual(self._get_from_fake_identity(attr),
- getattr(creds, attr))
-
- def _test_base_url_helper(self, expected_url, filters,
- auth_data=None):
-
- url = self.auth_provider.base_url(filters, auth_data)
- self.assertEqual(url, expected_url)
-
- def test_base_url(self):
- self.filters = {
- 'service': 'compute',
- 'endpoint_type': 'publicURL',
- 'region': 'FakeRegion'
- }
- expected = self._get_result_url_from_endpoint(
- self._endpoints[0]['endpoints'][1])
- self._test_base_url_helper(expected, self.filters)
-
- def test_base_url_to_get_admin_endpoint(self):
- self.filters = {
- 'service': 'compute',
- 'endpoint_type': 'adminURL',
- 'region': 'FakeRegion'
- }
- expected = self._get_result_url_from_endpoint(
- self._endpoints[0]['endpoints'][1], endpoint_type='adminURL')
- self._test_base_url_helper(expected, self.filters)
-
- def test_base_url_unknown_region(self):
- """
- Assure that if the region is unknow the first endpoint is returned.
- """
- self.filters = {
- 'service': 'compute',
- 'endpoint_type': 'publicURL',
- 'region': 'AintNoBodyKnowThisRegion'
- }
- expected = self._get_result_url_from_endpoint(
- self._endpoints[0]['endpoints'][0])
- self._test_base_url_helper(expected, self.filters)
-
- def test_base_url_with_non_existent_service(self):
- self.filters = {
- 'service': 'BAD_SERVICE',
- 'endpoint_type': 'publicURL',
- 'region': 'FakeRegion'
- }
- self.assertRaises(exceptions.EndpointNotFound,
- self._test_base_url_helper, None, self.filters)
-
- def test_base_url_without_service(self):
- self.filters = {
- 'endpoint_type': 'publicURL',
- 'region': 'FakeRegion'
- }
- self.assertRaises(exceptions.EndpointNotFound,
- self._test_base_url_helper, None, self.filters)
-
- def test_base_url_with_api_version_filter(self):
- self.filters = {
- 'service': 'compute',
- 'endpoint_type': 'publicURL',
- 'region': 'FakeRegion',
- 'api_version': 'v12'
- }
- expected = self._get_result_url_from_endpoint(
- self._endpoints[0]['endpoints'][1], replacement='v12')
- self._test_base_url_helper(expected, self.filters)
-
- def test_base_url_with_skip_path_filter(self):
- self.filters = {
- 'service': 'compute',
- 'endpoint_type': 'publicURL',
- 'region': 'FakeRegion',
- 'skip_path': True
- }
- expected = 'http://fake_url/'
- self._test_base_url_helper(expected, self.filters)
-
- def test_token_not_expired(self):
- expiry_data = datetime.datetime.utcnow() + datetime.timedelta(days=1)
- auth_data = self._auth_data_with_expiry(
- expiry_data.strftime(self.auth_provider.EXPIRY_DATE_FORMAT))
- self.assertFalse(self.auth_provider.is_expired(auth_data))
-
- def test_token_expired(self):
- expiry_data = datetime.datetime.utcnow() - datetime.timedelta(hours=1)
- auth_data = self._auth_data_with_expiry(
- expiry_data.strftime(self.auth_provider.EXPIRY_DATE_FORMAT))
- self.assertTrue(self.auth_provider.is_expired(auth_data))
-
- def test_token_not_expired_to_be_renewed(self):
- expiry_data = datetime.datetime.utcnow() + \
- self.auth_provider.token_expiry_threshold / 2
- auth_data = self._auth_data_with_expiry(
- expiry_data.strftime(self.auth_provider.EXPIRY_DATE_FORMAT))
- self.assertTrue(self.auth_provider.is_expired(auth_data))
-
-
-class TestKeystoneV3AuthProvider(TestKeystoneV2AuthProvider):
- _endpoints = fake_identity.IDENTITY_V3_RESPONSE['token']['catalog']
- _auth_provider_class = auth.KeystoneV3AuthProvider
- credentials = fake_credentials.FakeKeystoneV3Credentials()
-
- def setUp(self):
- super(TestKeystoneV3AuthProvider, self).setUp()
- self.stubs.Set(v3_client.V3TokenClientJSON, 'raw_request',
- fake_identity._fake_v3_response)
-
- def _get_fake_alt_identity(self):
- return fake_identity.ALT_IDENTITY_V3['token']
-
- def _get_result_url_from_endpoint(self, ep, replacement=None):
- if replacement:
- return ep['url'].replace('v3', replacement)
- return ep['url']
-
- def _auth_data_with_expiry(self, date_as_string):
- token, access = self.auth_provider.auth_data
- access['expires_at'] = date_as_string
- return token, access
-
- def _get_from_fake_identity(self, attr):
- token = fake_identity.IDENTITY_V3_RESPONSE['token']
- if attr == 'user_id':
- return token['user']['id']
- elif attr == 'project_id':
- return token['project']['id']
- elif attr == 'user_domain_id':
- return token['user']['domain']['id']
- elif attr == 'project_domain_id':
- return token['project']['domain']['id']
-
- def test_check_credentials_missing_attribute(self):
- # reset credentials to fresh ones
- self.credentials.reset()
- for attr in ['username', 'password', 'user_domain_name',
- 'project_domain_name']:
- cred = copy.copy(self.credentials)
- del cred[attr]
- self.assertFalse(self.auth_provider.check_credentials(cred),
- "Credentials should be invalid without %s" % attr)
-
- def test_check_domain_credentials_missing_attribute(self):
- # reset credentials to fresh ones
- self.credentials.reset()
- domain_creds = fake_credentials.FakeKeystoneV3DomainCredentials()
- for attr in ['username', 'password', 'user_domain_name']:
- cred = copy.copy(domain_creds)
- del cred[attr]
- self.assertFalse(self.auth_provider.check_credentials(cred),
- "Credentials should be invalid without %s" % attr)
-
- def test_fill_credentials(self):
- self.auth_provider.fill_credentials()
- creds = self.auth_provider.credentials
- for attr in ['user_id', 'project_id', 'user_domain_id',
- 'project_domain_id']:
- self.assertEqual(self._get_from_fake_identity(attr),
- getattr(creds, attr))
-
- # Overwrites v2 test
- def test_base_url_to_get_admin_endpoint(self):
- self.filters = {
- 'service': 'compute',
- 'endpoint_type': 'admin',
- 'region': 'MiddleEarthRegion'
- }
- expected = self._get_result_url_from_endpoint(
- self._endpoints[0]['endpoints'][2])
- self._test_base_url_helper(expected, self.filters)
diff --git a/tempest/tests/test_credentials.py b/tempest/tests/test_credentials.py
deleted file mode 100644
index bf44d11..0000000
--- a/tempest/tests/test_credentials.py
+++ /dev/null
@@ -1,180 +0,0 @@
-# Copyright 2014 Hewlett-Packard Development Company, L.P.
-# All Rights Reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-import copy
-
-from tempest import auth
-from tempest import exceptions
-from tempest.services.identity.v2.json import token_client as v2_client
-from tempest.services.identity.v3.json import token_client as v3_client
-from tempest.tests import base
-from tempest.tests import fake_identity
-
-
-class CredentialsTests(base.TestCase):
- attributes = {}
- credentials_class = auth.Credentials
-
- def _get_credentials(self, attributes=None):
- if attributes is None:
- attributes = self.attributes
- return self.credentials_class(**attributes)
-
- def _check(self, credentials, credentials_class, filled):
- # Check the right version of credentials has been returned
- self.assertIsInstance(credentials, credentials_class)
- # Check the id attributes are filled in
- attributes = [x for x in credentials.ATTRIBUTES if (
- '_id' in x and x != 'domain_id')]
- for attr in attributes:
- if filled:
- self.assertIsNotNone(getattr(credentials, attr))
- else:
- self.assertIsNone(getattr(credentials, attr))
-
- def test_create(self):
- creds = self._get_credentials()
- self.assertEqual(self.attributes, creds._initial)
-
- def test_create_invalid_attr(self):
- self.assertRaises(exceptions.InvalidCredentials,
- self._get_credentials,
- attributes=dict(invalid='fake'))
-
- def test_is_valid(self):
- creds = self._get_credentials()
- self.assertRaises(NotImplementedError, creds.is_valid)
-
-
-class KeystoneV2CredentialsTests(CredentialsTests):
- attributes = {
- 'username': 'fake_username',
- 'password': 'fake_password',
- 'tenant_name': 'fake_tenant_name'
- }
-
- identity_response = fake_identity._fake_v2_response
- credentials_class = auth.KeystoneV2Credentials
- tokenclient_class = v2_client.TokenClientJSON
- identity_version = 'v2'
-
- def setUp(self):
- super(KeystoneV2CredentialsTests, self).setUp()
- self.stubs.Set(self.tokenclient_class, 'raw_request',
- self.identity_response)
-
- def _verify_credentials(self, credentials_class, creds_dict, filled=True):
- creds = auth.get_credentials(fake_identity.FAKE_AUTH_URL,
- fill_in=filled,
- identity_version=self.identity_version,
- **creds_dict)
- self._check(creds, credentials_class, filled)
-
- def test_get_credentials(self):
- self._verify_credentials(credentials_class=self.credentials_class,
- creds_dict=self.attributes)
-
- def test_get_credentials_not_filled(self):
- self._verify_credentials(credentials_class=self.credentials_class,
- creds_dict=self.attributes,
- filled=False)
-
- def test_is_valid(self):
- creds = self._get_credentials()
- self.assertTrue(creds.is_valid())
-
- def _test_is_not_valid(self, ignore_key):
- creds = self._get_credentials()
- for attr in self.attributes.keys():
- if attr == ignore_key:
- continue
- temp_attr = getattr(creds, attr)
- delattr(creds, attr)
- self.assertFalse(creds.is_valid(),
- "Credentials should be invalid without %s" % attr)
- setattr(creds, attr, temp_attr)
-
- def test_is_not_valid(self):
- # NOTE(mtreinish): A KeystoneV2 credential object is valid without
- # a tenant_name. So skip that check. See tempest.auth for the valid
- # credential requirements
- self._test_is_not_valid('tenant_name')
-
- def test_reset_all_attributes(self):
- creds = self._get_credentials()
- initial_creds = copy.deepcopy(creds)
- set_attr = creds.__dict__.keys()
- missing_attr = set(creds.ATTRIBUTES).difference(set_attr)
- # Set all unset attributes, then reset
- for attr in missing_attr:
- setattr(creds, attr, 'fake' + attr)
- creds.reset()
- # Check reset credentials are same as initial ones
- self.assertEqual(creds, initial_creds)
-
- def test_reset_single_attribute(self):
- creds = self._get_credentials()
- initial_creds = copy.deepcopy(creds)
- set_attr = creds.__dict__.keys()
- missing_attr = set(creds.ATTRIBUTES).difference(set_attr)
- # Set one unset attributes, then reset
- for attr in missing_attr:
- setattr(creds, attr, 'fake' + attr)
- creds.reset()
- # Check reset credentials are same as initial ones
- self.assertEqual(creds, initial_creds)
-
-
-class KeystoneV3CredentialsTests(KeystoneV2CredentialsTests):
- attributes = {
- 'username': 'fake_username',
- 'password': 'fake_password',
- 'project_name': 'fake_project_name',
- 'user_domain_name': 'fake_domain_name'
- }
-
- credentials_class = auth.KeystoneV3Credentials
- identity_response = fake_identity._fake_v3_response
- tokenclient_class = v3_client.V3TokenClientJSON
- identity_version = 'v3'
-
- def test_is_not_valid(self):
- # NOTE(mtreinish) For a Keystone V3 credential object a project name
- # is not required to be valid, so we skip that check. See tempest.auth
- # for the valid credential requirements
- self._test_is_not_valid('project_name')
-
- def test_synced_attributes(self):
- attributes = self.attributes
- # Create V3 credentials with tenant instead of project, and user_domain
- for attr in ['project_id', 'user_domain_id']:
- attributes[attr] = 'fake_' + attr
- creds = self._get_credentials(attributes)
- self.assertEqual(creds.project_name, creds.tenant_name)
- self.assertEqual(creds.project_id, creds.tenant_id)
- self.assertEqual(creds.user_domain_name, creds.project_domain_name)
- self.assertEqual(creds.user_domain_id, creds.project_domain_id)
- # Replace user_domain with project_domain
- del attributes['user_domain_name']
- del attributes['user_domain_id']
- del attributes['project_name']
- del attributes['project_id']
- for attr in ['project_domain_name', 'project_domain_id',
- 'tenant_name', 'tenant_id']:
- attributes[attr] = 'fake_' + attr
- self.assertEqual(creds.tenant_name, creds.project_name)
- self.assertEqual(creds.tenant_id, creds.project_id)
- self.assertEqual(creds.project_domain_name, creds.user_domain_name)
- self.assertEqual(creds.project_domain_id, creds.user_domain_id)
diff --git a/tempest/tests/test_ssh.py b/tempest/tests/test_ssh.py
deleted file mode 100644
index aaacaab..0000000
--- a/tempest/tests/test_ssh.py
+++ /dev/null
@@ -1,189 +0,0 @@
-# Copyright 2014 OpenStack Foundation
-#
-# 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 contextlib
-import socket
-import time
-
-import mock
-import testtools
-
-from tempest.common import ssh
-from tempest import exceptions
-from tempest.tests import base
-
-
-class TestSshClient(base.TestCase):
-
- def test_pkey_calls_paramiko_RSAKey(self):
- with contextlib.nested(
- mock.patch('paramiko.RSAKey.from_private_key'),
- mock.patch('six.moves.cStringIO')) as (rsa_mock, cs_mock):
- cs_mock.return_value = mock.sentinel.csio
- pkey = 'mykey'
- ssh.Client('localhost', 'root', pkey=pkey)
- rsa_mock.assert_called_once_with(mock.sentinel.csio)
- cs_mock.assert_called_once_with('mykey')
- rsa_mock.reset_mock()
- cs_mock.reset_mock()
- pkey = mock.sentinel.pkey
- # Shouldn't call out to load a file from RSAKey, since
- # a sentinel isn't a basestring...
- ssh.Client('localhost', 'root', pkey=pkey)
- self.assertEqual(0, rsa_mock.call_count)
- self.assertEqual(0, cs_mock.call_count)
-
- def _set_ssh_connection_mocks(self):
- client_mock = mock.MagicMock()
- client_mock.connect.return_value = True
- return (self.patch('paramiko.SSHClient'),
- self.patch('paramiko.AutoAddPolicy'),
- client_mock)
-
- def test_get_ssh_connection(self):
- c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
- s_mock = self.patch('time.sleep')
-
- c_mock.return_value = client_mock
- aa_mock.return_value = mock.sentinel.aa
-
- # Test normal case for successful connection on first try
- client = ssh.Client('localhost', 'root', timeout=2)
- client._get_ssh_connection(sleep=1)
-
- aa_mock.assert_called_once_with()
- client_mock.set_missing_host_key_policy.assert_called_once_with(
- mock.sentinel.aa)
- expected_connect = [mock.call(
- 'localhost',
- username='root',
- pkey=None,
- key_filename=None,
- look_for_keys=False,
- timeout=10.0,
- password=None
- )]
- self.assertEqual(expected_connect, client_mock.connect.mock_calls)
- self.assertEqual(0, s_mock.call_count)
-
- def test_get_ssh_connection_two_attemps(self):
- c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
-
- c_mock.return_value = client_mock
- client_mock.connect.side_effect = [
- socket.error,
- mock.MagicMock()
- ]
-
- client = ssh.Client('localhost', 'root', timeout=1)
- start_time = int(time.time())
- client._get_ssh_connection(sleep=1)
- end_time = int(time.time())
- self.assertLess((end_time - start_time), 4)
- self.assertGreater((end_time - start_time), 1)
-
- def test_get_ssh_connection_timeout(self):
- c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
-
- c_mock.return_value = client_mock
- client_mock.connect.side_effect = [
- socket.error,
- socket.error,
- socket.error,
- ]
-
- client = ssh.Client('localhost', 'root', timeout=2)
- start_time = int(time.time())
- with testtools.ExpectedException(exceptions.SSHTimeout):
- client._get_ssh_connection()
- end_time = int(time.time())
- self.assertLess((end_time - start_time), 5)
- self.assertGreaterEqual((end_time - start_time), 2)
-
- def test_exec_command(self):
- gsc_mock = self.patch('tempest.common.ssh.Client._get_ssh_connection')
- ito_mock = self.patch('tempest.common.ssh.Client._is_timed_out')
- select_mock = self.patch('select.poll')
-
- client_mock = mock.MagicMock()
- tran_mock = mock.MagicMock()
- chan_mock = mock.MagicMock()
- poll_mock = mock.MagicMock()
-
- def reset_mocks():
- gsc_mock.reset_mock()
- ito_mock.reset_mock()
- select_mock.reset_mock()
- poll_mock.reset_mock()
- client_mock.reset_mock()
- tran_mock.reset_mock()
- chan_mock.reset_mock()
-
- select_mock.return_value = poll_mock
- gsc_mock.return_value = client_mock
- ito_mock.return_value = True
- client_mock.get_transport.return_value = tran_mock
- tran_mock.open_session.return_value = chan_mock
- poll_mock.poll.side_effect = [
- [0, 0, 0]
- ]
-
- # Test for a timeout condition immediately raised
- client = ssh.Client('localhost', 'root', timeout=2)
- with testtools.ExpectedException(exceptions.TimeoutException):
- client.exec_command("test")
-
- chan_mock.fileno.assert_called_once_with()
- chan_mock.exec_command.assert_called_once_with("test")
- chan_mock.shutdown_write.assert_called_once_with()
-
- SELECT_POLLIN = 1
- poll_mock.register.assert_called_once_with(chan_mock, SELECT_POLLIN)
- poll_mock.poll.assert_called_once_with(10)
-
- # Test for proper reading of STDOUT and STDERROR and closing
- # of all file descriptors.
-
- reset_mocks()
-
- select_mock.return_value = poll_mock
- gsc_mock.return_value = client_mock
- ito_mock.return_value = False
- client_mock.get_transport.return_value = tran_mock
- tran_mock.open_session.return_value = chan_mock
- poll_mock.poll.side_effect = [
- [1, 0, 0]
- ]
- closed_prop = mock.PropertyMock(return_value=True)
- type(chan_mock).closed = closed_prop
- chan_mock.recv_exit_status.return_value = 0
- chan_mock.recv.return_value = ''
- chan_mock.recv_stderr.return_value = ''
-
- client = ssh.Client('localhost', 'root', timeout=2)
- client.exec_command("test")
-
- chan_mock.fileno.assert_called_once_with()
- chan_mock.exec_command.assert_called_once_with("test")
- chan_mock.shutdown_write.assert_called_once_with()
-
- SELECT_POLLIN = 1
- poll_mock.register.assert_called_once_with(chan_mock, SELECT_POLLIN)
- poll_mock.poll.assert_called_once_with(10)
- chan_mock.recv_ready.assert_called_once_with()
- chan_mock.recv.assert_called_once_with(1024)
- chan_mock.recv_stderr_ready.assert_called_once_with()
- chan_mock.recv_stderr.assert_called_once_with(1024)
- chan_mock.recv_exit_status.assert_called_once_with()
- closed_prop.assert_called_once_with()
diff --git a/tempest/tests/test_tenant_isolation.py b/tempest/tests/test_tenant_isolation.py
index fd8718f..1eb33a4 100644
--- a/tempest/tests/test_tenant_isolation.py
+++ b/tempest/tests/test_tenant_isolation.py
@@ -15,6 +15,7 @@
import mock
from oslo_config import cfg
from oslotest import mockpatch
+from tempest_lib.services.identity.v2 import token_client as json_token_client
from tempest.common import isolated_creds
from tempest.common import service_client
@@ -22,7 +23,6 @@
from tempest import exceptions
from tempest.services.identity.v2.json import identity_client as \
json_iden_client
-from tempest.services.identity.v2.json import token_client as json_token_client
from tempest.services.network.json import network_client as json_network_client
from tempest.tests import base
from tempest.tests import fake_config
diff --git a/tox.ini b/tox.ini
index 2f0aa99..88d1302 100644
--- a/tox.ini
+++ b/tox.ini
@@ -47,7 +47,7 @@
# See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
+ bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty)) {posargs}'
[testenv:full-serial]
sitepackages = {[tempestenv]sitepackages}
@@ -57,7 +57,7 @@
# See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
commands =
find . -type f -name "*.pyc" -delete
- bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
+ bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty)) {posargs}'
[testenv:heat-slow]
sitepackages = {[tempestenv]sitepackages}