Merge "Fix load balancer scenario if no tenant network"
diff --git a/HACKING.rst b/HACKING.rst
index 8652971..025bf74 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -12,6 +12,7 @@
- [T104] Scenario tests require a services decorator
- [T105] Unit tests cannot use setUpClass
- [T106] vim configuration should not be kept in source files.
+- [N322] Method's default argument shouldn't be mutable
Test Data/Configuration
-----------------------
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 343a39a..47d1254 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -271,10 +271,10 @@
return resp, body
@classmethod
- def create_test_server_group(cls, name="", policy=[]):
+ def create_test_server_group(cls, name="", policy=None):
if not name:
name = data_utils.rand_name(cls.__name__ + "-Server-Group")
- if not policy:
+ if policy is None:
policy = ['affinity']
resp, body = cls.servers_client.create_server_group(name, policy)
cls.server_groups.append(body['id'])
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 187c0d4..1c5d4a3 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -47,6 +47,7 @@
self.__class__.server_id = self.rebuild_server(self.server_id)
@classmethod
+ @test.safe_setup
def setUpClass(cls):
super(ImagesOneServerTestJSON, cls).setUpClass()
cls.client = cls.images_client
@@ -59,12 +60,8 @@
% cls.__name__)
raise cls.skipException(skip_msg)
- try:
- resp, server = cls.create_test_server(wait_until='ACTIVE')
- cls.server_id = server['id']
- except Exception:
- cls.tearDownClass()
- raise
+ resp, server = cls.create_test_server(wait_until='ACTIVE')
+ cls.server_id = server['id']
def _get_default_flavor_disk_size(self, flavor_id):
resp, flavor = self.flavors_client.get_flavor_details(flavor_id)
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index 4e84e08..51d9b85 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -55,6 +55,7 @@
self.__class__.server_id = self.rebuild_server(self.server_id)
@classmethod
+ @test.safe_setup
def setUpClass(cls):
super(ImagesOneServerNegativeTestJSON, cls).setUpClass()
cls.client = cls.images_client
@@ -67,12 +68,8 @@
% cls.__name__)
raise cls.skipException(skip_msg)
- try:
- resp, server = cls.create_test_server(wait_until='ACTIVE')
- cls.server_id = server['id']
- except Exception:
- cls.tearDownClass()
- raise
+ resp, server = cls.create_test_server(wait_until='ACTIVE')
+ cls.server_id = server['id']
cls.image_ids = []
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index 68794b1..9f1cfc8 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -32,6 +32,7 @@
class ListImageFiltersTestJSON(base.BaseV2ComputeTest):
@classmethod
+ @test.safe_setup
def setUpClass(cls):
super(ListImageFiltersTestJSON, cls).setUpClass()
if not CONF.service_available.glance:
@@ -69,33 +70,28 @@
return
# Create instances and snapshots via nova
- try:
- resp, cls.server1 = cls.create_test_server()
- resp, cls.server2 = cls.create_test_server(wait_until='ACTIVE')
- # NOTE(sdague) this is faster than doing the sync wait_util on both
- cls.servers_client.wait_for_server_status(cls.server1['id'],
- 'ACTIVE')
+ resp, cls.server1 = cls.create_test_server()
+ resp, cls.server2 = cls.create_test_server(wait_until='ACTIVE')
+ # NOTE(sdague) this is faster than doing the sync wait_util on both
+ cls.servers_client.wait_for_server_status(cls.server1['id'],
+ 'ACTIVE')
- # Create images to be used in the filter tests
- resp, cls.snapshot1 = cls.create_image_from_server(
- cls.server1['id'], wait_until='ACTIVE')
- cls.snapshot1_id = cls.snapshot1['id']
+ # Create images to be used in the filter tests
+ resp, cls.snapshot1 = cls.create_image_from_server(
+ cls.server1['id'], wait_until='ACTIVE')
+ cls.snapshot1_id = cls.snapshot1['id']
- # Servers have a hidden property for when they are being imaged
- # Performing back-to-back create image calls on a single
- # server will sometimes cause failures
- resp, cls.snapshot3 = cls.create_image_from_server(
- cls.server2['id'], wait_until='ACTIVE')
- cls.snapshot3_id = cls.snapshot3['id']
+ # Servers have a hidden property for when they are being imaged
+ # Performing back-to-back create image calls on a single
+ # server will sometimes cause failures
+ resp, cls.snapshot3 = cls.create_image_from_server(
+ cls.server2['id'], wait_until='ACTIVE')
+ cls.snapshot3_id = cls.snapshot3['id']
- # Wait for the server to be active after the image upload
- resp, cls.snapshot2 = cls.create_image_from_server(
- cls.server1['id'], wait_until='ACTIVE')
- cls.snapshot2_id = cls.snapshot2['id']
- except Exception:
- LOG.exception('setUpClass failed')
- cls.tearDownClass()
- raise
+ # Wait for the server to be active after the image upload
+ resp, cls.snapshot2 = cls.create_image_from_server(
+ cls.server1['id'], wait_until='ACTIVE')
+ cls.snapshot2_id = cls.snapshot2['id']
@test.attr(type='gate')
def test_list_images_filter_by_status(self):
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 792b523..b9ec29e 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -404,13 +404,6 @@
nonexistent_server)
@test.attr(type=['negative', 'gate'])
- def test_force_delete_server_invalid_state(self):
- # we can only force-delete a server in 'soft-delete' state
- self.assertRaises(exceptions.Conflict,
- self.client.force_delete_server,
- self.server_id)
-
- @test.attr(type=['negative', 'gate'])
def test_restore_nonexistent_server_id(self):
# restore-delete a non existent server
nonexistent_server = data_utils.rand_uuid()
diff --git a/tempest/api/compute/v3/images/test_images_oneserver.py b/tempest/api/compute/v3/images/test_images_oneserver.py
index 795437b..edf91a7 100644
--- a/tempest/api/compute/v3/images/test_images_oneserver.py
+++ b/tempest/api/compute/v3/images/test_images_oneserver.py
@@ -47,6 +47,7 @@
super(ImagesOneServerV3Test, self).tearDown()
@classmethod
+ @test.safe_setup
def setUpClass(cls):
super(ImagesOneServerV3Test, cls).setUpClass()
cls.client = cls.images_client
@@ -54,12 +55,8 @@
skip_msg = ("%s skipped as glance is not available" % cls.__name__)
raise cls.skipException(skip_msg)
- try:
- resp, server = cls.create_test_server(wait_until='ACTIVE')
- cls.server_id = server['id']
- except Exception:
- cls.tearDownClass()
- raise
+ resp, server = cls.create_test_server(wait_until='ACTIVE')
+ cls.server_id = server['id']
def _get_default_flavor_disk_size(self, flavor_id):
resp, flavor = self.flavors_client.get_flavor_details(flavor_id)
diff --git a/tempest/api/compute/v3/images/test_images_oneserver_negative.py b/tempest/api/compute/v3/images/test_images_oneserver_negative.py
index eed81c6..544a5a5 100644
--- a/tempest/api/compute/v3/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/v3/images/test_images_oneserver_negative.py
@@ -55,6 +55,7 @@
self.__class__.server_id = self.rebuild_server(self.server_id)
@classmethod
+ @test.safe_setup
def setUpClass(cls):
super(ImagesOneServerNegativeV3Test, cls).setUpClass()
cls.client = cls.images_client
@@ -62,12 +63,8 @@
skip_msg = ("%s skipped as glance is not available" % cls.__name__)
raise cls.skipException(skip_msg)
- try:
- resp, server = cls.create_test_server(wait_until='ACTIVE')
- cls.server_id = server['id']
- except Exception:
- cls.tearDownClass()
- raise
+ resp, server = cls.create_test_server(wait_until='ACTIVE')
+ cls.server_id = server['id']
cls.image_ids = []
diff --git a/tempest/api/network/test_metering_extensions.py b/tempest/api/network/test_metering_extensions.py
index 5b8db43..0cc218b 100644
--- a/tempest/api/network/test_metering_extensions.py
+++ b/tempest/api/network/test_metering_extensions.py
@@ -35,6 +35,7 @@
"""
@classmethod
+ @test.safe_setup
def setUpClass(cls):
super(MeteringJSON, cls).setUpClass()
if not test.is_extension_enabled('metering', 'network'):
@@ -42,17 +43,12 @@
raise cls.skipException(msg)
description = "metering label created by tempest"
name = data_utils.rand_name("metering-label")
- try:
- cls.metering_label = cls.create_metering_label(name, description)
- remote_ip_prefix = "10.0.0.0/24"
- direction = "ingress"
- cls.metering_label_rule = cls.create_metering_label_rule(
- remote_ip_prefix, direction,
- metering_label_id=cls.metering_label['id'])
- except Exception:
- LOG.exception('setUpClass failed')
- cls.tearDownClass()
- raise
+ cls.metering_label = cls.create_metering_label(name, description)
+ remote_ip_prefix = "10.0.0.0/24"
+ direction = "ingress"
+ cls.metering_label_rule = cls.create_metering_label_rule(
+ remote_ip_prefix, direction,
+ metering_label_id=cls.metering_label['id'])
def _delete_metering_label(self, metering_label_id):
# Deletes a label and verifies if it is deleted or not
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index f06d17c..c6fe817 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -16,6 +16,7 @@
import socket
from tempest.api.network import base
+from tempest.common import custom_matchers
from tempest.common.utils import data_utils
from tempest import config
from tempest import test
@@ -72,18 +73,12 @@
_, body = self.client.show_port(self.port['id'])
port = body['port']
self.assertIn('id', port)
- self.assertEqual(port['id'], self.port['id'])
- self.assertEqual(self.port['admin_state_up'], port['admin_state_up'])
- self.assertEqual(self.port['device_id'], port['device_id'])
- self.assertEqual(self.port['device_owner'], port['device_owner'])
- self.assertEqual(self.port['mac_address'], port['mac_address'])
- self.assertEqual(self.port['name'], port['name'])
- self.assertEqual(self.port['security_groups'],
- port['security_groups'])
- self.assertEqual(self.port['network_id'], port['network_id'])
- self.assertEqual(self.port['security_groups'],
- port['security_groups'])
- self.assertEqual(port['fixed_ips'], [])
+ # TODO(Santosh)- This is a temporary workaround to compare create_port
+ # and show_port dict elements.Remove this once extra_dhcp_opts issue
+ # gets fixed in neutron.( bug - 1365341.)
+ self.assertThat(self.port,
+ custom_matchers.MatchesDictExceptForKeys
+ (port, excluded_keys=['extra_dhcp_opts']))
@test.attr(type='smoke')
def test_show_port_fields(self):
@@ -249,10 +244,10 @@
_tenant_network_mask_bits = CONF.network.tenant_network_v6_mask_bits
@classmethod
+ @test.safe_setup
def setUpClass(cls):
super(PortsIpV6TestJSON, cls).setUpClass()
if not CONF.network_feature_enabled.ipv6:
- cls.tearDownClass()
skip_msg = "IPv6 Tests are disabled."
raise cls.skipException(skip_msg)
@@ -274,6 +269,5 @@
super(PortsAdminExtendedAttrsIpV6TestJSON, cls).setUpClass()
-class PortsAdminExtendedAttrsIpV6TestXML(
- PortsAdminExtendedAttrsIpV6TestJSON):
+class PortsAdminExtendedAttrsIpV6TestXML(PortsAdminExtendedAttrsIpV6TestJSON):
_interface = 'xml'
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
index d0fb825..0b22de5 100644
--- a/tempest/api/orchestration/base.py
+++ b/tempest/api/orchestration/base.py
@@ -64,8 +64,10 @@
return admin_client
@classmethod
- def create_stack(cls, stack_name, template_data, parameters={},
+ def create_stack(cls, stack_name, template_data, parameters=None,
environment=None, files=None):
+ if parameters is None:
+ parameters = {}
resp, body = cls.client.create_stack(
stack_name,
template=template_data,
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index 6761a69..f37bfdb 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -20,6 +20,7 @@
"""
import argparse
+import datetime
import logging
import os
import sys
@@ -30,12 +31,14 @@
import tempest.auth
from tempest import config
from tempest import exceptions
+from tempest.openstack.common import timeutils
from tempest.services.compute.json import flavors_client
from tempest.services.compute.json import servers_client
from tempest.services.identity.json import identity_client
from tempest.services.image.v2.json import image_client
from tempest.services.object_storage import container_client
from tempest.services.object_storage import object_client
+from tempest.services.telemetry.json import telemetry_client
from tempest.services.volume.json import volumes_client
OPTS = {}
@@ -44,6 +47,8 @@
LOG = None
+JAVELIN_START = datetime.datetime.utcnow()
+
class OSClient(object):
_creds = None
@@ -62,6 +67,7 @@
self.containers = container_client.ContainerClient(_auth)
self.images = image_client.ImageClientV2JSON(_auth)
self.flavors = flavors_client.FlavorsClientJSON(_auth)
+ self.telemetry = telemetry_client.TelemetryClientJSON(_auth)
self.volumes = volumes_client.VolumesClientJSON(_auth)
@@ -196,6 +202,7 @@
# TODO(sdague): Volumes not yet working, bring it back once the
# code is self testing.
# self.check_volumes()
+ self.check_telemetry()
def check_users(self):
"""Check that the users we expect to exist, do.
@@ -252,6 +259,26 @@
"Server %s is not pingable at %s" % (
server['name'], addr))
+ def check_telemetry(self):
+ """Check that ceilometer provides a sane sample.
+
+ Confirm that there are more than one sample and that they have the
+ expected metadata.
+
+ If in check mode confirm that the oldest sample available is from
+ before the upgrade.
+ """
+ LOG.info("checking telemetry")
+ for server in self.res['servers']:
+ client = client_for_user(server['owner'])
+ response, body = client.telemetry.list_samples(
+ 'instance',
+ query=('metadata.display_name', 'eq', server['name'])
+ )
+ self.assertEqual(response.status, 200)
+ self.assertTrue(len(body) >= 1, 'expecting at least one sample')
+ self._confirm_telemetry_sample(server, body[-1])
+
def check_volumes(self):
"""Check that the volumes are still there and attached."""
if not self.res.get('volumes'):
@@ -270,6 +297,26 @@
self.assertEqual(volume['id'], attachment['volume_id'])
self.assertEqual(server_id, attachment['server_id'])
+ def _confirm_telemetry_sample(self, server, sample):
+ """Check this sample matches the expected resource metadata."""
+ # Confirm display_name
+ self.assertEqual(server['name'],
+ sample['resource_metadata']['display_name'])
+ # Confirm instance_type of flavor
+ flavor = sample['resource_metadata'].get(
+ 'flavor.name',
+ sample['resource_metadata'].get('instance_type')
+ )
+ self.assertEqual(server['flavor'], flavor)
+ # Confirm the oldest sample was created before upgrade.
+ if OPTS.mode == 'check':
+ oldest_timestamp = timeutils.normalize_time(
+ timeutils.parse_isotime(sample['timestamp']))
+ self.assertTrue(
+ oldest_timestamp < JAVELIN_START,
+ 'timestamp should come before start of second javelin run'
+ )
+
#######################
#
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index ff92b67..132d0a6 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -248,8 +248,10 @@
return resp[i]
return ""
- def _log_request_start(self, method, req_url, req_headers={},
+ def _log_request_start(self, method, req_url, req_headers=None,
req_body=None):
+ if req_headers is None:
+ req_headers = {}
caller_name = misc_utils.find_test_caller()
trace_regex = CONF.debug.trace_requests
if trace_regex and re.search(trace_regex, caller_name):
@@ -257,8 +259,10 @@
(caller_name, method, req_url))
def _log_request(self, method, req_url, resp,
- secs="", req_headers={},
+ secs="", req_headers=None,
req_body=None, resp_body=None):
+ if req_headers is None:
+ req_headers = {}
# if we have the request id, put it in the right part of the log
extra = dict(request_id=self._get_request_id(resp))
# NOTE(sdague): while we still have 6 callers to this function
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index cef010e..abc60cb 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -27,6 +27,7 @@
SETUPCLASS_DEFINITION = re.compile(r'^\s*def setUpClass')
SCENARIO_DECORATOR = re.compile(r'\s*@.*services\((.*)\)')
VI_HEADER_RE = re.compile(r"^#\s+vim?:.+")
+mutable_default_args = re.compile(r"^\s*def .+\((.+=\{\}|.+=\[\])")
def import_no_clients_in_api(physical_line, filename):
@@ -119,6 +120,16 @@
'tests')
+def no_mutable_default_args(logical_line):
+ """Check that mutable object isn't used as default argument
+
+ N322: Method's default argument shouldn't be mutable
+ """
+ msg = "N322: Method's default argument shouldn't be mutable!"
+ if mutable_default_args.match(logical_line):
+ yield (0, msg)
+
+
def factory(register):
register(import_no_clients_in_api)
register(scenario_tests_need_service_tags)
@@ -126,3 +137,4 @@
register(no_vi_headers)
register(service_tags_not_in_module_path)
register(no_official_client_manager_in_api_tests)
+ register(no_mutable_default_args)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 7a80a66..8f1a61d 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -141,8 +141,8 @@
pass
def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
- cleanup_callable, cleanup_args=[],
- cleanup_kwargs={}, ignore_error=True):
+ cleanup_callable, cleanup_args=None,
+ cleanup_kwargs=None, ignore_error=True):
"""Adds wait for ansyc resource deletion at the end of cleanups
@param waiter_callable: callable to wait for the resource to delete
@@ -152,6 +152,10 @@
the following *cleanup_args, **cleanup_kwargs.
usually a delete method.
"""
+ if cleanup_args is None:
+ cleanup_args = []
+ if cleanup_kwargs is None:
+ cleanup_kwargs = {}
self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
wait_dict = {
'waiter_callable': waiter_callable,
@@ -186,7 +190,7 @@
def create_server(self, name=None, image=None, flavor=None,
wait_on_boot=True, wait_on_delete=True,
- create_kwargs={}):
+ create_kwargs=None):
"""Creates VM instance.
@param image: image from which to create the instance
@@ -201,6 +205,8 @@
image = CONF.compute.image_ref
if flavor is None:
flavor = CONF.compute.flavor_ref
+ if create_kwargs is None:
+ create_kwargs = {}
fixed_network_name = CONF.compute.fixed_network_name
if 'nics' not in create_kwargs and fixed_network_name:
@@ -343,7 +349,9 @@
return linux_client
- def _image_create(self, name, fmt, path, properties={}):
+ def _image_create(self, name, fmt, path, properties=None):
+ if properties is None:
+ properties = {}
name = data_utils.rand_name('%s-' % name)
image_file = open(path, 'rb')
self.addCleanup(image_file.close)
@@ -390,6 +398,9 @@
LOG.debug("image:%s" % self.image)
def _log_console_output(self, servers=None):
+ if not CONF.compute_feature_enabled.console_output:
+ LOG.debug('Console output not supported, cannot log')
+ return
if not servers:
_, servers = self.servers_client.list_servers()
servers = servers['servers']
@@ -1022,8 +1033,8 @@
def addCleanup_with_wait(self, things, thing_id,
error_status='ERROR',
exc_type=nova_exceptions.NotFound,
- cleanup_callable=None, cleanup_args=[],
- cleanup_kwargs={}):
+ cleanup_callable=None, cleanup_args=None,
+ cleanup_kwargs=None):
"""Adds wait for ansyc resource deletion at the end of cleanups
@param things: type of the resource to delete
@@ -1035,6 +1046,10 @@
usually a delete method. if not used, will try to use:
things.delete(thing_id)
"""
+ if cleanup_args is None:
+ cleanup_args = []
+ if cleanup_kwargs is None:
+ cleanup_kwargs = {}
if cleanup_callable is None:
LOG.debug("no delete method passed. using {rclass}.delete({id}) as"
" default".format(rclass=things, id=thing_id))
@@ -1216,7 +1231,7 @@
def create_server(self, client=None, name=None, image=None, flavor=None,
wait_on_boot=True, wait_on_delete=True,
- create_kwargs={}):
+ create_kwargs=None):
"""Creates VM instance.
@param client: compute client to create the instance
@@ -1234,6 +1249,8 @@
image = CONF.compute.image_ref
if flavor is None:
flavor = CONF.compute.flavor_ref
+ if create_kwargs is None:
+ create_kwargs = {}
fixed_network_name = CONF.compute.fixed_network_name
if 'nics' not in create_kwargs and fixed_network_name:
@@ -1363,7 +1380,9 @@
self.status_timeout(
self.volume_client.volumes, volume_id, status)
- def _image_create(self, name, fmt, path, properties={}):
+ def _image_create(self, name, fmt, path, properties=None):
+ if properties is None:
+ properties = {}
name = data_utils.rand_name('%s-' % name)
image_file = open(path, 'rb')
self.addCleanup(image_file.close)
@@ -2375,12 +2394,17 @@
self._list_and_check_container_objects(container_name,
not_present_obj=[filename])
- def _list_and_check_container_objects(self, container_name, present_obj=[],
- not_present_obj=[]):
+ def _list_and_check_container_objects(self, container_name,
+ present_obj=None,
+ not_present_obj=None):
"""
List objects for a given container and assert which are present and
which are not.
"""
+ if present_obj is None:
+ present_obj = []
+ if not_present_obj is None:
+ not_present_obj = []
_, object_list = self.container_client.list_container_contents(
container_name)
if present_obj:
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index aa04752..47f2f1a 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -70,6 +70,9 @@
create_kwargs=create_kwargs)
self.floating_ip = self._create_floating_ip(self.server,
public_network_id)
+ # Verify that we can indeed connect to the server before we mess with
+ # it's state
+ self._wait_server_status_and_check_network_connectivity()
def _check_network_connectivity(self, should_connect=True):
username = CONF.compute.image_ssh_user
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index c32923a..fdda423 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -117,7 +117,7 @@
private_key=keypair['private_key'])
except Exception:
LOG.exception('ssh to server failed')
- self._log_console_output(self)
+ self._log_console_output(servers=[server])
raise
def _get_content(self, ssh_client):
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index be0f888..eca57c0 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -32,11 +32,15 @@
def create_account(self, data=None,
params=None,
- metadata={},
- remove_metadata={},
+ metadata=None,
+ remove_metadata=None,
metadata_prefix='X-Account-Meta-',
remove_metadata_prefix='X-Remove-Account-Meta-'):
"""Create an account."""
+ if metadata is None:
+ metadata = {}
+ if remove_metadata is None:
+ remove_metadata = {}
url = ''
if params:
url += '?%s' % urllib.urlencode(params)
diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py
index 9c76f51..d3867cd 100644
--- a/tempest/services/orchestration/json/orchestration_client.py
+++ b/tempest/services/orchestration/json/orchestration_client.py
@@ -45,9 +45,11 @@
body = json.loads(body)
return resp, body['stacks']
- def create_stack(self, name, disable_rollback=True, parameters={},
+ def create_stack(self, name, disable_rollback=True, parameters=None,
timeout_mins=60, template=None, template_url=None,
environment=None, files=None):
+ if parameters is None:
+ parameters = {}
headers, body = self._prepare_update_create(
name,
disable_rollback,
@@ -63,8 +65,10 @@
return resp, body
def update_stack(self, stack_identifier, name, disable_rollback=True,
- parameters={}, timeout_mins=60, template=None,
+ parameters=None, timeout_mins=60, template=None,
template_url=None, environment=None, files=None):
+ if parameters is None:
+ parameters = {}
headers, body = self._prepare_update_create(
name,
disable_rollback,
@@ -80,9 +84,11 @@
return resp, body
def _prepare_update_create(self, name, disable_rollback=True,
- parameters={}, timeout_mins=60,
+ parameters=None, timeout_mins=60,
template=None, template_url=None,
environment=None, files=None):
+ if parameters is None:
+ parameters = {}
post_body = {
"stack_name": name,
"disable_rollback": disable_rollback,
@@ -264,16 +270,20 @@
body = json.loads(body)
return resp, body
- def validate_template(self, template, parameters={}):
+ def validate_template(self, template, parameters=None):
"""Returns the validation result for a template with parameters."""
+ if parameters is None:
+ parameters = {}
post_body = {
'template': template,
'parameters': parameters,
}
return self._validate_template(post_body)
- def validate_template_url(self, template_url, parameters={}):
+ def validate_template_url(self, template_url, parameters=None):
"""Returns the validation result for a template with parameters."""
+ if parameters is None:
+ parameters = {}
post_body = {
'template_url': template_url,
'parameters': parameters,
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index 52fdf7e..9c13013 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -107,3 +107,16 @@
self.assertFalse(checks.no_official_client_manager_in_api_tests(
"cls.official_client = clients.OfficialClientManager(credentials)",
"tempest/scenario/fake_test.py"))
+
+ def test_no_mutable_default_args(self):
+ self.assertEqual(1, len(list(checks.no_mutable_default_args(
+ " def function1(para={}):"))))
+
+ self.assertEqual(1, len(list(checks.no_mutable_default_args(
+ "def function2(para1, para2, para3=[])"))))
+
+ self.assertEqual(0, len(list(checks.no_mutable_default_args(
+ "defined = []"))))
+
+ self.assertEqual(0, len(list(checks.no_mutable_default_args(
+ "defined, undefined = [], {}"))))
diff --git a/tools/check_logs.py b/tools/check_logs.py
index eab9f73..917aaaf 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -26,8 +26,9 @@
import yaml
-is_grenade = (os.environ.get('DEVSTACK_GATE_GRENADE', "0") == "1" or
- os.environ.get('DEVSTACK_GATE_GRENADE_FORWARD', "0") == "1")
+# DEVSTACK_GATE_GRENADE is either unset if grenade is not running
+# or a string describing what type of grenade run to perform.
+is_grenade = os.environ.get('DEVSTACK_GATE_GRENADE') is not None
dump_all_errors = True
# As logs are made clean, add to this set