Run tests in py34 environment
A lot of fixes to be compatible with python 3: - fix encoding/decoding errors - fix issues with comparison - use `reload`, `reraise`, ext. modules from six - use items() instead of iteritems() - add a new file with py3 specific test requirements - drop passing the arbitrary arguments to object.__new__ method. See bug [1] for more details. - add a workaround to bug in `mock` library - add py33 and py34 test environment to tox.ini [1] http://bugs.python.org/issue1683368 Change-Id: I90936cb6b6eaaf4b5e1ce67732caec3c8bdc1cc2
This commit is contained in:
parent
1961523996
commit
70062322a2
@ -185,7 +185,7 @@ class DriversController(rest.RestController):
|
||||
# choose to expose below it.
|
||||
|
||||
driver_dict = pecan.request.dbapi.get_active_driver_dict()
|
||||
for name, hosts in driver_dict.iteritems():
|
||||
for name, hosts in driver_dict.items():
|
||||
if name == driver_name:
|
||||
return Driver.convert_with_links(name, list(hosts))
|
||||
|
||||
|
@ -34,10 +34,13 @@ JSONPATCH_EXCEPTIONS = (jsonpatch.JsonPatchException,
|
||||
|
||||
|
||||
def validate_limit(limit):
|
||||
if limit is not None and limit <= 0:
|
||||
if limit is None:
|
||||
return CONF.api.max_limit
|
||||
|
||||
if limit <= 0:
|
||||
raise wsme.exc.ClientSideError(_("Limit must be positive"))
|
||||
|
||||
return min(CONF.api.max_limit, limit) or CONF.api.max_limit
|
||||
return min(CONF.api.max_limit, limit)
|
||||
|
||||
|
||||
def validate_sort_dir(sort_dir):
|
||||
|
@ -26,6 +26,7 @@ import json
|
||||
from xml import etree as et
|
||||
|
||||
from oslo_log import log
|
||||
import six
|
||||
import webob
|
||||
|
||||
from ironic.common.i18n import _
|
||||
@ -83,7 +84,11 @@ class ParsableErrorMiddleware(object):
|
||||
+ '</error_message>']
|
||||
state['headers'].append(('Content-Type', 'application/xml'))
|
||||
else:
|
||||
if six.PY3:
|
||||
app_iter = [i.decode('utf-8') for i in app_iter]
|
||||
body = [json.dumps({'error_message': '\n'.join(app_iter)})]
|
||||
if six.PY3:
|
||||
body = [item.encode('utf-8') for item in body]
|
||||
state['headers'].append(('Content-Type', 'application/json'))
|
||||
state['headers'].append(('Content-Length', str(len(body[0]))))
|
||||
else:
|
||||
|
@ -190,6 +190,8 @@ def list_partitions(device):
|
||||
output = utils.execute(
|
||||
'parted', '-s', '-m', device, 'unit', 'MiB', 'print',
|
||||
use_standard_locale=True)[0]
|
||||
if isinstance(output, bytes):
|
||||
output = output.decode("utf-8")
|
||||
lines = [line for line in output.split('\n') if line.strip()][2:]
|
||||
# Example of line: 1:1.00MiB:501MiB:500MiB:ext4::boot
|
||||
fields = ('start', 'end', 'size', 'filesystem', 'flags')
|
||||
|
@ -80,7 +80,7 @@ class IronicException(Exception):
|
||||
# kwargs doesn't match a variable in the message
|
||||
# log the issue and the kwargs
|
||||
LOG.exception(_LE('Exception in string format operation'))
|
||||
for name, value in kwargs.iteritems():
|
||||
for name, value in kwargs.items():
|
||||
LOG.error("%s: %s" % (name, value))
|
||||
|
||||
if CONF.fatal_exception_format_errors:
|
||||
|
@ -25,6 +25,7 @@ from glanceclient import client
|
||||
from glanceclient import exc as glance_exc
|
||||
from oslo_config import cfg
|
||||
import sendfile
|
||||
import six
|
||||
import six.moves.urllib.parse as urlparse
|
||||
|
||||
from ironic.common import exception
|
||||
@ -146,7 +147,7 @@ class BaseImageService(object):
|
||||
else:
|
||||
new_exc = _translate_image_exception(
|
||||
args[0], exc_value)
|
||||
raise new_exc, None, exc_trace
|
||||
six.reraise(type(new_exc), new_exc, exc_trace)
|
||||
|
||||
@check_image_service
|
||||
def _detail(self, method='list', **kwargs):
|
||||
|
@ -151,7 +151,7 @@ def _get_api_server():
|
||||
|
||||
if not _GLANCE_API_SERVER:
|
||||
_GLANCE_API_SERVER = _get_api_server_iterator()
|
||||
return _GLANCE_API_SERVER.next()
|
||||
return six.next(_GLANCE_API_SERVER)
|
||||
|
||||
|
||||
def parse_image_ref(image_href):
|
||||
|
@ -18,6 +18,7 @@ import hashlib
|
||||
import threading
|
||||
|
||||
from oslo_config import cfg
|
||||
import six
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common.i18n import _
|
||||
@ -105,6 +106,8 @@ class HashRing(object):
|
||||
|
||||
def _get_partition(self, data):
|
||||
try:
|
||||
if six.PY3 and data is not None:
|
||||
data = data.encode('utf-8')
|
||||
key_hash = hashlib.md5(data)
|
||||
hashed_key = self._hash2int(key_hash)
|
||||
position = bisect.bisect(self._partitions, hashed_key)
|
||||
@ -180,7 +183,7 @@ class HashRingManager(object):
|
||||
rings = {}
|
||||
d2c = self.dbapi.get_active_driver_dict()
|
||||
|
||||
for driver_name, hosts in d2c.iteritems():
|
||||
for driver_name, hosts in d2c.items():
|
||||
rings[driver_name] = HashRing(hosts)
|
||||
return rings
|
||||
|
||||
|
@ -288,10 +288,10 @@ def sanitize_hostname(hostname):
|
||||
if isinstance(hostname, six.text_type):
|
||||
hostname = hostname.encode('latin-1', 'ignore')
|
||||
|
||||
hostname = re.sub('[ _]', '-', hostname)
|
||||
hostname = re.sub('[^\w.-]+', '', hostname)
|
||||
hostname = re.sub(b'[ _]', b'-', hostname)
|
||||
hostname = re.sub(b'[^\w.-]+', b'', hostname)
|
||||
hostname = hostname.lower()
|
||||
hostname = hostname.strip('.-')
|
||||
hostname = hostname.strip(b'.-')
|
||||
|
||||
return hostname
|
||||
|
||||
|
@ -1751,7 +1751,7 @@ class ConductorManager(periodic_task.PeriodicTasks):
|
||||
|
||||
def get_vendor_passthru_metadata(route_dict):
|
||||
d = {}
|
||||
for method, metadata in route_dict.iteritems():
|
||||
for method, metadata in route_dict.items():
|
||||
# 'func' is the vendor method reference, ignore it
|
||||
d[method] = {k: metadata[k] for k in metadata if k != 'func'}
|
||||
return d
|
||||
|
@ -132,7 +132,12 @@ class BaseInterface(object):
|
||||
# the conductor. We use __new__ instead of __init___
|
||||
# to avoid breaking backwards compatibility with all the drivers.
|
||||
# We want to return all steps, regardless of priority.
|
||||
instance = super(BaseInterface, cls).__new__(cls, *args, **kwargs)
|
||||
|
||||
super_new = super(BaseInterface, cls).__new__
|
||||
if super_new is object.__new__:
|
||||
instance = super_new(cls)
|
||||
else:
|
||||
instance = super_new(cls, *args, **kwargs)
|
||||
instance.clean_steps = []
|
||||
for n, method in inspect.getmembers(instance, inspect.ismethod):
|
||||
if getattr(method, '_is_clean_step', False):
|
||||
@ -548,7 +553,11 @@ class VendorInterface(object):
|
||||
"""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
inst = super(VendorInterface, cls).__new__(cls, *args, **kwargs)
|
||||
super_new = super(VendorInterface, cls).__new__
|
||||
if super_new is object.__new__:
|
||||
inst = super_new(cls)
|
||||
else:
|
||||
inst = super_new(cls, *args, **kwargs)
|
||||
|
||||
inst.vendor_routes = {}
|
||||
inst.driver_routes = {}
|
||||
|
@ -151,7 +151,9 @@ def parse_driver_info(node):
|
||||
for param in REQUIRED_PROPERTIES:
|
||||
value = info.get(param)
|
||||
if value:
|
||||
d_info[param[4:]] = six.binary_type(value)
|
||||
if not isinstance(value, six.binary_type):
|
||||
value = value.encode()
|
||||
d_info[param[4:]] = value
|
||||
else:
|
||||
missing_info.append(param)
|
||||
|
||||
@ -166,7 +168,9 @@ def parse_driver_info(node):
|
||||
if protocol not in AMT_PROTOCOL_PORT_MAP:
|
||||
raise exception.InvalidParameterValue(_("Invalid "
|
||||
"protocol %s.") % protocol)
|
||||
d_info[param[4:]] = six.binary_type(protocol)
|
||||
if not isinstance(value, six.binary_type):
|
||||
protocol = protocol.encode()
|
||||
d_info[param[4:]] = protocol
|
||||
|
||||
return d_info
|
||||
|
||||
|
@ -139,11 +139,11 @@ def make_persistent_password_file(path, password):
|
||||
utils.delete_if_exists(path)
|
||||
with open(path, 'wb') as file:
|
||||
os.chmod(path, 0o600)
|
||||
file.write(password)
|
||||
file.write(password.encode())
|
||||
return path
|
||||
except Exception as e:
|
||||
utils.delete_if_exists(path)
|
||||
raise exception.PasswordFileFailedToCreate(error=str(e))
|
||||
raise exception.PasswordFileFailedToCreate(error=e)
|
||||
|
||||
|
||||
def get_shellinabox_console_url(port):
|
||||
|
@ -505,7 +505,7 @@ def _get_configdrive(configdrive, node_uuid):
|
||||
data = configdrive
|
||||
|
||||
try:
|
||||
data = six.StringIO(base64.b64decode(data))
|
||||
data = six.BytesIO(base64.b64decode(data))
|
||||
except TypeError:
|
||||
error_msg = (_('Config drive for node %s is not base64 encoded '
|
||||
'or the content is malformed.') % node_uuid)
|
||||
|
@ -26,6 +26,7 @@ import uuid
|
||||
from oslo_concurrency import lockutils
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common.glance_service import service_utils
|
||||
@ -107,8 +108,9 @@ class ImageCache(object):
|
||||
else:
|
||||
# NOTE(vdrok): Doing conversion of href in case it's unicode
|
||||
# string, UUID cannot be generated for unicode strings on python 2.
|
||||
href_encoded = href.encode('utf-8') if six.PY2 else href
|
||||
master_file_name = str(uuid.uuid5(uuid.NAMESPACE_URL,
|
||||
href.encode('utf-8')))
|
||||
href_encoded))
|
||||
master_path = os.path.join(self.master_dir, master_file_name)
|
||||
|
||||
if CONF.parallel_image_downloads:
|
||||
@ -281,7 +283,7 @@ class ImageCache(object):
|
||||
"threshold %(expected)d"),
|
||||
{'dir': self.master_dir, 'actual': total_size,
|
||||
'expected': self._cache_size})
|
||||
return max(amount, 0)
|
||||
return max(amount, 0) if amount is not None else 0
|
||||
|
||||
|
||||
def _find_candidates_for_deletion(master_dir):
|
||||
@ -379,7 +381,7 @@ def cleanup(priority):
|
||||
"""Decorator method for adding cleanup priority to a class."""
|
||||
def _add_property_to_class_func(cls):
|
||||
_cache_cleanup_list.append((priority, cls))
|
||||
_cache_cleanup_list.sort(reverse=True)
|
||||
_cache_cleanup_list.sort(reverse=True, key=lambda tuple_: tuple_[0])
|
||||
return cls
|
||||
|
||||
return _add_property_to_class_func
|
||||
|
@ -380,7 +380,7 @@ def _exec_ipmitool(driver_info, command):
|
||||
except processutils.ProcessExecutionError as e:
|
||||
with excutils.save_and_reraise_exception() as ctxt:
|
||||
err_list = [x for x in IPMITOOL_RETRYABLE_FAILURES
|
||||
if x in e.message]
|
||||
if x in e.args[0]]
|
||||
if ((time.time() > end_time) or
|
||||
(num_tries == 0) or
|
||||
not err_list):
|
||||
|
@ -90,7 +90,7 @@ def parse_driver_info(node):
|
||||
"Missing the following iRMC parameters in node's"
|
||||
" driver_info: %s.") % missing_info)
|
||||
|
||||
req = {key: value for key, value in info.iteritems()
|
||||
req = {key: value for key, value in info.items()
|
||||
if key in REQUIRED_PROPERTIES}
|
||||
# corresponding config names don't have 'irmc_' prefix
|
||||
opt = {param: info.get(param, CONF.irmc.get(param[len('irmc_'):]))
|
||||
|
@ -277,7 +277,7 @@ def _cache_ramdisk_kernel(ctx, node, pxe_info):
|
||||
os.path.join(pxe_utils.get_root_dir(), node.uuid))
|
||||
LOG.debug("Fetching necessary kernel and ramdisk for node %s",
|
||||
node.uuid)
|
||||
deploy_utils.fetch_images(ctx, TFTPImageCache(), pxe_info.values(),
|
||||
deploy_utils.fetch_images(ctx, TFTPImageCache(), list(pxe_info.values()),
|
||||
CONF.force_raw_images)
|
||||
|
||||
|
||||
|
@ -579,8 +579,8 @@ class Management(base.ManagementInterface):
|
||||
except seamicro_client_exception.ClientException as ex:
|
||||
LOG.error(_LE("Seamicro set boot device failed for node "
|
||||
"%(node)s with the following error: %(error)s"),
|
||||
{'node': task.node.uuid, 'error': ex.message})
|
||||
raise exception.IronicException(message=ex.message)
|
||||
{'node': task.node.uuid, 'error': ex.args[0]})
|
||||
raise exception.IronicException(message=ex.args[0])
|
||||
|
||||
def get_boot_device(self, task):
|
||||
"""Get the current boot device for the task's node.
|
||||
|
@ -314,7 +314,7 @@ def _parse_driver_info(node):
|
||||
|
||||
# Only one credential may be set (avoids complexity around having
|
||||
# precedence etc).
|
||||
if len(filter(None, (password, key_filename, key_contents))) != 1:
|
||||
if len([v for v in (password, key_filename, key_contents) if v]) != 1:
|
||||
raise exception.InvalidParameterValue(_(
|
||||
"SSHPowerDriver requires one and only one of password, "
|
||||
"key_contents and key_filename to be set."))
|
||||
|
@ -54,7 +54,7 @@ def make_class_properties(cls):
|
||||
for name, field in supercls.fields.items():
|
||||
if name not in cls.fields:
|
||||
cls.fields[name] = field
|
||||
for name, typefn in cls.fields.iteritems():
|
||||
for name, typefn in cls.fields.items():
|
||||
|
||||
def getter(self, name=name):
|
||||
attrname = get_attrname(name)
|
||||
@ -394,7 +394,7 @@ class IronicObject(object):
|
||||
|
||||
@property
|
||||
def obj_fields(self):
|
||||
return self.fields.keys() + self.obj_extra_fields
|
||||
return list(self.fields) + self.obj_extra_fields
|
||||
|
||||
# dictish syntactic sugar
|
||||
def iteritems(self):
|
||||
@ -402,7 +402,7 @@ class IronicObject(object):
|
||||
|
||||
NOTE(danms): May be removed in the future.
|
||||
"""
|
||||
for name in self.fields.keys() + self.obj_extra_fields:
|
||||
for name in list(self.fields) + self.obj_extra_fields:
|
||||
if (hasattr(self, get_attrname(name)) or
|
||||
name in self.obj_extra_fields):
|
||||
yield name, getattr(self, name)
|
||||
|
@ -32,3 +32,14 @@ eventlet.monkey_patch(os=False)
|
||||
# The code below enables nosetests to work with i18n _() blocks
|
||||
import six.moves.builtins as __builtin__
|
||||
setattr(__builtin__, '_', lambda x: x)
|
||||
|
||||
# NOTE(viktors): We can't use mock as third-party library in python 3.4 because
|
||||
# of bug https://code.google.com/p/mock/issues/detail?id=234
|
||||
# so let's use mock from standard library in python 3.x
|
||||
import six
|
||||
|
||||
if six.PY3:
|
||||
import sys
|
||||
import unittest.mock
|
||||
|
||||
sys.modules['mock'] = unittest.mock
|
||||
|
@ -19,6 +19,7 @@ import json
|
||||
import mock
|
||||
from oslo import messaging
|
||||
from oslo_config import cfg
|
||||
import six
|
||||
from webob import exc as webob_exc
|
||||
|
||||
from ironic.api.controllers import root
|
||||
@ -137,7 +138,8 @@ class TestNoExceptionTracebackHook(base.FunctionalTest):
|
||||
# rare thing (happens due to wrong deserialization settings etc.)
|
||||
# we don't care about this garbage.
|
||||
expected_msg = ("Remote error: %s %s"
|
||||
% (test_exc_type, self.MSG_WITHOUT_TRACE) + "\n[u'")
|
||||
% (test_exc_type, self.MSG_WITHOUT_TRACE)
|
||||
+ ("\n[u'" if six.PY2 else "\n['"))
|
||||
actual_msg = json.loads(response.json['error_message'])['faultstring']
|
||||
self.assertEqual(expected_msg, actual_msg)
|
||||
|
||||
|
@ -74,7 +74,7 @@ class FakeMemcache(object):
|
||||
def remove_internal(values, internal):
|
||||
# NOTE(yuriyz): internal attributes should not be posted, except uuid
|
||||
int_attr = [attr.lstrip('/') for attr in internal if attr != '/uuid']
|
||||
return dict([(k, v) for (k, v) in values.iteritems() if k not in int_attr])
|
||||
return {k: v for (k, v) in values.items() if k not in int_attr}
|
||||
|
||||
|
||||
def node_post_data(**kw):
|
||||
|
@ -45,10 +45,10 @@ class TestListDrivers(base.FunctionalTest):
|
||||
expected = sorted([
|
||||
{'name': self.d1, 'hosts': [self.h1]},
|
||||
{'name': self.d2, 'hosts': [self.h1, self.h2]},
|
||||
])
|
||||
], key=lambda d: d['name'])
|
||||
data = self.get_json('/drivers')
|
||||
self.assertThat(data['drivers'], HasLength(2))
|
||||
drivers = sorted(data['drivers'])
|
||||
drivers = sorted(data['drivers'], key=lambda d: d['name'])
|
||||
for i in range(len(expected)):
|
||||
d = drivers[i]
|
||||
self.assertEqual(expected[i]['name'], d['name'])
|
||||
|
@ -22,6 +22,7 @@ import mock
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import timeutils
|
||||
from oslo_utils import uuidutils
|
||||
import six
|
||||
from six.moves.urllib import parse as urlparse
|
||||
from testtools.matchers import HasLength
|
||||
from wsme import types as wtypes
|
||||
@ -1197,6 +1198,8 @@ class TestPost(test_api_base.FunctionalTest):
|
||||
is_async=True):
|
||||
expected_status = 202 if is_async else 200
|
||||
expected_return_value = json.dumps(return_value)
|
||||
if six.PY3:
|
||||
expected_return_value = expected_return_value.encode('utf-8')
|
||||
|
||||
node = obj_utils.create_test_node(self.context)
|
||||
info = {'foo': 'bar'}
|
||||
@ -1212,6 +1215,8 @@ class TestPost(test_api_base.FunctionalTest):
|
||||
is_async=True):
|
||||
expected_status = 202 if is_async else 200
|
||||
expected_return_value = json.dumps(return_value)
|
||||
if six.PY3:
|
||||
expected_return_value = expected_return_value.encode('utf-8')
|
||||
|
||||
node = obj_utils.create_test_node(self.context, name='node-109')
|
||||
info = {'foo': 'bar'}
|
||||
@ -1276,9 +1281,7 @@ class TestPost(test_api_base.FunctionalTest):
|
||||
with mock.patch.object(
|
||||
rpcapi.ConductorAPI, 'vendor_passthru') as mock_vendor:
|
||||
mock_vendor.side_effect = exception.UnsupportedDriverExtension(
|
||||
{'driver': node.driver,
|
||||
'node': uuid,
|
||||
'extension': 'test'})
|
||||
**{'driver': node.driver, 'node': uuid, 'extension': 'test'})
|
||||
response = self.post_json('/nodes/%s/vendor_passthru/test' % uuid,
|
||||
info, expect_errors=True)
|
||||
mock_vendor.assert_called_once_with(
|
||||
@ -1470,7 +1473,7 @@ class TestDelete(test_api_base.FunctionalTest):
|
||||
mock_get.return_value = node
|
||||
response = self.delete('/nodes/%s/maintenance' % node.uuid)
|
||||
self.assertEqual(202, response.status_int)
|
||||
self.assertEqual('', response.body)
|
||||
self.assertEqual(b'', response.body)
|
||||
self.assertEqual(False, node.maintenance)
|
||||
self.assertEqual(None, node.maintenance_reason)
|
||||
mock_get.assert_called_once_with(mock.ANY, node.uuid)
|
||||
@ -1488,7 +1491,7 @@ class TestDelete(test_api_base.FunctionalTest):
|
||||
response = self.delete('/nodes/%s/maintenance' % node.name,
|
||||
headers={api_base.Version.string: "1.5"})
|
||||
self.assertEqual(202, response.status_int)
|
||||
self.assertEqual('', response.body)
|
||||
self.assertEqual(b'', response.body)
|
||||
self.assertEqual(False, node.maintenance)
|
||||
self.assertEqual(None, node.maintenance_reason)
|
||||
mock_get.assert_called_once_with(mock.ANY, node.name)
|
||||
@ -1523,7 +1526,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
response = self.put_json('/nodes/%s/states/power' % self.node.uuid,
|
||||
{'target': states.POWER_ON})
|
||||
self.assertEqual(202, response.status_code)
|
||||
self.assertEqual('', response.body)
|
||||
self.assertEqual(b'', response.body)
|
||||
self.mock_cnps.assert_called_once_with(mock.ANY,
|
||||
self.node.uuid,
|
||||
states.POWER_ON,
|
||||
@ -1545,7 +1548,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
{'target': states.POWER_ON},
|
||||
headers={api_base.Version.string: "1.5"})
|
||||
self.assertEqual(202, response.status_code)
|
||||
self.assertEqual('', response.body)
|
||||
self.assertEqual(b'', response.body)
|
||||
self.mock_cnps.assert_called_once_with(mock.ANY,
|
||||
self.node.uuid,
|
||||
states.POWER_ON,
|
||||
@ -1577,7 +1580,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
ret = self.put_json('/nodes/%s/states/provision' % self.node.uuid,
|
||||
{'target': states.ACTIVE})
|
||||
self.assertEqual(202, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
self.mock_dnd.assert_called_once_with(
|
||||
mock.ANY, self.node.uuid, False, None, 'test-topic')
|
||||
# Check location header
|
||||
@ -1597,7 +1600,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
{'target': states.ACTIVE},
|
||||
headers={api_base.Version.string: "1.5"})
|
||||
self.assertEqual(202, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
self.mock_dnd.assert_called_once_with(
|
||||
mock.ANY, self.node.uuid, False, None, 'test-topic')
|
||||
|
||||
@ -1605,7 +1608,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
ret = self.put_json('/nodes/%s/states/provision' % self.node.uuid,
|
||||
{'target': states.ACTIVE, 'configdrive': 'foo'})
|
||||
self.assertEqual(202, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
self.mock_dnd.assert_called_once_with(
|
||||
mock.ANY, self.node.uuid, False, 'foo', 'test-topic')
|
||||
# Check location header
|
||||
@ -1628,7 +1631,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
ret = self.put_json('/nodes/%s/states/provision' % node.uuid,
|
||||
{'target': states.DELETED})
|
||||
self.assertEqual(202, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
self.mock_dntd.assert_called_once_with(
|
||||
mock.ANY, node.uuid, 'test-topic')
|
||||
# Check location header
|
||||
@ -1656,7 +1659,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
ret = self.put_json('/nodes/%s/states/provision' % node.uuid,
|
||||
{'target': states.DELETED})
|
||||
self.assertEqual(202, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
self.mock_dntd.assert_called_once_with(
|
||||
mock.ANY, node.uuid, 'test-topic')
|
||||
# Check location header
|
||||
@ -1678,7 +1681,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
ret = self.put_json('/nodes/%s/states/provision' % node.uuid,
|
||||
{'target': states.ACTIVE})
|
||||
self.assertEqual(202, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
self.mock_dnd.assert_called_once_with(
|
||||
mock.ANY, node.uuid, False, None, 'test-topic')
|
||||
# Check location header
|
||||
@ -1711,7 +1714,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
{'target': states.VERBS['provide']},
|
||||
headers={api_base.Version.string: "1.4"})
|
||||
self.assertEqual(202, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
mock_dpa.assert_called_once_with(mock.ANY, self.node.uuid,
|
||||
states.VERBS['provide'],
|
||||
'test-topic')
|
||||
@ -1736,7 +1739,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
{'target': states.VERBS['manage']},
|
||||
headers={api_base.Version.string: "1.4"})
|
||||
self.assertEqual(202, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
mock_dpa.assert_called_once_with(mock.ANY, self.node.uuid,
|
||||
states.VERBS['manage'],
|
||||
'test-topic')
|
||||
@ -1759,7 +1762,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
ret = self.put_json('/nodes/%s/states/console' % self.node.uuid,
|
||||
{'enabled': "true"})
|
||||
self.assertEqual(202, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
mock_scm.assert_called_once_with(mock.ANY, self.node.uuid,
|
||||
True, 'test-topic')
|
||||
# Check location header
|
||||
@ -1781,7 +1784,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
{'enabled': "true"},
|
||||
headers={api_base.Version.string: "1.5"})
|
||||
self.assertEqual(202, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
mock_scm.assert_called_once_with(mock.ANY, self.node.uuid,
|
||||
True, 'test-topic')
|
||||
|
||||
@ -1791,7 +1794,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
ret = self.put_json('/nodes/%s/states/console' % self.node.uuid,
|
||||
{'enabled': "false"})
|
||||
self.assertEqual(202, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
mock_scm.assert_called_once_with(mock.ANY, self.node.uuid,
|
||||
False, 'test-topic')
|
||||
# Check location header
|
||||
@ -1846,7 +1849,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
ret = self.put_json('/nodes/%s/management/boot_device'
|
||||
% self.node.uuid, {'boot_device': device})
|
||||
self.assertEqual(204, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
mock_sbd.assert_called_once_with(mock.ANY, self.node.uuid,
|
||||
device, persistent=False,
|
||||
topic='test-topic')
|
||||
@ -1858,7 +1861,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
% self.node.name, {'boot_device': device},
|
||||
headers={api_base.Version.string: "1.5"})
|
||||
self.assertEqual(204, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
mock_sbd.assert_called_once_with(mock.ANY, self.node.uuid,
|
||||
device, persistent=False,
|
||||
topic='test-topic')
|
||||
@ -1883,7 +1886,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
ret = self.put_json('/nodes/%s/management/boot_device?persistent=True'
|
||||
% self.node.uuid, {'boot_device': device})
|
||||
self.assertEqual(204, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
mock_sbd.assert_called_once_with(mock.ANY, self.node.uuid,
|
||||
device, persistent=True,
|
||||
topic='test-topic')
|
||||
@ -1912,7 +1915,7 @@ class TestPut(test_api_base.FunctionalTest):
|
||||
ret = self.put_json('/nodes/%s/maintenance' % node_ident,
|
||||
request_body, headers=headers)
|
||||
self.assertEqual(202, ret.status_code)
|
||||
self.assertEqual('', ret.body)
|
||||
self.assertEqual(b'', ret.body)
|
||||
self.assertEqual(True, self.node.maintenance)
|
||||
self.assertEqual(reason, self.node.maintenance_reason)
|
||||
mock_get.assert_called_once_with(mock.ANY, node_ident)
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
import mock
|
||||
from oslo_utils import uuidutils
|
||||
import six
|
||||
import webtest
|
||||
import wsme
|
||||
from wsme import types as wtypes
|
||||
@ -134,7 +135,7 @@ class TestJsonPatchType(base.TestCase):
|
||||
'value': {'cat': 'meow'}}]
|
||||
ret = self._patch_json(valid_patches, False)
|
||||
self.assertEqual(200, ret.status_int)
|
||||
self.assertEqual(sorted(valid_patches), sorted(ret.json))
|
||||
self.assertItemsEqual(valid_patches, ret.json)
|
||||
|
||||
def test_cannot_update_internal_attr(self):
|
||||
patch = [{'path': '/internal', 'op': 'replace', 'value': 'foo'}]
|
||||
@ -255,7 +256,8 @@ class TestJsonType(base.TestCase):
|
||||
vts = str(types.jsontype)
|
||||
self.assertIn(str(wtypes.text), vts)
|
||||
self.assertIn(str(int), vts)
|
||||
self.assertIn(str(long), vts)
|
||||
if six.PY2:
|
||||
self.assertIn(str(long), vts)
|
||||
self.assertIn(str(float), vts)
|
||||
self.assertIn(str(types.BooleanType), vts)
|
||||
self.assertIn(str(list), vts)
|
||||
|
@ -124,7 +124,7 @@ class TestCase(testtools.TestCase):
|
||||
def config(self, **kw):
|
||||
"""Override config options for a test."""
|
||||
group = kw.pop('group', None)
|
||||
for k, v in kw.iteritems():
|
||||
for k, v in kw.items():
|
||||
CONF.set_override(k, v, group)
|
||||
|
||||
def path_get(self, project_file=None):
|
||||
|
@ -1311,7 +1311,7 @@ class DoNodeDeployTearDownTestCase(_ServiceSetUpMixin,
|
||||
self.assertRaises(exception.SwiftOperationError,
|
||||
manager.do_node_deploy, task,
|
||||
self.service.conductor.id,
|
||||
configdrive='fake config drive')
|
||||
configdrive=b'fake config drive')
|
||||
node.refresh()
|
||||
self.assertEqual(states.DEPLOYFAIL, node.provision_state)
|
||||
self.assertEqual(states.ACTIVE, node.target_provision_state)
|
||||
@ -3573,7 +3573,7 @@ class StoreConfigDriveTestCase(tests_base.TestCase):
|
||||
group='conductor')
|
||||
mock_swift.return_value.get_temp_url.return_value = 'http://1.2.3.4'
|
||||
|
||||
manager._store_configdrive(self.node, 'foo')
|
||||
manager._store_configdrive(self.node, b'foo')
|
||||
|
||||
mock_swift.assert_called_once_with()
|
||||
mock_swift.return_value.create_object.assert_called_once_with(
|
||||
|
@ -91,8 +91,8 @@ class DracClientTestCase(base.TestCase):
|
||||
|
||||
# assert the XML was merged
|
||||
result_string = ElementTree.tostring(result)
|
||||
self.assertIn('<item1>test1</item1>', result_string)
|
||||
self.assertIn('<item2>test2</item2>', result_string)
|
||||
self.assertIn(b'<item1>test1</item1>', result_string)
|
||||
self.assertIn(b'<item2>test2</item2>', result_string)
|
||||
|
||||
mock_options = mock_client_pywsman.ClientOptions.return_value
|
||||
mock_options.set_flags.assert_called_once_with(
|
||||
|
@ -20,6 +20,7 @@ import tempfile
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import importutils
|
||||
import six
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common import images
|
||||
@ -35,6 +36,10 @@ from ironic.tests.objects import utils as obj_utils
|
||||
ilo_client = importutils.try_import('proliantutils.ilo.client')
|
||||
ilo_error = importutils.try_import('proliantutils.exception')
|
||||
|
||||
if six.PY3:
|
||||
import io
|
||||
file = io.BytesIO
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
@ -19,6 +19,7 @@ import tempfile
|
||||
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
import six
|
||||
|
||||
from ironic.common import boot_devices
|
||||
from ironic.common import exception
|
||||
@ -44,6 +45,10 @@ from ironic.tests.db import utils as db_utils
|
||||
from ironic.tests.objects import utils as obj_utils
|
||||
|
||||
|
||||
if six.PY3:
|
||||
import io
|
||||
file = io.BytesIO
|
||||
|
||||
INFO_DICT = db_utils.get_test_ilo_info()
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
@ -195,7 +195,7 @@ class ConsoleUtilsTestCase(db_base.DbTestCase):
|
||||
'tempdir': tempfile.gettempdir(),
|
||||
'node_uuid': self.info['uuid']}
|
||||
password = ''.join([random.choice(string.ascii_letters)
|
||||
for n in xrange(16)])
|
||||
for n in range(16)])
|
||||
console_utils.make_persistent_password_file(filepath, password)
|
||||
# make sure file exists
|
||||
self.assertTrue(os.path.exists(filepath))
|
||||
|
@ -46,7 +46,7 @@ from ironic.tests.db import base as db_base
|
||||
from ironic.tests.db import utils as db_utils
|
||||
from ironic.tests.objects import utils as obj_utils
|
||||
|
||||
_PXECONF_DEPLOY = """
|
||||
_PXECONF_DEPLOY = b"""
|
||||
default deploy
|
||||
|
||||
label deploy
|
||||
@ -97,7 +97,7 @@ COM32 chain.c32
|
||||
append mbr:0x12345678
|
||||
"""
|
||||
|
||||
_IPXECONF_DEPLOY = """
|
||||
_IPXECONF_DEPLOY = b"""
|
||||
#!ipxe
|
||||
|
||||
dhcp
|
||||
@ -166,7 +166,7 @@ append mbr:0x12345678
|
||||
boot
|
||||
"""
|
||||
|
||||
_UEFI_PXECONF_DEPLOY = """
|
||||
_UEFI_PXECONF_DEPLOY = b"""
|
||||
default=deploy
|
||||
|
||||
image=deploy_kernel
|
||||
@ -1169,7 +1169,7 @@ class MakePartitionsTestCase(tests_base.TestCase):
|
||||
self.ephemeral_mb, self.configdrive_mb)
|
||||
|
||||
parted_call = mock.call(*cmd, run_as_root=True, check_exit_code=[0])
|
||||
mock_exc.assert_has_calls(parted_call)
|
||||
mock_exc.assert_has_calls([parted_call])
|
||||
|
||||
|
||||
@mock.patch.object(utils, 'get_dev_block_size')
|
||||
|
@ -23,6 +23,7 @@ import uuid
|
||||
|
||||
import mock
|
||||
from oslo_utils import uuidutils
|
||||
import six
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common import image_service
|
||||
@ -131,8 +132,8 @@ class TestImageCacheFetch(base.TestCase):
|
||||
def test_fetch_image_not_uuid(self, mock_download, mock_clean_up,
|
||||
mock_fetch):
|
||||
href = u'http://abc.com/ubuntu.qcow2'
|
||||
href_converted = str(uuid.uuid5(uuid.NAMESPACE_URL,
|
||||
href.encode('utf-8')))
|
||||
href_encoded = href.encode('utf-8') if six.PY2 else href
|
||||
href_converted = str(uuid.uuid5(uuid.NAMESPACE_URL, href_encoded))
|
||||
master_path = os.path.join(self.master_dir, href_converted)
|
||||
self.cache.fetch_image(href, self.dest_path)
|
||||
self.assertFalse(mock_fetch.called)
|
||||
@ -195,7 +196,7 @@ class TestImageCacheCleanUp(base.TestCase):
|
||||
files = [os.path.join(self.master_dir, str(i))
|
||||
for i in range(2)]
|
||||
for filename in files:
|
||||
open(filename, 'wb').write('X')
|
||||
open(filename, 'wb').write(b'X')
|
||||
new_current_time = time.time() + 900
|
||||
with mock.patch.object(time, 'time', lambda: new_current_time):
|
||||
self.cache.clean_up(amount=1)
|
||||
|
@ -223,8 +223,8 @@ class IPMINativeDriverTestCase(db_base.DbTestCase):
|
||||
self.assertEqual(expected, self.driver.power.get_properties())
|
||||
self.assertEqual(expected, self.driver.management.get_properties())
|
||||
|
||||
expected = ipminative.COMMON_PROPERTIES.keys()
|
||||
expected += ipminative.CONSOLE_PROPERTIES.keys()
|
||||
expected = list(ipminative.COMMON_PROPERTIES)
|
||||
expected += list(ipminative.CONSOLE_PROPERTIES)
|
||||
self.assertEqual(sorted(expected),
|
||||
sorted(self.driver.console.get_properties().keys()))
|
||||
self.assertEqual(sorted(expected),
|
||||
|
@ -251,7 +251,7 @@ class IPMIToolPrivateMethodTestCase(db_base.DbTestCase):
|
||||
ValueError,
|
||||
self._test__make_password_file,
|
||||
mock_sleep, 12345, ValueError('we should fail'))
|
||||
self.assertEqual(result.message, 'we should fail')
|
||||
self.assertEqual('we should fail', result.args[0])
|
||||
|
||||
@mock.patch.object(tempfile, 'NamedTemporaryFile',
|
||||
new=mock.MagicMock(side_effect=OSError('Test Error')))
|
||||
@ -270,7 +270,7 @@ class IPMIToolPrivateMethodTestCase(db_base.DbTestCase):
|
||||
result = self.assertRaises(
|
||||
OverflowError,
|
||||
self._test__make_password_file, mock_sleep, 12345)
|
||||
self.assertEqual(result.message, 'Test Error')
|
||||
self.assertEqual('Test Error', result.args[0])
|
||||
|
||||
def test__make_password_file_write_exception(self, mock_sleep):
|
||||
# Test exception in _make_password_file for write()
|
||||
|
@ -400,8 +400,8 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
||||
|
||||
pxe._cache_ramdisk_kernel(self.context, self.node, fake_pxe_info)
|
||||
mock_ensure_tree.assert_called_with(expected_path)
|
||||
mock_fetch_image.assert_called_once_with(self.context, mock.ANY,
|
||||
fake_pxe_info.values(), True)
|
||||
mock_fetch_image.assert_called_once_with(
|
||||
self.context, mock.ANY, list(fake_pxe_info.values()), True)
|
||||
|
||||
@mock.patch.object(pxe, 'TFTPImageCache', lambda: None)
|
||||
@mock.patch.object(fileutils, 'ensure_tree')
|
||||
@ -415,7 +415,7 @@ class PXEPrivateMethodsTestCase(db_base.DbTestCase):
|
||||
pxe._cache_ramdisk_kernel(self.context, self.node, fake_pxe_info)
|
||||
mock_ensure_tree.assert_called_with(expected_path)
|
||||
mock_fetch_image.assert_called_once_with(self.context, mock.ANY,
|
||||
fake_pxe_info.values(),
|
||||
list(fake_pxe_info.values()),
|
||||
True)
|
||||
|
||||
@mock.patch.object(pxe.LOG, 'error')
|
||||
|
@ -33,6 +33,7 @@ import sys
|
||||
|
||||
import mock
|
||||
from oslo_utils import importutils
|
||||
import six
|
||||
|
||||
from ironic.drivers.modules import ipmitool
|
||||
from ironic.tests.drivers import third_party_driver_mock_specs as mock_specs
|
||||
@ -54,7 +55,7 @@ if not seamicroclient:
|
||||
# if anything has loaded the seamicro driver yet, reload it now that
|
||||
# the external library has been mocked
|
||||
if 'ironic.drivers.modules.seamicro' in sys.modules:
|
||||
reload(sys.modules['ironic.drivers.modules.seamicro'])
|
||||
six.moves.reload_module(sys.modules['ironic.drivers.modules.seamicro'])
|
||||
|
||||
# IPMITool driver checks the system for presence of 'ipmitool' binary during
|
||||
# __init__. We bypass that check in order to run the unit tests, which do not
|
||||
@ -81,7 +82,7 @@ if not pyghmi:
|
||||
p.ipmi.command.boot_devices = {'pxe': 4}
|
||||
|
||||
if 'ironic.drivers.modules.ipminative' in sys.modules:
|
||||
reload(sys.modules['ironic.drivers.modules.ipminative'])
|
||||
six.moves.reload_module(sys.modules['ironic.drivers.modules.ipminative'])
|
||||
|
||||
proliantutils = importutils.try_import('proliantutils')
|
||||
if not proliantutils:
|
||||
@ -94,7 +95,7 @@ if not proliantutils:
|
||||
command_exception = type('IloCommandNotSupportedError', (Exception,), {})
|
||||
proliantutils.exception.IloCommandNotSupportedError = command_exception
|
||||
if 'ironic.drivers.ilo' in sys.modules:
|
||||
reload(sys.modules['ironic.drivers.ilo'])
|
||||
six.moves.reload_module(sys.modules['ironic.drivers.ilo'])
|
||||
|
||||
|
||||
# attempt to load the external 'pywsman' library, which is required by
|
||||
@ -106,9 +107,9 @@ if not pywsman:
|
||||
# Now that the external library has been mocked, if anything had already
|
||||
# loaded any of the drivers, reload them.
|
||||
if 'ironic.drivers.modules.drac' in sys.modules:
|
||||
reload(sys.modules['ironic.drivers.modules.drac'])
|
||||
six.moves.reload_module(sys.modules['ironic.drivers.modules.drac'])
|
||||
if 'ironic.drivers.modules.amt' in sys.modules:
|
||||
reload(sys.modules['ironic.drivers.modules.amt'])
|
||||
six.moves.reload_module(sys.modules['ironic.drivers.modules.amt'])
|
||||
|
||||
|
||||
# attempt to load the external 'iboot' library, which is required by
|
||||
@ -122,7 +123,7 @@ if not iboot:
|
||||
# if anything has loaded the iboot driver yet, reload it now that the
|
||||
# external library has been mocked
|
||||
if 'ironic.drivers.modules.iboot' in sys.modules:
|
||||
reload(sys.modules['ironic.drivers.modules.iboot'])
|
||||
six.moves.reload_module(sys.modules['ironic.drivers.modules.iboot'])
|
||||
|
||||
|
||||
# attempt to load the external 'pysnmp' library, which is required by
|
||||
@ -148,7 +149,7 @@ if not pysnmp:
|
||||
# if anything has loaded the snmp driver yet, reload it now that the
|
||||
# external library has been mocked
|
||||
if 'ironic.drivers.modules.snmp' in sys.modules:
|
||||
reload(sys.modules['ironic.drivers.modules.snmp'])
|
||||
six.moves.reload_module(sys.modules['ironic.drivers.modules.snmp'])
|
||||
|
||||
|
||||
# attempt to load the external 'scciclient' library, which is required by
|
||||
@ -168,7 +169,7 @@ if not scciclient:
|
||||
# if anything has loaded the iRMC driver yet, reload it now that the
|
||||
# external library has been mocked
|
||||
if 'ironic.drivers.modules.irmc' in sys.modules:
|
||||
reload(sys.modules['ironic.drivers.modules.irmc'])
|
||||
six.moves.reload_module(sys.modules['ironic.drivers.modules.irmc'])
|
||||
|
||||
pyremotevbox = importutils.try_import('pyremotevbox')
|
||||
if not pyremotevbox:
|
||||
@ -178,7 +179,8 @@ if not pyremotevbox:
|
||||
pyremotevbox.exception.VmInWrongPowerState = Exception
|
||||
sys.modules['pyremotevbox'] = pyremotevbox
|
||||
if 'ironic.drivers.modules.virtualbox' in sys.modules:
|
||||
reload(sys.modules['ironic.drivers.modules.virtualbox'])
|
||||
six.moves.reload_module(
|
||||
sys.modules['ironic.drivers.modules.virtualbox'])
|
||||
|
||||
|
||||
ironic_discoverd = importutils.try_import('ironic_discoverd')
|
||||
@ -189,4 +191,5 @@ if not ironic_discoverd:
|
||||
sys.modules['ironic_discoverd'] = ironic_discoverd
|
||||
sys.modules['ironic_discoverd.client'] = ironic_discoverd.client
|
||||
if 'ironic.drivers.modules.discoverd' in sys.modules:
|
||||
reload(sys.modules['ironic.drivers.modules.discoverd'])
|
||||
six.moves.reload_module(
|
||||
sys.modules['ironic.drivers.modules.discoverd'])
|
||||
|
@ -310,14 +310,10 @@ class _TestObject(object):
|
||||
class Foo(base.IronicObject):
|
||||
fields = {'foobar': int}
|
||||
obj = Foo(self.context)
|
||||
# NOTE(danms): Can't use assertRaisesRegexp() because of py26
|
||||
raised = False
|
||||
try:
|
||||
obj.foobar
|
||||
except NotImplementedError as ex:
|
||||
raised = True
|
||||
self.assertTrue(raised)
|
||||
self.assertTrue('foobar' in str(ex))
|
||||
|
||||
self.assertRaisesRegexp(
|
||||
NotImplementedError, "Cannot load 'foobar' in the base class",
|
||||
getattr, obj, 'foobar')
|
||||
|
||||
def test_loaded_in_primitive(self):
|
||||
obj = MyObj(self.context)
|
||||
@ -467,7 +463,7 @@ class _TestObject(object):
|
||||
self.assertRaises(AttributeError, obj.get, 'nothing', 3)
|
||||
|
||||
def test_object_inheritance(self):
|
||||
base_fields = base.IronicObject.fields.keys()
|
||||
base_fields = list(base.IronicObject.fields)
|
||||
myobj_fields = ['foo', 'bar', 'missing'] + base_fields
|
||||
myobj3_fields = ['new_field']
|
||||
self.assertTrue(issubclass(TestSubclassedObject, MyObj))
|
||||
|
@ -20,8 +20,9 @@ from ironic.tests import base
|
||||
|
||||
class TestIronicException(base.TestCase):
|
||||
def test____init__(self):
|
||||
expected = '\xc3\xa9\xe0\xaf\xb2\xe0\xbe\x84'
|
||||
expected = b'\xc3\xa9\xe0\xaf\xb2\xe0\xbe\x84'
|
||||
if six.PY3:
|
||||
expected = expected.decode('utf-8')
|
||||
message = chr(233) + chr(0x0bf2) + chr(3972)
|
||||
else:
|
||||
message = unichr(233) + unichr(0x0bf2) + unichr(3972)
|
||||
|
@ -27,7 +27,6 @@ from oslo_context import context
|
||||
from oslo_serialization import jsonutils
|
||||
import testtools
|
||||
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common.glance_service import base_image_service
|
||||
from ironic.common.glance_service import service_utils
|
||||
@ -381,8 +380,8 @@ class TestGlanceImageService(base.TestCase):
|
||||
self.assertEqual(2, num_images)
|
||||
|
||||
# Check the image is marked as deleted.
|
||||
num_images = reduce(lambda x, y: x + (0 if y['deleted'] else 1),
|
||||
self.service.detail(), 0)
|
||||
num_images = len([x for x in self.service.detail()
|
||||
if not x['deleted']])
|
||||
self.assertEqual(1, num_images)
|
||||
|
||||
def test_show_passes_through_to_client(self):
|
||||
@ -499,8 +498,8 @@ class TestGlanceImageService(base.TestCase):
|
||||
"""A client that returns a file url."""
|
||||
|
||||
(outfd, s_tmpfname) = tempfile.mkstemp(prefix='directURLsrc')
|
||||
outf = os.fdopen(outfd, 'w')
|
||||
inf = open('/dev/urandom', 'r')
|
||||
outf = os.fdopen(outfd, 'wb')
|
||||
inf = open('/dev/urandom', 'rb')
|
||||
for i in range(10):
|
||||
_data = inf.read(1024)
|
||||
outf.write(_data)
|
||||
|
@ -16,6 +16,7 @@ import shutil
|
||||
import mock
|
||||
import requests
|
||||
import sendfile
|
||||
import six
|
||||
import six.moves.builtins as __builtin__
|
||||
|
||||
from ironic.common import exception
|
||||
@ -23,6 +24,10 @@ from ironic.common.glance_service.v1 import image_service as glance_v1_service
|
||||
from ironic.common import image_service
|
||||
from ironic.tests import base
|
||||
|
||||
if six.PY3:
|
||||
import io
|
||||
file = io.BytesIO
|
||||
|
||||
|
||||
class HttpImageServiceTestCase(base.TestCase):
|
||||
def setUp(self):
|
||||
@ -167,6 +172,7 @@ class FileImageServiceTestCase(base.TestCase):
|
||||
_validate_mock.return_value = self.href_path
|
||||
stat_mock.return_value.st_dev = 'dev1'
|
||||
file_mock = mock.MagicMock(spec=file)
|
||||
file_mock.name = 'file'
|
||||
input_mock = mock.MagicMock(spec=file)
|
||||
open_mock.return_value = input_mock
|
||||
self.service.download(self.href, file_mock)
|
||||
@ -208,6 +214,7 @@ class FileImageServiceTestCase(base.TestCase):
|
||||
_validate_mock.return_value = self.href_path
|
||||
stat_mock.return_value.st_dev = 'dev1'
|
||||
file_mock = mock.MagicMock(spec=file)
|
||||
file_mock.name = 'file'
|
||||
input_mock = mock.MagicMock(spec=file)
|
||||
open_mock.return_value = input_mock
|
||||
self.assertRaises(exception.ImageDownloadFailed,
|
||||
|
@ -22,6 +22,7 @@ import shutil
|
||||
import mock
|
||||
from oslo_concurrency import processutils
|
||||
from oslo_config import cfg
|
||||
import six
|
||||
import six.moves.builtins as __builtin__
|
||||
|
||||
from ironic.common import exception
|
||||
@ -32,6 +33,10 @@ from ironic.common import utils
|
||||
from ironic.openstack.common import imageutils
|
||||
from ironic.tests import base
|
||||
|
||||
if six.PY3:
|
||||
import io
|
||||
file = io.BytesIO
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
|
@ -18,6 +18,7 @@ import os
|
||||
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
import six
|
||||
|
||||
from ironic.common import pxe_utils
|
||||
from ironic.conductor import task_manager
|
||||
@ -84,7 +85,7 @@ class TestPXEUtils(db_base.DbTestCase):
|
||||
expected_template = open(
|
||||
'ironic/tests/drivers/pxe_config.template').read().rstrip()
|
||||
|
||||
self.assertEqual(unicode(expected_template), rendered_template)
|
||||
self.assertEqual(six.text_type(expected_template), rendered_template)
|
||||
|
||||
def test__build_pxe_config_with_agent(self):
|
||||
|
||||
@ -94,7 +95,7 @@ class TestPXEUtils(db_base.DbTestCase):
|
||||
expected_template = open(
|
||||
'ironic/tests/drivers/agent_pxe_config.template').read().rstrip()
|
||||
|
||||
self.assertEqual(unicode(expected_template), rendered_template)
|
||||
self.assertEqual(six.text_type(expected_template), rendered_template)
|
||||
|
||||
def test__build_ipxe_config(self):
|
||||
# NOTE(lucasagomes): iPXE is just an extension of the PXE driver,
|
||||
@ -112,7 +113,7 @@ class TestPXEUtils(db_base.DbTestCase):
|
||||
expected_template = open(
|
||||
'ironic/tests/drivers/ipxe_config.template').read().rstrip()
|
||||
|
||||
self.assertEqual(unicode(expected_template), rendered_template)
|
||||
self.assertEqual(six.text_type(expected_template), rendered_template)
|
||||
|
||||
def test__build_elilo_config(self):
|
||||
pxe_opts = self.pxe_options
|
||||
@ -124,7 +125,7 @@ class TestPXEUtils(db_base.DbTestCase):
|
||||
'ironic/tests/drivers/elilo_efi_pxe_config.template'
|
||||
).read().rstrip()
|
||||
|
||||
self.assertEqual(unicode(expected_template), rendered_template)
|
||||
self.assertEqual(six.text_type(expected_template), rendered_template)
|
||||
|
||||
@mock.patch('ironic.common.utils.create_link_without_raise', autospec=True)
|
||||
@mock.patch('ironic.common.utils.unlink_without_raise', autospec=True)
|
||||
@ -346,8 +347,8 @@ class TestPXEUtils(db_base.DbTestCase):
|
||||
{'opt_name': 'bootfile-name',
|
||||
'opt_value': expected_boot_script_url}]
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
self.assertEqual(sorted(expected_info),
|
||||
sorted(pxe_utils.dhcp_options_for_instance(task)))
|
||||
self.assertItemsEqual(expected_info,
|
||||
pxe_utils.dhcp_options_for_instance(task))
|
||||
|
||||
self.config(dhcp_provider='neutron', group='dhcp')
|
||||
expected_boot_script_url = 'http://192.0.3.2:1234/boot.ipxe'
|
||||
@ -360,8 +361,8 @@ class TestPXEUtils(db_base.DbTestCase):
|
||||
{'opt_name': 'bootfile-name',
|
||||
'opt_value': expected_boot_script_url}]
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
self.assertEqual(sorted(expected_info),
|
||||
sorted(pxe_utils.dhcp_options_for_instance(task)))
|
||||
self.assertItemsEqual(expected_info,
|
||||
pxe_utils.dhcp_options_for_instance(task))
|
||||
|
||||
@mock.patch('ironic.common.utils.rmtree_without_raise', autospec=True)
|
||||
@mock.patch('ironic.common.utils.unlink_without_raise', autospec=True)
|
||||
|
@ -14,6 +14,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import six
|
||||
|
||||
from ironic.common import states
|
||||
from ironic.tests import base
|
||||
|
||||
@ -28,10 +30,10 @@ class StatesTest(base.TestCase):
|
||||
This is specified in db/sqlalchemy/models.py
|
||||
|
||||
"""
|
||||
for key, value in states.__dict__.iteritems():
|
||||
for key, value in states.__dict__.items():
|
||||
# Assumption: A state variable name is all UPPERCASE and contents
|
||||
# are a string.
|
||||
if key.upper() == key and isinstance(value, basestring):
|
||||
if key.upper() == key and isinstance(value, six.string_types):
|
||||
self.assertTrue(
|
||||
(len(value) <= 15),
|
||||
"Value for state: {} is greater than 15 characters".format(
|
||||
|
@ -12,11 +12,12 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import __builtin__
|
||||
import sys
|
||||
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
import six
|
||||
from six.moves import builtins as __builtin__
|
||||
from swiftclient import client as swift_client
|
||||
from swiftclient import exceptions as swift_exception
|
||||
from swiftclient import utils as swift_utils
|
||||
@ -27,6 +28,10 @@ from ironic.tests import base
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
if six.PY3:
|
||||
import io
|
||||
file = io.BytesIO
|
||||
|
||||
|
||||
@mock.patch.object(swift_client, 'Connection', autospec=True)
|
||||
class SwiftTestCase(base.TestCase):
|
||||
@ -46,7 +51,7 @@ class SwiftTestCase(base.TestCase):
|
||||
# The constructor of SwiftAPI accepts arguments whose
|
||||
# default values are values of some config options above. So reload
|
||||
# the module to make sure the required values are set.
|
||||
reload(sys.modules['ironic.common.swift'])
|
||||
six.moves.reload_module(sys.modules['ironic.common.swift'])
|
||||
|
||||
def test___init__(self, connection_mock):
|
||||
swift.SwiftAPI()
|
||||
|
@ -100,7 +100,7 @@ exit 1
|
||||
self.assertRaises(processutils.ProcessExecutionError,
|
||||
utils.execute,
|
||||
tmpfilename, tmpfilename2, attempts=10,
|
||||
process_input='foo',
|
||||
process_input=b'foo',
|
||||
delay_on_retry=False)
|
||||
except OSError as e:
|
||||
if e.errno == errno.EACCES:
|
||||
@ -151,7 +151,7 @@ grep foo
|
||||
try:
|
||||
utils.execute(tmpfilename,
|
||||
tmpfilename2,
|
||||
process_input='foo',
|
||||
process_input=b'foo',
|
||||
attempts=2)
|
||||
except OSError as e:
|
||||
if e.errno == errno.EACCES:
|
||||
@ -205,27 +205,27 @@ grep foo
|
||||
class GenericUtilsTestCase(base.TestCase):
|
||||
def test_hostname_unicode_sanitization(self):
|
||||
hostname = u"\u7684.test.example.com"
|
||||
self.assertEqual("test.example.com",
|
||||
self.assertEqual(b"test.example.com",
|
||||
utils.sanitize_hostname(hostname))
|
||||
|
||||
def test_hostname_sanitize_periods(self):
|
||||
hostname = "....test.example.com..."
|
||||
self.assertEqual("test.example.com",
|
||||
self.assertEqual(b"test.example.com",
|
||||
utils.sanitize_hostname(hostname))
|
||||
|
||||
def test_hostname_sanitize_dashes(self):
|
||||
hostname = "----test.example.com---"
|
||||
self.assertEqual("test.example.com",
|
||||
self.assertEqual(b"test.example.com",
|
||||
utils.sanitize_hostname(hostname))
|
||||
|
||||
def test_hostname_sanitize_characters(self):
|
||||
hostname = "(#@&$!(@*--#&91)(__=+--test-host.example!!.com-0+"
|
||||
self.assertEqual("91----test-host.example.com-0",
|
||||
self.assertEqual(b"91----test-host.example.com-0",
|
||||
utils.sanitize_hostname(hostname))
|
||||
|
||||
def test_hostname_translate(self):
|
||||
hostname = "<}\x1fh\x10e\x08l\x02l\x05o\x12!{>"
|
||||
self.assertEqual("hello", utils.sanitize_hostname(hostname))
|
||||
self.assertEqual(b"hello", utils.sanitize_hostname(hostname))
|
||||
|
||||
def test_read_cached_file(self):
|
||||
with mock.patch.object(
|
||||
@ -273,8 +273,8 @@ class GenericUtilsTestCase(base.TestCase):
|
||||
fake_context_manager.__enter__.assert_called_once_with()
|
||||
|
||||
def test_hash_file(self):
|
||||
data = 'Mary had a little lamb, its fleece as white as snow'
|
||||
flo = six.StringIO(data)
|
||||
data = b'Mary had a little lamb, its fleece as white as snow'
|
||||
flo = six.BytesIO(data)
|
||||
h1 = utils.hash_file(flo)
|
||||
h2 = hashlib.sha1(data).hexdigest()
|
||||
self.assertEqual(h1, h2)
|
||||
|
22
test-requirements-py3.txt
Normal file
22
test-requirements-py3.txt
Normal file
@ -0,0 +1,22 @@
|
||||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
hacking>=0.9.2,<0.10
|
||||
coverage>=3.6
|
||||
discover
|
||||
fixtures>=0.3.14
|
||||
mock>=1.0
|
||||
Babel>=1.3
|
||||
oslotest>=1.5.1 # Apache-2.0
|
||||
psycopg2
|
||||
PyMySQL>=0.6.2 # MIT License
|
||||
python-ironicclient>=0.2.1
|
||||
python-subunit>=0.0.18
|
||||
testrepository>=0.0.18
|
||||
testtools>=0.9.36,!=1.2.0
|
||||
|
||||
# Doc requirements
|
||||
sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
|
||||
sphinxcontrib-pecanwsme>=0.8
|
||||
oslosphinx>=2.5.0 # Apache-2.0
|
||||
|
14
tox.ini
14
tox.ini
@ -1,7 +1,7 @@
|
||||
[tox]
|
||||
minversion = 1.6
|
||||
skipsdist = True
|
||||
envlist = py27,pep8
|
||||
envlist = py27,py34,pep8
|
||||
|
||||
[testenv]
|
||||
usedevelop = True
|
||||
@ -23,6 +23,18 @@ deps = {[testenv]deps}
|
||||
pydot2
|
||||
commands = {toxinidir}/tools/states_to_dot.py -f {toxinidir}/doc/source/images/states.png
|
||||
|
||||
[testenv:py34]
|
||||
# NOTE(viktors): we must change default connection string for MySQL because
|
||||
# we use a different DB connector (PyMySQL, not MySQLdb) in py3x
|
||||
# env. So we should put new DB URLs in the env variable. This
|
||||
# will allow to run tests, that require MySQL database,
|
||||
# for example DB migration tests.
|
||||
setenv =
|
||||
{[testenv]setenv}
|
||||
OS_TEST_DBAPI_ADMIN_CONNECTION=mysql+pymysql://openstack_citest:openstack_citest@localhost/;postgresql://openstack_citest:openstack_citest@localhost/postgres;sqlite://
|
||||
deps = -r{toxinidir}/requirements.txt
|
||||
-r{toxinidir}/test-requirements-py3.txt
|
||||
|
||||
[testenv:pep8]
|
||||
commands =
|
||||
flake8 {posargs}
|
||||
|
Loading…
x
Reference in New Issue
Block a user