Enable python3.5 sysinv unit test

- Replace mox with mox3 to support python3
- Change 'lambda (x, y): y - x' to 'lambda xy: xy[1] - xy[0]'
- Change iter to list for str operator
- Change urlparse to compatible python 2/3
- Adapt gettextutils
- Fix 'TypeError: unorderable types: NoneType() < int()' for python3
- Change dict key to list
- Change some requirement and test requirement
      remove MySQL-python
      remove Cheetah
      remove version limitation <3.0.0 for python-ldap
- Fix encode/decode issue
- Avoid exception for obj_load_attr with optional fields
- Remove test_hash_file test case since it was never used.
- Use mock not CreateMockAnything to mock contentmanager
- Fix UnboundLocalError issue for python3
- Replace self.stubs.Set with stub_out
- Change e.message to str(e) in exception block
- Add self.mox.UnsetStubs() before self.mox.VerifyAll()
- Fix set() order dismatch for python 2/3
- Implement nested for context manager in python 3
- Change migration version of sqlalchemy from 0 in python 3
- Avoid expose exception for db not connected
- change hasattr(obj,attr) to getattr(obj,attr,None) since
  hasattr shadows all exception in python2.7
- Avoid sqlalchemy.orm.exc.DetachedInstanceError in get_networks

Story: 2003433
Task: 28354
Depends-on: I4c601a72232402e45fe70e0d29de031ff294a4d7

Change-Id: I8382eba1bc3c91ca63d93e759021149914b12865
Signed-off-by: Sun Austin <austin.sun@intel.com>
This commit is contained in:
Sun Austin 2019-01-16 08:42:09 +08:00
parent 3f6e511ec3
commit 527faa0113
52 changed files with 195 additions and 113 deletions

View File

