Merge "immutable user source: v3 test_roles"
diff --git a/.zuul.yaml b/.zuul.yaml
index 2bec8c4..7b8bcfa 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -294,6 +294,13 @@
CINDER_ENABLED_BACKENDS: lvm:lvmdriver-1,lvm:lvmdriver-2
ENABLE_VOLUME_MULTIATTACH: true
tempest_concurrency: 2
+ group-vars:
+ # NOTE(mriedem): The ENABLE_VOLUME_MULTIATTACH variable is used on both
+ # the controller and subnode prior to Rocky so we have to make sure the
+ # variable is set in both locations.
+ subnode:
+ devstack_localrc:
+ ENABLE_VOLUME_MULTIATTACH: true
- job:
name: tempest-slow-py3
@@ -344,7 +351,7 @@
parent: tox
description: |
Run tempest plugin sanity check script using tox.
- nodeset: ubuntu-xenial
+ nodeset: ubuntu-bionic
vars:
tox_envlist: plugin-sanity-check
voting: false
diff --git a/releasenotes/notes/add-profiler-config-options-db7c4ae6d338ee5c.yaml b/releasenotes/notes/add-profiler-config-options-db7c4ae6d338ee5c.yaml
new file mode 100644
index 0000000..2245044
--- /dev/null
+++ b/releasenotes/notes/add-profiler-config-options-db7c4ae6d338ee5c.yaml
@@ -0,0 +1,10 @@
+---
+features:
+ - |
+ Add support of `OSProfiler library`_ for profiling and distributed
+ tracing of OpenStack. A new config option ``key`` in section ``profiler``
+ is added, the option sets the secret key used to enable profiling in
+ OpenStack services. The value needs to correspond to the one specified
+ in [profiler]/hmac_keys option of OpenStack services.
+
+ .. _OSProfiler library: https://docs.openstack.org/osprofiler/
diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py
index 5801db1..daf6a06 100644
--- a/tempest/api/compute/servers/test_novnc.py
+++ b/tempest/api/compute/servers/test_novnc.py
@@ -143,7 +143,7 @@
data_length = len(data) if data is not None else 0
self.assertFalse(data_length <= 24 or
data_length != (struct.unpack(">L",
- data[20:24])[0] + 24),
+ data[20:24])[0] + 24),
'Server initialization was not the right format.')
# Since the rest of the data on the screen is arbitrary, we will
# close the socket and end our validation of the data at this point
@@ -151,7 +151,7 @@
# initialization was the right format
self.assertFalse(data_length <= 24 or
data_length != (struct.unpack(">L",
- data[20:24])[0] + 24))
+ data[20:24])[0] + 24))
def _validate_websocket_upgrade(self):
self.assertTrue(
diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py
index acc5a8c..2672f71 100644
--- a/tempest/api/identity/admin/v3/test_inherits.py
+++ b/tempest/api/identity/admin/v3/test_inherits.py
@@ -9,14 +9,22 @@
# 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 testtools
from tempest.api.identity import base
from tempest.common import utils
+from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
+CONF = config.CONF
+
class InheritsV3TestJSON(base.BaseIdentityV3AdminTest):
+ # NOTE: force_tenant_isolation is true in the base class by default but
+ # overridden to false here to allow test execution for clouds using the
+ # pre-provisioned credentials provider.
+ force_tenant_isolation = False
@classmethod
def skip_checks(cls):
@@ -43,18 +51,26 @@
domain_id=cls.domain['id'])['group']
cls.addClassResourceCleanup(cls.groups_client.delete_group,
cls.group['id'])
- cls.user = cls.users_client.create_user(
- name=u_name, description=u_desc, password=u_password,
- email=u_email, project_id=cls.project['id'],
- domain_id=cls.domain['id'])['user']
- cls.addClassResourceCleanup(cls.users_client.delete_user,
- cls.user['id'])
+ if not CONF.identity_feature_enabled.immutable_user_source:
+ cls.user = cls.users_client.create_user(
+ name=u_name,
+ description=u_desc,
+ password=u_password,
+ email=u_email,
+ project_id=cls.project['id'],
+ domain_id=cls.domain['id']
+ )['user']
+ cls.addClassResourceCleanup(cls.users_client.delete_user,
+ cls.user['id'])
def _list_assertions(self, body, fetched_role_ids, role_id):
self.assertEqual(len(body), 1)
self.assertIn(role_id, fetched_role_ids)
@decorators.idempotent_id('4e6f0366-97c8-423c-b2be-41eae6ac91c8')
+ @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+ 'Skipped because environment has an immutable user '
+ 'source and solely provides read-only access to users.')
def test_inherit_assign_list_check_revoke_roles_on_domains_user(self):
# Create role
src_role = self.setup_test_role()
@@ -103,6 +119,9 @@
self.domain['id'], self.group['id'], src_role['id'])
@decorators.idempotent_id('18b70e45-7687-4b72-8277-b8f1a47d7591')
+ @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+ 'Skipped because environment has an immutable user '
+ 'source and solely provides read-only access to users.')
def test_inherit_assign_check_revoke_roles_on_projects_user(self):
# Create role
src_role = self.setup_test_role()
@@ -134,6 +153,9 @@
self.project['id'], self.group['id'], src_role['id']))
@decorators.idempotent_id('3acf666e-5354-42ac-8e17-8b68893bcd36')
+ @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+ 'Skipped because environment has an immutable user '
+ 'source and solely provides read-only access to users.')
def test_inherit_assign_list_revoke_user_roles_on_domain(self):
# Create role
src_role = self.setup_test_role()
@@ -178,6 +200,9 @@
self.assertEmpty(assignments)
@decorators.idempotent_id('9f02ccd9-9b57-46b4-8f77-dd5a736f3a06')
+ @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+ 'Skipped because environment has an immutable user '
+ 'source and solely provides read-only access to users.')
def test_inherit_assign_list_revoke_user_roles_on_project_tree(self):
# Create role
src_role = self.setup_test_role()
diff --git a/tempest/api/identity/admin/v3/test_list_projects.py b/tempest/api/identity/admin/v3/test_list_projects.py
index 50f3186..299a618 100644
--- a/tempest/api/identity/admin/v3/test_list_projects.py
+++ b/tempest/api/identity/admin/v3/test_list_projects.py
@@ -13,11 +13,14 @@
# License for the specific language governing permissions and limitations
# under the License.
+from oslo_log import log as logging
+
from tempest.api.identity import base
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
+LOG = logging.getLogger(__name__)
CONF = config.CONF
@@ -26,6 +29,9 @@
def _list_projects_with_params(self, included, excluded, params, key):
# Validate that projects in ``included`` belongs to the projects
# returned that match ``params`` but not projects in ``excluded``
+ all_projects = self.projects_client.list_projects()['projects']
+ LOG.debug("Complete list of projects available in keystone: %s",
+ all_projects)
body = self.projects_client.list_projects(params)['projects']
for p in included:
self.assertIn(p[key], map(lambda x: x[key], body))
@@ -39,13 +45,12 @@
def resource_setup(cls):
super(ListProjectsTestJSON, cls).resource_setup()
cls.project_ids = list()
- # Create a domain
- cls.domain = cls.create_domain()
+ cls.domain_id = cls.os_admin.credentials.domain_id
# Create project with domain
cls.p1_name = data_utils.rand_name('project')
cls.p1 = cls.projects_client.create_project(
cls.p1_name, enabled=False,
- domain_id=cls.domain['id'])['project']
+ domain_id=cls.domain_id)['project']
cls.addClassResourceCleanup(cls.projects_client.delete_project,
cls.p1['id'])
cls.project_ids.append(cls.p1['id'])
diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py
index 3ab2909..eb31ed3 100644
--- a/tempest/api/network/test_dhcp_ipv6.py
+++ b/tempest/api/network/test_dhcp_ipv6.py
@@ -206,7 +206,7 @@
for k in port['fixed_ips']])
real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
for sub in [subnet_dhcp,
- subnet_slaac]]
+ subnet_slaac]]
self.ports_client.delete_port(port['id'])
self.ports.pop()
body = self.ports_client.list_ports()
@@ -257,7 +257,7 @@
for k in port['fixed_ips']])
real_dhcp_ip, real_eui_ip = [real_ips[sub['id']]
for sub in [subnet_dhcp,
- subnet_slaac]]
+ subnet_slaac]]
self._clean_network()
self.assertEqual(real_eui_ip,
eui_ip,
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 7345fd1..ed8eb52 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -317,7 +317,7 @@
subnet = self.create_subnet(
network, **self.subnet_dict(['gateway', 'host_routes',
- 'dns_nameservers',
+ 'dns_nameservers',
'allocation_pools']))
subnet_id = subnet['id']
new_gateway = str(netaddr.IPAddress(
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 2c9159c..25976ce 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -107,7 +107,7 @@
address = self.cidr
address.prefixlen = self.mask_bits
if ((address.version == 4 and address.prefixlen >= 30) or
- (address.version == 6 and address.prefixlen >= 126)):
+ (address.version == 6 and address.prefixlen >= 126)):
msg = ("Subnet %s isn't large enough for the test" % address.cidr)
raise exceptions.InvalidConfiguration(msg)
allocation_pools = {'allocation_pools': [{'start': str(address[2]),
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index f6af0ba..e6db2e9 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -310,8 +310,8 @@
svc.run()
with open(SAVED_STATE_JSON, 'w+') as f:
- f.write(json.dumps(data,
- sort_keys=True, indent=2, separators=(',', ': ')))
+ f.write(json.dumps(data, sort_keys=True,
+ indent=2, separators=(',', ': ')))
def _load_json(self, saved_state_json=SAVED_STATE_JSON):
try:
diff --git a/tempest/cmd/run.py b/tempest/cmd/run.py
index 823ed11..bb3fe63 100644
--- a/tempest/cmd/run.py
+++ b/tempest/cmd/run.py
@@ -202,8 +202,8 @@
svc.run()
with open(SAVED_STATE_JSON, 'w+') as f:
- f.write(json.dumps(data,
- sort_keys=True, indent=2, separators=(',', ': ')))
+ f.write(json.dumps(data, sort_keys=True,
+ indent=2, separators=(',', ': ')))
def get_parser(self, prog_name):
parser = super(TempestRun, self).get_parser(prog_name)
diff --git a/tempest/common/identity.py b/tempest/common/identity.py
index 525110b..cd6d058 100644
--- a/tempest/common/identity.py
+++ b/tempest/common/identity.py
@@ -26,7 +26,7 @@
if project['name'] == project_name:
return project
raise lib_exc.NotFound('No such project(%s) in %s' % (project_name,
- projects))
+ projects))
def get_tenant_by_name(client, tenant_name):
diff --git a/tempest/common/utils/net_utils.py b/tempest/common/utils/net_utils.py
index 867b3dd..b697ef1 100644
--- a/tempest/common/utils/net_utils.py
+++ b/tempest/common/utils/net_utils.py
@@ -19,7 +19,6 @@
def get_unused_ip_addresses(ports_client, subnets_client,
network_id, subnet_id, count):
-
"""Return a list with the specified number of unused IP addresses
This method uses the given ports_client to find the specified number of
diff --git a/tempest/config.py b/tempest/config.py
index fbe18a3..24ae3ae 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -1100,6 +1100,18 @@
""")
]
+
+profiler_group = cfg.OptGroup(name="profiler",
+ title="OpenStack Profiler")
+
+ProfilerGroup = [
+ cfg.StrOpt('key',
+ help="The secret key to enable OpenStack Profiler. The value "
+ "should match the one configured in OpenStack services "
+ "under `[profiler]/hmac_keys` property. The default empty "
+ "value keeps profiling disabled"),
+]
+
DefaultGroup = [
cfg.BoolOpt('pause_teardown',
default=False,
@@ -1132,6 +1144,7 @@
(service_available_group, ServiceAvailableGroup),
(debug_group, DebugGroup),
(placement_group, PlacementGroup),
+ (profiler_group, ProfilerGroup),
(None, DefaultGroup)
]
@@ -1249,7 +1262,7 @@
logging_cfg_path = "%s/logging.conf" % os.path.dirname(path)
if ((not hasattr(_CONF, 'log_config_append') or
- _CONF.log_config_append is None) and
+ _CONF.log_config_append is None) and
os.path.isfile(logging_cfg_path)):
# if logging conf is in place we need to set log_config_append
_CONF.log_config_append = logging_cfg_path
diff --git a/tempest/lib/cmd/check_uuid.py b/tempest/lib/cmd/check_uuid.py
index ac40eef..71ecb32 100755
--- a/tempest/lib/cmd/check_uuid.py
+++ b/tempest/lib/cmd/check_uuid.py
@@ -110,7 +110,7 @@
for item in files:
if item.endswith('.py'):
module_name = '.'.join((root_package,
- os.path.splitext(item)[0]))
+ os.path.splitext(item)[0]))
if not module_name.startswith(UNIT_TESTS_EXCLUDE):
modules.append(module_name)
return modules
diff --git a/tempest/lib/common/api_version_utils.py b/tempest/lib/common/api_version_utils.py
index bcb076b..709c319 100644
--- a/tempest/lib/common/api_version_utils.py
+++ b/tempest/lib/common/api_version_utils.py
@@ -54,7 +54,7 @@
config_min_version = api_version_request.APIVersionRequest(cfg_min_version)
config_max_version = api_version_request.APIVersionRequest(cfg_max_version)
if ((min_version > max_version) or
- (config_min_version > config_max_version)):
+ (config_min_version > config_max_version)):
msg = ("Test Class versions [%s - %s]. "
"Configuration versions [%s - %s]."
% (min_version.get_string(),
diff --git a/tempest/lib/common/preprov_creds.py b/tempest/lib/common/preprov_creds.py
index fcdeb17..1011504 100644
--- a/tempest/lib/common/preprov_creds.py
+++ b/tempest/lib/common/preprov_creds.py
@@ -273,7 +273,7 @@
# NOTE(andreaf) Not all fields may be available on all credentials
# so defaulting to None for that case.
if all([getattr(creds, k, None) == hash_attributes.get(k, None) for
- k in init_attributes]):
+ k in init_attributes]):
return _hash
raise AttributeError('Invalid credentials %s' % creds)
diff --git a/tempest/lib/common/profiler.py b/tempest/lib/common/profiler.py
new file mode 100644
index 0000000..1544337
--- /dev/null
+++ b/tempest/lib/common/profiler.py
@@ -0,0 +1,64 @@
+# 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 base64
+import hashlib
+import hmac
+import json
+
+from oslo_utils import encodeutils
+from oslo_utils import uuidutils
+
+_profiler = {}
+
+
+def enable(profiler_key, trace_id=None):
+ """Enable global profiler instance
+
+ :param profiler_key: the secret key used to enable profiling in services
+ :param trace_id: unique id of the trace, if empty the id is generated
+ automatically
+ """
+ _profiler['key'] = profiler_key
+ _profiler['uuid'] = trace_id or uuidutils.generate_uuid()
+
+
+def disable():
+ """Disable global profiler instance"""
+ _profiler.clear()
+
+
+def serialize_as_http_headers():
+ """Serialize profiler state as HTTP headers
+
+ This function corresponds to the one from osprofiler library.
+ :return: dictionary with 2 keys `X-Trace-Info` and `X-Trace-HMAC`.
+ """
+ p = _profiler
+ if not p: # profiler is not enabled
+ return {}
+
+ info = {'base_id': p['uuid'], 'parent_id': p['uuid']}
+ trace_info = base64.urlsafe_b64encode(
+ encodeutils.to_utf8(json.dumps(info)))
+ trace_hmac = _sign(trace_info, p['key'])
+
+ return {
+ 'X-Trace-Info': trace_info,
+ 'X-Trace-HMAC': trace_hmac,
+ }
+
+
+def _sign(trace_info, key):
+ h = hmac.new(encodeutils.to_utf8(key), digestmod=hashlib.sha1)
+ h.update(trace_info)
+ return h.hexdigest()
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index 3be441e..f076727 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -27,6 +27,7 @@
from tempest.lib.common import http
from tempest.lib.common import jsonschema_validator
+from tempest.lib.common import profiler
from tempest.lib.common.utils import test_utils
from tempest.lib import exceptions
@@ -131,8 +132,10 @@
accept_type = 'json'
if send_type is None:
send_type = 'json'
- return {'Content-Type': 'application/%s' % send_type,
- 'Accept': 'application/%s' % accept_type}
+ headers = {'Content-Type': 'application/%s' % send_type,
+ 'Accept': 'application/%s' % accept_type}
+ headers.update(profiler.serialize_as_http_headers())
+ return headers
def __str__(self):
STRING_LIMIT = 80
diff --git a/tempest/lib/common/utils/data_utils.py b/tempest/lib/common/utils/data_utils.py
index 3483c51..7f94612 100644
--- a/tempest/lib/common/utils/data_utils.py
+++ b/tempest/lib/common/utils/data_utils.py
@@ -170,7 +170,7 @@
:rtype: string
"""
return b''.join([six.int2byte(random.randint(0, 255))
- for i in range(size)])
+ for i in range(size)])
# Courtesy of http://stackoverflow.com/a/312464
diff --git a/tempest/lib/common/utils/misc.py b/tempest/lib/common/utils/misc.py
index 2b0fcd5..a0b0c0a 100644
--- a/tempest/lib/common/utils/misc.py
+++ b/tempest/lib/common/utils/misc.py
@@ -12,9 +12,6 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-from oslo_log import log as logging
-
-LOG = logging.getLogger(__name__)
def singleton(cls):
diff --git a/tempest/lib/decorators.py b/tempest/lib/decorators.py
index 62a5d67..4064401 100644
--- a/tempest/lib/decorators.py
+++ b/tempest/lib/decorators.py
@@ -146,7 +146,7 @@
# Check to see if the attr should be conditional applied.
if 'condition' in kwargs and not kwargs.get('condition'):
return f
- if 'type' in kwargs and isinstance(kwargs['type'], str):
+ if 'type' in kwargs and isinstance(kwargs['type'], six.string_types):
f = testtools.testcase.attr(kwargs['type'])(f)
elif 'type' in kwargs and isinstance(kwargs['type'], list):
for attr in kwargs['type']:
diff --git a/tempest/lib/services/compute/flavors_client.py b/tempest/lib/services/compute/flavors_client.py
index 2fad0a4..5d2dd46 100644
--- a/tempest/lib/services/compute/flavors_client.py
+++ b/tempest/lib/services/compute/flavors_client.py
@@ -172,7 +172,7 @@
https://developer.openstack.org/api-ref/compute/#show-an-extra-spec-for-a-flavor
"""
resp, body = self.get('flavors/%s/os-extra_specs/%s' % (flavor_id,
- key))
+ key))
body = json.loads(body)
self.validate_response(
schema_extra_specs.set_get_flavor_extra_specs_key,
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index 9eed4b3..18e08cc 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -636,7 +636,7 @@
def list_virtual_interfaces(self, server_id):
"""List the virtual interfaces used in an instance."""
resp, body = self.get('/'.join(['servers', server_id,
- 'os-virtual-interfaces']))
+ 'os-virtual-interfaces']))
body = json.loads(body)
self.validate_response(schema.list_virtual_interfaces, resp, body)
return rest_client.ResponseBody(resp, body)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index dbb9acc..d2fd021 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -125,6 +125,27 @@
returns a test server. The purpose of this wrapper is to minimize
the impact on the code of the tests already using this
function.
+
+ :param **kwargs:
+ See extra parameters below
+
+ :Keyword Arguments:
+ * *vnic_type* (``string``) --
+ used when launching instances with pre-configured ports.
+ Examples:
+ normal: a traditional virtual port that is either attached
+ to a linux bridge or an openvswitch bridge on a
+ compute node.
+ direct: an SR-IOV port that is directly attached to a VM
+ macvtap: an SR-IOV port that is attached to a VM via a macvtap
+ device.
+ Defaults to ``CONF.network.port_vnic_type``.
+ * *port_profile* (``dict``) --
+ This attribute is a dictionary that can be used (with admin
+ credentials) to supply information influencing the binding of
+ the port.
+ example: port_profile = "capabilities:[switchdev]"
+ Defaults to ``CONF.network.port_profile``.
"""
# NOTE(jlanoux): As a first step, ssh checks in the scenario
@@ -143,8 +164,8 @@
if name is None:
name = data_utils.rand_name(self.__class__.__name__ + "-server")
- vnic_type = CONF.network.port_vnic_type
- profile = CONF.network.port_profile
+ vnic_type = kwargs.pop('vnic_type', CONF.network.port_vnic_type)
+ profile = kwargs.pop('port_profile', CONF.network.port_profile)
# If vnic_type or profile are configured create port for
# every network
@@ -166,7 +187,7 @@
clients.security_groups_client.list_security_groups(
).get('security_groups')
sec_dict = dict([(s['name'], s['id'])
- for s in security_groups])
+ for s in security_groups])
sec_groups_names = [s['name'] for s in kwargs.pop(
'security_groups')]
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 2b35e45..cee543b 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -48,6 +48,7 @@
10. Check SSH connection to instance after reboot
"""
+
def nova_show(self, server):
got_server = (self.servers_client.show_server(server['id'])
['server'])
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index e5730e7..6ed7e30 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -86,7 +86,6 @@
'Cinder volume snapshots are disabled')
@utils.services('compute', 'volume', 'image')
def test_volume_boot_pattern(self):
-
"""This test case attempts to reproduce the following steps:
* Create in Cinder some bootable volume importing a Glance image
diff --git a/tempest/test.py b/tempest/test.py
index c3c58dc..85000b6 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -28,6 +28,7 @@
from tempest.common import utils
from tempest import config
from tempest.lib.common import fixed_network
+from tempest.lib.common import profiler
from tempest.lib.common import validation_resources as vr
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
@@ -231,6 +232,9 @@
if CONF.pause_teardown:
BaseTestCase.insert_pdb_breakpoint()
+ if CONF.profiler.key:
+ profiler.disable()
+
@classmethod
def insert_pdb_breakpoint(cls):
"""Add pdb breakpoint.
@@ -608,6 +612,8 @@
self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
format=self.log_format,
level=None))
+ if CONF.profiler.key:
+ profiler.enable(CONF.profiler.key)
@property
def credentials_provider(self):
diff --git a/tempest/test_discover/plugins.py b/tempest/test_discover/plugins.py
index 9c18052..7a037eb 100644
--- a/tempest/test_discover/plugins.py
+++ b/tempest/test_discover/plugins.py
@@ -179,6 +179,7 @@
This class is used to manage the lifecycle of external tempest test
plugins. It provides functions for getting set
"""
+
def __init__(self):
self.ext_plugins = stevedore.ExtensionManager(
'tempest.test_plugins', invoke_on_load=True,
diff --git a/tempest/test_discover/test_discover.py b/tempest/test_discover/test_discover.py
index 330f370..143c6e1 100644
--- a/tempest/test_discover/test_discover.py
+++ b/tempest/test_discover/test_discover.py
@@ -37,7 +37,7 @@
top_level_dir=base_path))
else:
suite.addTests(loader.discover(full_test_dir, pattern=pattern,
- top_level_dir=base_path))
+ top_level_dir=base_path))
plugin_load_tests = ext_plugins.get_plugin_load_tests_tuple()
if not plugin_load_tests:
diff --git a/tempest/tests/cmd/test_workspace.py b/tempest/tests/cmd/test_workspace.py
index b4f6c5f..7a6b576 100644
--- a/tempest/tests/cmd/test_workspace.py
+++ b/tempest/tests/cmd/test_workspace.py
@@ -48,7 +48,7 @@
stdout, stderr = process.communicate()
return_code = process.returncode
msg = ("%s failed with:\nstdout: %s\nstderr: %s" % (' '.join(cmd),
- stdout, stderr))
+ stdout, stderr))
self.assertEqual(return_code, expected, msg)
def test_run_workspace_list(self):
diff --git a/tempest/tests/lib/common/test_dynamic_creds.py b/tempest/tests/lib/common/test_dynamic_creds.py
index ebcf5d1..4723458 100644
--- a/tempest/tests/lib/common/test_dynamic_creds.py
+++ b/tempest/tests/lib/common/test_dynamic_creds.py
@@ -109,8 +109,8 @@
return_value=(rest_client.ResponseBody
(200,
{'roles': [{'id': id, 'name': name},
- {'id': '1', 'name': 'FakeRole'},
- {'id': '2', 'name': 'Member'}]}))))
+ {'id': '1', 'name': 'FakeRole'},
+ {'id': '2', 'name': 'Member'}]}))))
return roles_fix
def _mock_list_2_roles(self):
@@ -120,8 +120,8 @@
return_value=(rest_client.ResponseBody
(200,
{'roles': [{'id': '1234', 'name': 'role1'},
- {'id': '1', 'name': 'FakeRole'},
- {'id': '12345', 'name': 'role2'}]}))))
+ {'id': '1', 'name': 'FakeRole'},
+ {'id': '12345', 'name': 'role2'}]}))))
return roles_fix
def _mock_assign_user_role(self):
diff --git a/tempest/tests/lib/common/test_profiler.py b/tempest/tests/lib/common/test_profiler.py
new file mode 100644
index 0000000..59fa0364
--- /dev/null
+++ b/tempest/tests/lib/common/test_profiler.py
@@ -0,0 +1,63 @@
+# 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
+import testtools
+
+from tempest.lib.common import profiler
+
+
+class TestProfiler(testtools.TestCase):
+
+ def test_serialize(self):
+ key = 'SECRET_KEY'
+ pm = {'key': key, 'uuid': 'ID'}
+
+ with mock.patch('tempest.lib.common.profiler._profiler', pm):
+ with mock.patch('json.dumps') as jdm:
+ jdm.return_value = '{"base_id": "ID", "parent_id": "ID"}'
+
+ expected = {
+ 'X-Trace-HMAC':
+ '887292df9f13b8b5ecd6bbbd2e16bfaaa4d914b0',
+ 'X-Trace-Info':
+ b'eyJiYXNlX2lkIjogIklEIiwgInBhcmVudF9pZCI6ICJJRCJ9'
+ }
+
+ self.assertEqual(expected,
+ profiler.serialize_as_http_headers())
+
+ def test_profiler_lifecycle(self):
+ key = 'SECRET_KEY'
+ uuid = 'ID'
+
+ self.assertEqual({}, profiler._profiler)
+
+ profiler.enable(key, uuid)
+ self.assertEqual({'key': key, 'uuid': uuid}, profiler._profiler)
+
+ profiler.disable()
+ self.assertEqual({}, profiler._profiler)
+
+ @mock.patch('oslo_utils.uuidutils.generate_uuid')
+ def test_profiler_lifecycle_generate_trace_id(self, generate_uuid_mock):
+ key = 'SECRET_KEY'
+ uuid = 'ID'
+ generate_uuid_mock.return_value = uuid
+
+ self.assertEqual({}, profiler._profiler)
+
+ profiler.enable(key)
+ self.assertEqual({'key': key, 'uuid': uuid}, profiler._profiler)
+
+ profiler.disable()
+ self.assertEqual({}, profiler._profiler)
diff --git a/tempest/tests/lib/services/compute/test_images_client.py b/tempest/tests/lib/services/compute/test_images_client.py
index c2c3b76..d1500e5 100644
--- a/tempest/tests/lib/services/compute/test_images_client.py
+++ b/tempest/tests/lib/services/compute/test_images_client.py
@@ -186,15 +186,19 @@
def _test_resource_deleted(self, bytes_body=False):
params = {"id": self.FAKE_IMAGE_ID}
expected_op = self.FAKE_IMAGE_DATA['show']
- self.useFixture(fixtures.MockPatch('tempest.lib.services.compute'
- '.images_client.ImagesClient.show_image',
- side_effect=lib_exc.NotFound))
+ self.useFixture(
+ fixtures.MockPatch(
+ 'tempest.lib.services.compute'
+ '.images_client.ImagesClient.show_image',
+ side_effect=lib_exc.NotFound))
self.assertEqual(True, self.client.is_resource_deleted(**params))
tempdata = copy.deepcopy(self.FAKE_IMAGE_DATA['show'])
tempdata['image']['id'] = None
- self.useFixture(fixtures.MockPatch('tempest.lib.services.compute'
- '.images_client.ImagesClient.show_image',
- return_value=expected_op))
+ self.useFixture(
+ fixtures.MockPatch(
+ 'tempest.lib.services.compute'
+ '.images_client.ImagesClient.show_image',
+ return_value=expected_op))
self.assertEqual(False, self.client.is_resource_deleted(**params))
def test_list_images_with_str_body(self):
diff --git a/tempest/tests/lib/services/volume/v3/test_scheduler_stats_client.py b/tempest/tests/lib/services/volume/v3/test_scheduler_stats_client.py
index e0f5566..84c7589 100644
--- a/tempest/tests/lib/services/volume/v3/test_scheduler_stats_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_scheduler_stats_client.py
@@ -62,7 +62,7 @@
resp_body = self.FAKE_POOLS_LIST
else:
resp_body = {'pools': [{'name': pool['name']}
- for pool in self.FAKE_POOLS_LIST['pools']]}
+ for pool in self.FAKE_POOLS_LIST['pools']]}
self.check_service_client_function(
self.client.list_pools,
'tempest.lib.common.rest_client.RestClient.get',
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index 9534ce8..83c1abb 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -48,6 +48,7 @@
just assertTrue if the check is expected to fail and assertFalse if it
should pass.
"""
+
def test_no_setup_teardown_class_for_tests(self):
self.assertTrue(checks.no_setup_teardown_class_for_tests(
" def setUpClass(cls):", './tempest/tests/fake_test.py'))
diff --git a/tools/format.sh b/tools/format.sh
new file mode 100755
index 0000000..adffb8c
--- /dev/null
+++ b/tools/format.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+cd $(dirname "$(readlink -f "$0")")
+
+autopep8 --exit-code --max-line-length=79 --experimental --in-place -r ../tempest ../setup.py && echo Formatting was not needed. >&2
+
diff --git a/tox.ini b/tox.ini
index 4068054..433f168 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
[tox]
-envlist = pep8,py36,py27,pip-check-reqs
+envlist = pep8,py36,py37,py27,pip-check-reqs
minversion = 2.3.1
skipsdist = True
@@ -197,11 +197,21 @@
whitelist_externals = rm
[testenv:pep8]
+deps =
+ -r test-requirements.txt
+ autopep8
basepython = python3
commands =
+ autopep8 --exit-code --max-line-length=79 --experimental --diff -r tempest setup.py
flake8 {posargs}
check-uuid
+[testenv:autopep8]
+deps = autopep8
+basepython = python3
+commands =
+ autopep8 --max-line-length=79 --experimental --in-place -r tempest setup.py
+
[testenv:uuidgen]
commands =
check-uuid --fix