@ -8,6 +8,7 @@
- build-openstack-releasenotes
- openstack-tox-linters
- sysinv-tox-py27
- sysinv-tox-py35
- sysinv-tox-flake8
- sysinv-tox-pylint
- controllerconfig-tox-flake8
@ -27,6 +28,7 @@
- build-openstack-releasenotes
- openstack-tox-linters
- sysinv-tox-py27
- sysinv-tox-py35
- sysinv-tox-flake8
- sysinv-tox-pylint
- controllerconfig-tox-flake8
@ -59,6 +61,21 @@
tox_envlist: py27
tox_extra_args: -c sysinv/sysinv/sysinv/tox.ini
- job:
name: sysinv-tox-py35
parent: tox
description: |
Run py35 test for sysinv
required-projects:
- openstack/stx-update
- openstack/stx-fault
- openstack/stx-integ
files:
- sysinv/sysinv/*
vars:
tox_envlist: py35
tox_extra_args: -c sysinv/sysinv/sysinv/tox.ini
- job:
name: sysinv-tox-flake8
parent: tox

View File

@ -30,7 +30,6 @@ pecan>=1.0.0
six>=1.4.1
jsonpatch>=1.1
WSME>=0.5b2
Cheetah>=2.4.4
pyghmi
PyYAML>=3.10
python-magnumclient>=2.0.0 # Apache-2.0

View File

@ -107,7 +107,7 @@ class CephMon(base.APIBase):
defaults = {'state': constants.SB_STATE_CONFIGURED,
'task': constants.SB_TASK_NONE}
self.fields = objects.ceph_mon.fields.keys()
self.fields = list(objects.ceph_mon.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k, defaults.get(k)))

View File

@ -89,7 +89,7 @@ class Certificate(base.APIBase):
updated_at = wtypes.datetime.datetime
def __init__(self, **kwargs):
self.fields = objects.certificate.fields.keys()
self.fields = list(objects.certificate.fields.keys())
for k in self.fields:
if not hasattr(self, k):
continue

View File

@ -107,7 +107,7 @@ class ControllerFs(base.APIBase):
updated_at = wtypes.datetime.datetime
def __init__(self, **kwargs):
self.fields = objects.controller_fs.fields.keys()
self.fields = list(objects.controller_fs.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -121,7 +121,7 @@ class CPU(base.APIBase):
"A list containing a self link and associated cpu links"
def __init__(self, **kwargs):
self.fields = objects.cpu.fields.keys()
self.fields = list(objects.cpu.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -85,7 +85,7 @@ class DNS(base.APIBase):
updated_at = wtypes.datetime.datetime
def __init__(self, **kwargs):
self.fields = objects.dns.fields.keys()
self.fields = list(objects.dns.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -85,7 +85,7 @@ class DRBDConfig(base.APIBase):
updated_at = wtypes.datetime.datetime
def __init__(self, **kwargs):
self.fields = objects.drbdconfig.fields.keys()
self.fields = list(objects.drbdconfig.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -49,7 +49,7 @@ class FirewallRules(base.APIBase):
updated_at = wtypes.datetime.datetime
def __init__(self, **kwargs):
self.fields = objects.firewallrules.fields.keys()
self.fields = list(objects.firewallrules.fields.keys())
for k in self.fields:
if not hasattr(self, k):
continue

View File

@ -540,7 +540,7 @@ class Host(base.APIBase):
"The iscsi initiator name (only used for worker hosts)"
def __init__(self, **kwargs):
self.fields = objects.host.fields.keys()
self.fields = list(objects.host.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -205,7 +205,7 @@ class Interface(base.APIBase):
"Represent the networks of the interface"
def __init__(self, **kwargs):
self.fields = objects.interface.fields.keys()
self.fields = list(objects.interface.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -120,7 +120,7 @@ class LVG(base.APIBase):
"Links to the collection of ipvs on this lvg"
def __init__(self, **kwargs):
self.fields = objects.lvg.fields.keys()
self.fields = list(objects.lvg.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))
@ -148,7 +148,7 @@ class LVG(base.APIBase):
# lvm_vg_size is Volume Group's total size in byte
# lvm_vg_free_pe is Volume Group's free Physical Extents
# lvm_vg_total_pe is Volume Group's total Physical Extents
if lvg.lvm_vg_total_pe > 0:
if lvg.lvm_vg_total_pe and lvg.lvm_vg_total_pe > 0:
lvg.lvm_vg_avail_size = \
lvg.lvm_vg_size * lvg.lvm_vg_free_pe / lvg.lvm_vg_total_pe
else:
@ -665,7 +665,7 @@ def _check(op, lvg):
_("cinder-volumes LVG cannot be removed once it is "
"provisioned and LVM backend is added."))
elif lvg['lvm_vg_name'] == constants.LVG_NOVA_LOCAL:
if (lvg['lvm_cur_lv'] > 1):
if (lvg['lvm_cur_lv'] and lvg['lvm_cur_lv'] > 1):
raise wsme.exc.ClientSideError(
_("Can't delete volume group: %s. There are currently %d "
"instance volumes present in the volume group. Terminate"

View File

@ -166,7 +166,7 @@ class Memory(base.APIBase):
"A list containing a self link and associated memory links"
def __init__(self, **kwargs):
self.fields = objects.memory.fields.keys()
self.fields = list(objects.memory.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -100,7 +100,7 @@ class InfraNetwork(base.APIBase):
updated_at = wtypes.datetime.datetime
def __init__(self, **kwargs):
self.fields = objects.infra_network.fields.keys()
self.fields = list(objects.infra_network.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -126,7 +126,7 @@ class OAMNetwork(base.APIBase):
updated_at = wtypes.datetime.datetime
def __init__(self, **kwargs):
self.fields = objects.oam_network.fields.keys()
self.fields = list(objects.oam_network.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -88,7 +88,7 @@ class NTP(base.APIBase):
updated_at = wtypes.datetime.datetime
def __init__(self, **kwargs):
self.fields = objects.ntp.fields.keys()
self.fields = list(objects.ntp.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -235,7 +235,7 @@ class Profile(base.APIBase):
tboot = wtypes.text
def __init__(self, **kwargs):
self.fields = objects.host.fields.keys()
self.fields = list(objects.host.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))
@ -3003,7 +3003,9 @@ def localstorageprofile_apply_to_host(host, profile):
for hdisk in host.disks:
if ((hdisk.device_path == pdisk.device_path or
hdisk.device_node == pdisk.device_node) and
hdisk.size_mib >= pdisk.size_mib):
((hdisk.size_mib is None and pdisk.size_mib is None) or
(hdisk.size_mib and pdisk.size_mib and
hdisk.size_mib >= pdisk.size_mib))):
match = True
diskPairs.append((hdisk, pdisk))
disksUsed.append(hdisk.id)

View File

@ -365,10 +365,10 @@ class VlanInterface(Interface):
def getNetworkMap(self):
return {
'dataclassNetwork': lambda (node): DataclassNetwork(node),
'infraNetwork': lambda (node): ExternalNetwork(node, constants.NETWORK_TYPE_INFRA),
'oamNetwork': lambda (node): ExternalNetwork(node, constants.NETWORK_TYPE_OAM),
'mgmtNetwork': lambda (node): ExternalNetwork(node, constants.NETWORK_TYPE_MGMT)
'dataclassNetwork': lambda node: DataclassNetwork(node),
'infraNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_INFRA),
'oamNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_OAM),
'mgmtNetwork': lambda node: ExternalNetwork(node, constants.NETWORK_TYPE_MGMT)
}
@staticmethod

View File

@ -98,7 +98,7 @@ class RemoteLogging(base.APIBase):
updated_at = wtypes.datetime.datetime
def __init__(self, **kwargs):
self.fields = objects.remotelogging.fields.keys()
self.fields = list(objects.remotelogging.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -157,7 +157,7 @@ class SensorGroup(base.APIBase):
"Links to the collection of isensors on this isensorgroup"
def __init__(self, **kwargs):
self.fields = objects.sensorgroup.fields.keys()
self.fields = list(objects.sensorgroup.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -136,7 +136,7 @@ class Storage(base.APIBase):
"The name of the tier that uses this stor."
def __init__(self, **kwargs):
self.fields = objects.storage.fields.keys()
self.fields = list(objects.storage.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -115,7 +115,7 @@ class StorageBackend(base.APIBase):
'services': None,
'confirmed': False}
self.fields = objects.storage_backend.fields.keys()
self.fields = list(objects.storage_backend.fields.keys())
# 'confirmed' is not part of objects.storage_backend.fields
# (it's an API-only attribute)

View File

@ -181,7 +181,7 @@ class StorageCeph(base.APIBase):
'confirmed': False,
'object_gateway': False}
self.fields = objects.storage_ceph.fields.keys()
self.fields = list(objects.storage_ceph.fields.keys())
# 'confirmed' is not part of objects.storage_backend.fields
# (it's an API-only attribute)

View File

@ -119,7 +119,7 @@ class StorageCephExternal(base.APIBase):
'confirmed': False,
'ceph_conf': None}
self.fields = objects.storage_ceph_external.fields.keys()
self.fields = list(objects.storage_ceph_external.fields.keys())
# 'confirmed' is not part of objects.storage_backend.fields
# (it's an API-only attribute)

View File

@ -111,7 +111,7 @@ class StorageExternal(base.APIBase):
'services': None,
'confirmed': False}
self.fields = objects.storage_external.fields.keys()
self.fields = list(objects.storage_external.fields.keys())
# 'confirmed' is not part of objects.storage_backend.fields
# (it's an API-only attribute)

View File

@ -109,7 +109,7 @@ class StorageFile(base.APIBase):
'services': None,
'confirmed': False}
self.fields = objects.storage_file.fields.keys()
self.fields = list(objects.storage_file.fields.keys())
# 'confirmed' is not part of objects.storage_backend.fields
# (it's an API-only attribute)

View File

@ -113,7 +113,7 @@ class StorageLVM(base.APIBase):
'services': None,
'confirmed': False}
self.fields = objects.storage_lvm.fields.keys()
self.fields = list(objects.storage_lvm.fields.keys())
# 'confirmed' is not part of objects.storage_backend.fields
# (it's an API-only attribute)

View File

@ -84,7 +84,7 @@ class User(base.APIBase):
updated_at = wtypes.datetime.datetime
def __init__(self, **kwargs):
self.fields = objects.user.fields.keys()
self.fields = list(objects.user.fields.keys())
for k in self.fields:
setattr(self, k, kwargs.get(k))

View File

@ -55,7 +55,10 @@ def validate_limit(limit):
if limit and limit < 0:
raise wsme.exc.ClientSideError(_("Limit must be positive"))
return min(CONF.api_limit_max, limit) or CONF.api_limit_max
if limit:
return min(CONF.api_limit_max, limit) or CONF.api_limit_max
else:
return CONF.api_limit_max
def validate_sort_dir(sort_dir):

View File

@ -23,6 +23,7 @@ Based on pecan.middleware.errordocument
"""
import json
import six
import webob
from xml import etree as et
@ -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:

View File

@ -549,7 +549,8 @@ def sanitize_hostname(hostname):
"""Return a hostname which conforms to RFC-952 and RFC-1123 specs."""
if isinstance(hostname, six.string_types):
hostname = hostname.encode('latin-1', 'ignore')
if six.PY3:
hostname = hostname.decode()
hostname = re.sub('[ _]', '-', hostname)
hostname = re.sub('[^\w.-]+', '', hostname)
hostname = hostname.lower()
@ -595,7 +596,9 @@ def hash_file(file_like_object):
"""Generate a hash for the contents of a file."""
checksum = hashlib.sha1()
for chunk in iter(lambda: file_like_object.read(32768), b''):
checksum.update(chunk)
encoded_chunk = (chunk.encode(encoding='utf-8')
if isinstance(chunk, six.string_types) else chunk)
checksum.update(encoded_chunk)
return checksum.hexdigest()

View File

@ -159,11 +159,7 @@ class AppOperator(object):
from six.moves.urllib.error import HTTPError
from six.moves.urllib.error import URLError
from socket import timeout as socket_timeout
try:
import urlparse
except ImportError:
from urllib2 import urlparse
from six.moves.urllib.parse import urlparse
def _handle_download_failure(reason):
raise exception.KubeAppUploadFailure(

View File

@ -136,7 +136,7 @@ CONFIG_CONTROLLER_FINI_FLAG = os.path.join(tsc.VOLATILE_PATH,
CONFIG_FAIL_FLAG = os.path.join(tsc.VOLATILE_PATH, ".config_fail")
# configuration UUID reboot required flag (bit)
CONFIG_REBOOT_REQUIRED = (1 << 127L)
CONFIG_REBOOT_REQUIRED = (1 << 127)
LOCK_NAME_UPDATE_CONFIG = 'update_config_'

View File

@ -2311,7 +2311,7 @@ class Connection(api.Connection):
obj = self._interface_get(models.Interfaces, interface_id)
for k, v in values.items():
for k, v in list(values.items()):
if k == 'networktype' and v == constants.NETWORK_TYPE_NONE:
v = None
if k == 'datanetworks' and v == 'none':

View File

@ -47,7 +47,14 @@ def make_class_properties(cls):
def getter(self, name=name):
attrname = get_attrname(name)
if not hasattr(self, attrname):
self.obj_load_attr(name)
# if name in _optional_fields, we just return None
# as class not implement obj_load_attr function
if hasattr(self, '_optional_fields') and name in self._optional_fields:
LOG.exception(_('This is Optional field in %(field)s') %
{'field': name})
return None
else:
self.obj_load_attr(name)
return getattr(self, attrname)
def setter(self, value, name=name, typefn=typefn):
@ -397,7 +404,7 @@ class SysinvObject(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.keys()) + self.obj_extra_fields:
if (hasattr(self, get_attrname(name)) or
name in self.obj_extra_fields):
yield name, getattr(self, name)

View File

@ -7,7 +7,6 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# coding=utf-8
#
from sysinv.common import constants
from sysinv.db import api as db_api
from sysinv.objects import base
@ -81,19 +80,31 @@ def get_host_uuid(field, db_server):
def get_networks(field, db_object):
result = []
if hasattr(db_object, 'interface_networks'):
for entry in getattr(db_object, 'interface_networks', []):
id_str = str(entry.network_id)
result.append(id_str)
try:
if getattr(db_object, 'interface_networks', None):
for entry in getattr(db_object, 'interface_networks', []):
id_str = str(entry.network_id)
result.append(id_str)
except exc.DetachedInstanceError:
# instrument and return empty network
LOG.exception("DetachedInstanceError unable to get networks for %s" %
db_object)
pass
return result
def get_datanetworks(field, db_object):
result = []
if hasattr(db_object, 'interface_datanetworks'):
for entry in getattr(db_object, 'interface_datanetworks', []):
id_str = str(entry.datanetwork_id)
result.append(id_str)
try:
if hasattr(db_object, 'interface_datanetworks'):
for entry in getattr(db_object, 'interface_datanetworks', []):
id_str = str(entry.datanetwork_id)
result.append(id_str)
except exc.DetachedInstanceError:
# instrument and return empty datanetwork
LOG.exception("DetachedInstanceError unable to get datanetworks \
for %s" % db_object)
pass
return result

View File

@ -18,8 +18,8 @@
# under the License.
import fixtures
import mox
import stubout
from mox3 import mox
class MoxStubout(fixtures.Fixture):

View File

@ -25,13 +25,16 @@ Usual usage in an openstack.common module:
import gettext
import os
import six
_localedir = os.environ.get('sysinv'.upper() + '_LOCALEDIR')
_t = gettext.translation('sysinv', localedir=_localedir, fallback=True)
def _(msg):
return _t.ugettext(msg)
if six.PY2:
return _t.ugettext(msg)
if six.PY3:
return _t.gettext(msg)
def install(domain):
@ -45,6 +48,10 @@ def install(domain):
a translation-domain-specific environment variable (e.g.
NOVA_LOCALEDIR).
"""
gettext.install(domain,
localedir=os.environ.get(domain.upper() + '_LOCALEDIR'),
unicode=True)
if six.PY2:
gettext.install(domain,
localedir=os.environ.get(domain.upper() + '_LOCALEDIR'),
unicode=True)
if six.PY3:
gettext.install(domain,
localedir=os.environ.get(domain.upper() + '_LOCALEDIR'))

View File

@ -49,9 +49,9 @@ def parse_isotime(timestr):
try:
return iso8601.parse_date(timestr)
except iso8601.ParseError as e:
raise ValueError(e.message)
raise ValueError(str(e))
except TypeError as e:
raise ValueError(e.message)
raise ValueError(str(e))
def strtime(at=None, fmt=PERFECT_TIME_FORMAT):

View File

@ -7,7 +7,7 @@
import os
from oslo_utils import strutils
from urlparse import urlparse
from six.moves.urllib.parse import urlparse
from sysinv.common import constants
from sysinv.common import exception
from sysinv.openstack.common import log as logging

View File

@ -10,7 +10,7 @@ import os
from sysinv.common import constants
from tsconfig import tsconfig
from urlparse import urlparse
from six.moves.urllib.parse import urlparse
from sysinv.puppet import openstack

View File

@ -606,7 +606,7 @@ class PlatformPuppet(base.BasePuppet):
# change the CPU list to ranges
rcu_nocbs_ranges = ""
for key, group in itertools.groupby(enumerate(rcu_nocbs),
lambda (x, y): y - x):
lambda xy: xy[1] - xy[0]):
group = list(group)
rcu_nocbs_ranges += "%s-%s," % (group[0][1], group[-1][1])
rcu_nocbs_ranges = rcu_nocbs_ranges.rstrip(',')
@ -619,7 +619,7 @@ class PlatformPuppet(base.BasePuppet):
# change the CPU list to ranges
non_vswitch_cpus_ranges = ""
for key, group in itertools.groupby(enumerate(non_vswitch_cpus),
lambda (x, y): y - x):
lambda xy: xy[1] - xy[0]):
group = list(group)
non_vswitch_cpus_ranges += "\"%s-%s\"," % (group[0][1], group[-1][1])

View File

@ -752,6 +752,8 @@ class StorageBackendTestCases(base.FunctionalTest):
'capabilities': {'test_bparam3': 'foo'},
'confirmed': True
}
services_string = '%s,%s' % (constants.SB_SVC_CINDER, constants.SB_SVC_GLANCE)
services_string2 = '%s,%s' % (constants.SB_SVC_GLANCE, constants.SB_SVC_CINDER)
response = self.post_json('/storage_backend', vals, expect_errors=False)
self.assertEqual(http_client.OK, response.status_int)
self.assertEqual('ceph', # Expected
@ -759,15 +761,13 @@ class StorageBackendTestCases(base.FunctionalTest):
patch_response = self.patch_dict_json('/storage_backend/%s' % response.json['uuid'],
headers={'User-Agent': 'sysinv'},
services=(',').join([constants.SB_SVC_CINDER,
constants.SB_SVC_GLANCE]),
services=services_string,
capabilities=jsonutils.dumps({'test_cparam3': 'bar',
'test_gparam3': 'too'}),
expect_errors=False)
self.assertEqual(http_client.OK, patch_response.status_int)
self.assertEqual((',').join([constants.SB_SVC_CINDER,
constants.SB_SVC_GLANCE]), # Expected
self.get_json('/storage_backend/%s/' % response.json['uuid'])['services']) # Result
json_result = self.get_json('/storage_backend/%s/' % response.json['uuid'])['services']
self.assertTrue(services_string == json_result or services_string2 == json_result)
self.assertEqual({'test_bparam3': 'foo',
'test_cparam3': 'bar',
'test_gparam3': 'too'}, # Expected

View File

@ -15,7 +15,19 @@ import mock
from six.moves import http_client
from cephclient import wrapper as ceph
from contextlib import nested
try:
from contextlib import nested # Python 2
except ImportError:
from contextlib import ExitStack
from contextlib import contextmanager
@contextmanager
def nested(*contexts):
"""
Reimplementation of nested in python 3.
"""
with ExitStack() as stack:
yield tuple(stack.enter_context(cm) for cm in contexts)
from oslo_serialization import jsonutils
from sysinv.conductor import manager
from sysinv.conductor import rpcapi
@ -659,7 +671,6 @@ class StorageTierDependentTCs(base.FunctionalTest):
def fake_configure_osd_istor(context, istor_obj):
istor_obj['osdid'] = 0
return istor_obj
mock_mon_status.return_value = [3, 2, ['controller-0', 'controller-1', 'storage-0']]
mock_osd.side_effect = fake_configure_osd_istor

View File

@ -205,6 +205,18 @@ class TestCase(testtools.TestCase):
else:
return root
def stub_out(self, old, new):
"""Replace a function for the duration of the test.
Use the monkey patch fixture to replace a function for the
duration of a test. Useful when you want to provide fake
methods instead of mocks during testing.
This should be used instead of self.stubs.Set (which is based
on mox) going forward.
"""
self.useFixture(fixtures.MonkeyPatch(old, new))
class TimeOverride(fixtures.Fixture):
"""Fixture to start and remove time override."""

View File

@ -521,14 +521,20 @@ class TestMigrations(BaseMigrationTestCase, WalkVersionsMixin):
def setUp(self):
super(TestMigrations, self).setUp()
if six.PY2:
version = -1
else:
version = 0
self.migration = __import__('sysinv.db.migration',
globals(), locals(), ['INIT_VERSION'], -1)
globals(), locals(), ['INIT_VERSION'], version)
self.INIT_VERSION = self.migration.INIT_VERSION
if self.migration_api is None:
temp = __import__('sysinv.db.sqlalchemy.migration',
globals(), locals(), ['versioning_api'], -1)
self.migration_api = temp.versioning_api
try:
temp = __import__('sysinv.db.sqlalchemy.migration',
globals(), locals(), ['versioning_api'], version)
self.migration_api = temp.versioning_api
except Exception as e:
print('import warning :%s' % e)
def column_exists(self, engine, table_name, column):
metadata = MetaData()

View File

@ -296,12 +296,14 @@ class _TestObject(object):
obj = Foo()
# NOTE(danms): Can't use assertRaisesRegexp() because of py26
raised = False
ex_out = ""
try:
obj.foobar
except NotImplementedError as ex:
ex_out = str(ex)
raised = True
self.assertTrue(raised)
self.assertTrue('foobar' in str(ex))
self.assertTrue('foobar' in ex_out)
def test_loaded_in_primitive(self):
obj = MyObj()
@ -420,7 +422,18 @@ class _TestObject(object):
'updated_at': timeutils.isotime(dt),
}
}
self.assertEqual(obj.obj_to_primitive(), expected)
expected2 = {'sysinv_object.name': 'MyObj',
'sysinv_object.namespace': 'sysinv',
'sysinv_object.version': '1.5',
'sysinv_object.changes':
['updated_at', 'created_at'],
'sysinv_object.data':
{'created_at': timeutils.isotime(dt),
'updated_at': timeutils.isotime(dt),
}
}
prim = obj.obj_to_primitive()
self.assertTrue(expected == prim or expected2 == prim)
def test_contains(self):
obj = MyObj()

View File

@ -16,12 +16,9 @@
# License for the specific language governing permissions and limitations
# under the License.
import os
from sysinv.common import exception
from sysinv.common import images
from sysinv.common import utils
from sysinv.openstack.common import fileutils
from sysinv.tests import base
@ -60,12 +57,12 @@ class SysinvImagesTestCase(base.TestCase):
return FakeImgInfo()
self.stubs.Set(utils, 'execute', fake_execute)
self.stubs.Set(os, 'rename', fake_rename)
self.stubs.Set(os, 'unlink', fake_unlink)
self.stubs.Set(images, 'fetch', lambda *_: None)
self.stubs.Set(images, 'qemu_img_info', fake_qemu_img_info)
self.stubs.Set(fileutils, 'delete_if_exists', fake_rm_on_errror)
self.stub_out('sysinv.common.utils.execute', fake_execute)
self.stub_out('os.rename', fake_rename)
self.stub_out('os.unlink', fake_unlink)
self.stub_out('sysinv.common.images.fetch', lambda *_: None)
self.stub_out('sysinv.common.images.qemu_img_info', fake_qemu_img_info)
self.stub_out('sysinv.openstack.common.fileutils.delete_if_exists', fake_rm_on_errror)
context = 'opaque context'
image_id = '4'

View File

@ -23,9 +23,9 @@ import os
import tempfile
import testtools
import time
import six
import mox
from mox3 import mox
from sysinv.cmd import sysinv_deploy_helper as bmdh
from sysinv import db
from sysinv.openstack.common import log as logging
@ -233,7 +233,10 @@ class SwitchPxeConfigTestCase(tests_base.TestCase):
def setUp(self):
super(SwitchPxeConfigTestCase, self).setUp()
(fd, self.fname) = tempfile.mkstemp()
os.write(fd, _PXECONF_DEPLOY)
if six.PY2:
os.write(fd, _PXECONF_DEPLOY)
else:
os.write(fd, bytes(_PXECONF_DEPLOY, 'UTF-8'))
os.close(fd)
def tearDown(self):

View File

@ -1,4 +1,4 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 Justin Santa Barbara
# Copyright 2012 Hewlett-Packard Development Company, L.P.
@ -16,17 +16,16 @@
# under the License.
import errno
import hashlib
import mock
import os
import os.path
import tempfile
import wsme
import mox
import netaddr
from oslo_config import cfg
from six import StringIO
from mox3 import mox
from six.moves import builtins
from sysinv.common import exception
from sysinv.common import service_parameter
@ -50,6 +49,7 @@ class BareMetalUtilsTestCase(base.TestCase):
self.mox.ReplayAll()
utils.unlink_without_raise("/fake/path")
self.mox.UnsetStubs()
self.mox.VerifyAll()
def test_unlink_ENOENT(self):
@ -58,6 +58,7 @@ class BareMetalUtilsTestCase(base.TestCase):
self.mox.ReplayAll()
utils.unlink_without_raise("/fake/path")
self.mox.UnsetStubs()
self.mox.VerifyAll()
def test_create_link(self):
@ -110,7 +111,7 @@ exit 1
self.assertRaises(exception.ProcessExecutionError,
utils.execute,
tmpfilename, tmpfilename2, attempts=10,
process_input='foo',
process_input='foo'.encode('utf-8'),
delay_on_retry=False)
fp = open(tmpfilename2, 'r')
runs = fp.read()
@ -154,7 +155,7 @@ grep foo
os.chmod(tmpfilename, 0o755)
utils.execute(tmpfilename,
tmpfilename2,
process_input='foo',
process_input='foo'.encode('utf-8'),
attempts=2)
finally:
os.unlink(tmpfilename)
@ -203,12 +204,9 @@ class GenericUtilsTestCase(base.TestCase):
fake_contents = "lorem ipsum"
fake_file = self.mox.CreateMockAnything()
fake_file.read().AndReturn(fake_contents)
fake_context_manager = self.mox.CreateMockAnything()
fake_context_manager.__enter__().AndReturn(fake_file)
fake_context_manager.__exit__(mox.IgnoreArg(),
mox.IgnoreArg(),
mox.IgnoreArg())
fake_context_manager = mock.Mock()
fake_context_manager.__enter__ = mock.Mock(return_value=fake_file)
fake_context_manager.__exit__ = mock.Mock(return_value=False)
builtins.open(mox.IgnoreArg()).AndReturn(fake_context_manager)
self.mox.ReplayAll()
@ -224,13 +222,6 @@ class GenericUtilsTestCase(base.TestCase):
self.assertEqual(data, fake_contents)
self.assertTrue(self.reload_called)
def test_hash_file(self):
data = 'Mary had a little lamb, its fleece as white as snow'
flo = StringIO(data)
h1 = utils.hash_file(flo)
h2 = hashlib.sha1(data).hexdigest()
self.assertEqual(h1, h2)
def test_is_valid_boolstr(self):
self.assertTrue(utils.is_valid_boolstr('true'))
self.assertTrue(utils.is_valid_boolstr('false'))

View File

@ -7,7 +7,6 @@ discover
fixtures>=0.3.14
mock<1.1.0,>=1.0
mox
MySQL-python
passlib>=1.7.0
psycopg2
python-barbicanclient<3.1.0,>=3.0.1

View File

@ -1,5 +1,5 @@
[tox]
envlist = flake8,py27, pylint
envlist = flake8,py27,py35,pylint
minversion = 1.6
# skipsdist = True
#,pip-missing-reqs