diff options
Diffstat (limited to 'testsuite')
-rw-r--r-- | testsuite/Testschema/test_schema.py | 11 | ||||
-rw-r--r-- | testsuite/Testsrc/test_code_checks.py | 5 | ||||
-rw-r--r-- | testsuite/Testsrc/test_doc.py | 2 | ||||
-rw-r--r-- | testsuite/common.py | 2 | ||||
-rw-r--r-- | testsuite/ext/exception_messages.py | 11 | ||||
-rw-r--r-- | testsuite/ext/pylint_compat.py | 280 | ||||
-rw-r--r-- | testsuite/ext/ssl_protocols.py | 14 | ||||
-rwxr-xr-x | testsuite/install.sh | 80 | ||||
-rwxr-xr-x | testsuite/prepare-python.sh | 8 | ||||
-rw-r--r-- | testsuite/pylintrc.conf | 2 | ||||
-rw-r--r-- | testsuite/requirements-26.txt | 9 | ||||
-rw-r--r-- | testsuite/requirements-legacy.txt | 14 | ||||
-rw-r--r-- | testsuite/requirements.txt | 9 | ||||
-rwxr-xr-x | testsuite/test.sh | 9 |
14 files changed, 421 insertions, 35 deletions
diff --git a/testsuite/Testschema/test_schema.py b/testsuite/Testschema/test_schema.py index cd9b74cdf..138468a91 100644 --- a/testsuite/Testschema/test_schema.py +++ b/testsuite/Testschema/test_schema.py @@ -34,13 +34,18 @@ NSMAP = dict(xs=XS) class TestSchemas(Bcfg2TestCase): schema_url = "http://www.w3.org/2001/XMLSchema.xsd" + catalog_file = os.path.expanduser("~/.cache/xml/catalog.xml") @skipUnless(HAS_XMLLINT, "xmllint not installed") def test_valid(self): + env = os.environ.copy() + if os.path.exists(self.catalog_file): + print('Using cached schema files.') + env["SGML_CATALOG_FILES"] = self.catalog_file schemas = [s for s in glob.glob(os.path.join(srcpath, '*.xsd'))] - xmllint = Popen(['xmllint', '--xinclude', '--noout', '--schema', - self.schema_url] + schemas, - stdout=PIPE, stderr=STDOUT) + xmllint = Popen(['xmllint', '--xinclude', '--noout', '--catalogs', + '--schema', self.schema_url] + schemas, + stdout=PIPE, stderr=STDOUT, env=env) print(xmllint.communicate()[0].decode()) self.assertEqual(xmllint.wait(), 0) diff --git a/testsuite/Testsrc/test_code_checks.py b/testsuite/Testsrc/test_code_checks.py index c26d8c139..44c4633a7 100644 --- a/testsuite/Testsrc/test_code_checks.py +++ b/testsuite/Testsrc/test_code_checks.py @@ -79,9 +79,10 @@ no_checks = { "lib/Bcfg2/Server/migrations": ["*.py"], "lib/Bcfg2/Server/south_migrations": ["*.py"], } + if sys.version_info < (2, 6): - # multiprocessing core requires py2.6 - no_checks['lib/Bcfg2/Server'] = ['MultiprocessingCore.py'] + # Server requires python 2.6 + no_checks['lib/Bcfg2'] = ['Server'] try: any diff --git a/testsuite/Testsrc/test_doc.py b/testsuite/Testsrc/test_doc.py index 93c8d1bb4..d105254c5 100644 --- a/testsuite/Testsrc/test_doc.py +++ b/testsuite/Testsrc/test_doc.py @@ -20,7 +20,7 @@ except ImportError: HAS_SPHINX = False -TEST_SPHINX = bool(os.environ.get('TEST_SPHINX', 'yes') != 'no') +TEST_SPHINX = bool(os.environ.get('TEST_SPHINX', 'no') != 'no') class DocTest(Bcfg2TestCase): diff --git a/testsuite/common.py b/testsuite/common.py index 944471ade..e0ff3ed19 100644 --- a/testsuite/common.py +++ b/testsuite/common.py @@ -167,7 +167,7 @@ class Bcfg2TestCase(TestCase): sys.stderr = cls._stderr if hasattr(TestCase, "assertCountEqual"): - assertItemsEqual = assertCountEqual + assertItemsEqual = TestCase.assertCountEqual def assertXMLEqual(self, el1, el2, msg=None): """ Test that the two XML trees given are equal. """ diff --git a/testsuite/ext/exception_messages.py b/testsuite/ext/exception_messages.py index cd3d7112c..5c59916df 100644 --- a/testsuite/ext/exception_messages.py +++ b/testsuite/ext/exception_messages.py @@ -35,10 +35,15 @@ class ExceptionMessageChecker(BaseChecker): priority = -1 def visit_raise(self, node): - if node.exc is None: + exc = None + try: + exc = node.exc + except AttributeError: + exc = node.type + if exc is None: return - if isinstance(node.exc, ast.Name): - raised = safe_infer(node.exc) + if isinstance(exc, ast.Name): + raised = safe_infer(exc) if (isinstance(raised, ast.Class) and raised.name not in self.config.exceptions_without_args): self.add_message('R9901', node=node.exc) diff --git a/testsuite/ext/pylint_compat.py b/testsuite/ext/pylint_compat.py new file mode 100644 index 000000000..5300df8e6 --- /dev/null +++ b/testsuite/ext/pylint_compat.py @@ -0,0 +1,280 @@ +from pylint.__pkginfo__ import version as pylint_version + +try: + from logilab.astng.__pkginfo__ import version as astng_version +except ImportError: + from astroid.__pkginfo__ import version as astng_version + + +def register(linter): + if pylint_version < '0.24.0': + import pylint.utils + orig_check_message_id = pylint.utils.MessagesHandlerMixIn.check_message_id + def check_message_id(self, msgid): + # translate the new message ids back into the old ones + replacements = {'12': '65', '13': '99'} + new = msgid[1:3] + if new in replacements: + msgid = msgid[0] + replacements[new] + msgid[3:] + return orig_check_message_id(self, msgid) + pylint.utils.MessagesHandlerMixIn.check_message_id = check_message_id + + def ignore(meth, msgid, *args, **kwargs): + # ignore non-existent message ids in disable/enable comments + ignore = ['W1401', 'R0924'] + if msgid in ignore: + return + return meth(msgid, *args, **kwargs) + linter._options_methods['disable'] = lambda *args, **kwargs: ignore(linter.disable, *args, **kwargs) + linter._options_methods['enable'] = lambda *args, **kwargs: ignore(linter.enable, *args, **kwargs) + + if pylint_version < '0.22.0': + import pylint.checkers.exceptions + orig_visit_raise = pylint.checkers.exceptions.ExceptionsChecker.visit_raise + def visit_raise(self, node): + if not hasattr(node, 'type') and hasattr(node, 'exc'): + node.type = node.exc + return orig_visit_raise(self, node) + pylint.checkers.exceptions.ExceptionsChecker.visit_raise = visit_raise + + if astng_version < '0.23': + import logilab.astng.scoped_nodes + from logilab.astng.bases import InferenceContext, InferenceError + + # backport import bug fix (e642ba33ba1bdde04ac9f0c75a25dc40131c55e7) + def ancestors(self, recurs=True, context=None): + yielded = set([self]) + if context is None: + context = InferenceContext() + for stmt in self.bases: + path = set(context.path) + try: + for baseobj in stmt.infer(context): + if not isinstance(baseobj, logilab.astng.scoped_nodes.Class): + # duh ? + continue + if baseobj in yielded: + continue # cf xxx above + yielded.add(baseobj) + yield baseobj + if recurs: + for grandpa in baseobj.ancestors(True, context): + if grandpa in yielded: + continue # cf xxx above + yielded.add(grandpa) + yield grandpa + except InferenceError: + # XXX log error ? + pass + context.path = path + logilab.astng.scoped_nodes.Class.ancestors = ancestors + + # support for classpropery (d110bcf2de4b8bc48e41638cf430f17c5714ffbc) + try: + from logilab.astng.rebuilder import TreeRebuilder + except: + try: + from logilab.astng._nodes_ast import TreeRebuilder + except: + from logilab.astng._nodes_compiler import TreeRebuilder + from logilab.astng import nodes + + orig_visit_function = TreeRebuilder.visit_function + def visit_function(self, node, parent): + newnode = orig_visit_function(self, node, parent) + if newnode.decorators is not None: + for decorator_expr in newnode.decorators.nodes: + if isinstance(decorator_expr, nodes.Name): + if decorator_expr.name == 'classproperty': + newnode.type = 'classmethod' + return newnode + TreeRebuilder.visit_function = visit_function + + if astng_version < '0.22': + from logilab.astng import nodes + from logilab.astng.bases import _infer_stmts, copy_context, path_wrapper, \ + InferenceError, NotFoundError + from logilab.astng._exceptions import ASTNGBuildingException + import logilab.astng.scoped_nodes + from logilab.astng.node_classes import List, DelName + + # backport of 11886551cfdcf969f0a661f8ab63c1fa1a6dd399 with + # a bit revert of af896e299ce5e381a928a77a9c28941cad90a243 + def infer_from(self, context=None, asname=True): + name = context.lookupname + if name is None: + raise InferenceError() + if asname: + name = self.real_name(name) + module = self.do_import_module(self.modname) + try: + context = copy_context(context) + context.lookupname = name + return _infer_stmts(module.getattr(name, ignore_locals=module is self.root()), context) + except NotFoundError: + raise InferenceError(name) + nodes.From.infer = path_wrapper(infer_from) + + def getattr(self, name, context=None, ignore_locals=False): + if name in self.special_attributes: + if name == '__file__': + return [cf(self.file)] + self.locals.get(name, []) + if name == '__path__' and self.package: + return [List()] + self.locals.get(name, []) + return std_special_attributes(self, name) + if not ignore_locals and name in self.locals: + return self.locals[name] + if self.package: + try: + return [self.import_module(name, relative_only=True)] + except (KeyboardInterrupt, SystemExit): + raise + except: + pass + raise NotFoundError(name) + logilab.astng.scoped_nodes.Module.getattr = logilab.astng.scoped_nodes.remove_nodes(getattr, DelName) + + if astng_version < '0.21.1': + # backport of 3d463da455e33e7ddc53a295b6a33db7b9e4288b + from logilab.astng.scoped_nodes import Function + from logilab.astng.rebuilder import RebuildVisitor + from logilab.astng.bases import YES, Instance + + orig_init = Function.__init__ + def init(self, name, doc): + orig_init(self, name, doc) + self.instance_attrs = {} + Function.__init__ = init + + orig_getattr = Function.getattr + def getattr(self, name, context=None): + if name != '__module__' and name in self.instance_attrs: + return self.instance_attrs[name] + return orig_getattr(self, name, context) + Function.getattr = getattr + + def delayed_assattr(self, node): + """visit a AssAttr node -> add name to locals, handle members + definition + """ + try: + frame = node.frame() + for infered in node.expr.infer(): + if infered is YES: + continue + try: + if infered.__class__ is Instance: + infered = infered._proxied + iattrs = infered.instance_attrs + elif isinstance(infered, Instance): + # Const, Tuple, ... we may be wrong, may be not, but + # anyway we don't want to pollute builtin's namespace + continue + elif infered.is_function: + iattrs = infered.instance_attrs + else: + iattrs = infered.locals + except AttributeError: + # XXX log error + #import traceback + #traceback.print_exc() + continue + values = iattrs.setdefault(node.attrname, []) + if node in values: + continue + # get assign in __init__ first XXX useful ? + if frame.name == '__init__' and values and not \ + values[0].frame().name == '__init__': + values.insert(0, node) + else: + values.append(node) + except InferenceError: + pass + RebuildVisitor.delayed_assattr = delayed_assattr + + if astng_version < '0.20.4': + try: + from logilab.astng._nodes_ast import TreeRebuilder, _lineno_parent + except: + from logilab.astng._nodes_compiler import TreeRebuilder + _lineno_parent = (lambda *args: TreeRebuilder._set_infos(None, *args)) + from logilab.astng import nodes + from logilab.astng.bases import NodeNG, Instance + from logilab.astng.mixins import ParentAssignTypeMixin + + class Set(NodeNG, Instance, ParentAssignTypeMixin): + _astng_fields = ('elts',) + elts = None + + def pytype(self): + return '__builtin__.set' + + def itered(self): + return self.elts + + def visit_set(self, node, parent): + newnode = Set() + _lineno_parent(node, newnode, parent) + newnode.elts = [self.visit(child, newnode) for child in node.elts] + newnode.set_line_info(newnode.last_child()) + return newnode + TreeRebuilder.visit_set = visit_set + + def visit_setcomp(self, node, parent): + newnode = nodes.SetComp() + _lineno_parent(node, newnode, parent) + newnode.elt = self.visit(node.elt, newnode) + newnode.generators = [self.visit(child, newnode) + for child in node.generators] + newnode.set_line_info(newnode.last_child()) + return newnode + TreeRebuilder.visit_setcomp = visit_setcomp + + class DictComp(NodeNG): + _astng_fields = ('key', 'value', 'generators') + key = None + value = None + generators = None + + def visit_dictcomp(self, node, parent): + newnode = DictComp() + _lineno_parent(node, newnode, parent) + newnode.key = self.visit(node.key, newnode) + newnode.value = self.visit(node.value, newnode) + newnode.generators = [self.visit(child, newnode) + for child in node.generators] + newnode.set_line_info(newnode.last_child()) + return newnode + TreeRebuilder.visit_dictcomp = visit_dictcomp + + # backport of bfe9e5c53cfb75c3b45ebb5cb8e8902464782c7d + from logilab.astng.node_classes import From + orig_from_init = From.__init__ + def from_init(self, fromname, names, level=0): + orig_from_init(self, fromname or '', names, level) + From.__init__ = from_init + + # partial backport of 6d59ad07d722d01e458aaf8fd14fd7dfc7ebaa6e + from logilab.astng.scoped_nodes import Module + orig_absolute_modname = Module.absolute_modname + def absolute_modname(self, modname, level): + result = orig_absolute_modname(self, modname, level) + if result[-1] == '.': + return result[:-1] + return result + Module.absolute_modname = absolute_modname + + # python2.4 compatibility (no super on old-style classes) + from logilab.astng.bases import Proxy, UnboundMethod + + def unbound_igetattr(self, name, context=None): + if name == 'im_func': + return iter((self._proxied,)) + return Proxy.igetattr(self, name, context) + UnboundMethod.igetattr = unbound_igetattr + + def unbound_getattr(self, name, context=None): + if name == 'im_func': + return [self._proxied] + return Proxy.getattr(self, name, context) + UnboundMethod.getattr = unbound_getattr diff --git a/testsuite/ext/ssl_protocols.py b/testsuite/ext/ssl_protocols.py index 66068d2a9..f92e3e355 100644 --- a/testsuite/ext/ssl_protocols.py +++ b/testsuite/ext/ssl_protocols.py @@ -1,5 +1,5 @@ try: - from logilab.astng import MANAGER, scoped_nodes, node_classes + from logilab.astng import MANAGER, builder, scoped_nodes, node_classes PYLINT=0 except ImportError: from astroid import MANAGER, scoped_nodes, node_classes @@ -8,10 +8,18 @@ except ImportError: def ssl_transform(module): if module.name == 'ssl': for proto in ('SSLv23', 'TLSv1'): - module.locals['PROTOCOL_%s' % proto] = [node_classes.Const()] + module.locals['PROTOCOL_%s' % proto] = [node_classes.Const(0)] def register(linter): if PYLINT == 0: - MANAGER.register_transformer(ssl_transform) + if hasattr(MANAGER, 'register_transformer'): + MANAGER.register_transformer(ssl_transform) + else: + safe = builder.ASTNGBuilder.string_build + def _string_build(self, data, modname='', path=None): + if modname == 'ssl': + data += '\n\nPROTOCOL_SSLv23 = 0\nPROTOCOL_TLSv1 = 0' + return safe(self, data, modname, path) + builder.ASTNGBuilder.string_build = _string_build else: MANAGER.register_transform(scoped_nodes.Module, ssl_transform) diff --git a/testsuite/install.sh b/testsuite/install.sh index 4d8778ad7..af07de0a9 100755 --- a/testsuite/install.sh +++ b/testsuite/install.sh @@ -1,31 +1,77 @@ #!/bin/bash -ex # install script for Travis-CI +PYVER=$(python -c 'import sys;print(".".join(str(v) for v in sys.version_info[0:2]))') +SITE_PACKAGES=$(python -c 'from distutils.sysconfig import get_python_lib; print(get_python_lib())') -sudo apt-get update -qq -sudo apt-get install swig libxml2-utils - -pip install -r testsuite/requirements.txt +if [[ ${PYVER:0:1} == "2" && $PYVER != "2.7" && $PYVER != "2.6" ]]; then + pip install -r testsuite/requirements-legacy.txt +else + pip install --upgrade pip -PYVER=$(python -c 'import sys;print(".".join(str(v) for v in sys.version_info[0:2]))') + pip_wheel() { + pip wheel --find-links="$HOME/.cache/wheels/" --wheel-dir="$HOME/.cache/wheels/" "$@" + pip install --no-index --find-links="$HOME/.cache/wheels/" "$@" + } -if [[ ${PYVER:0:1} == "2" && $PYVER != "2.7" ]]; then - pip install unittest2 -fi + if [[ $PYVER == "2.6" ]]; then + pip_wheel -r testsuite/requirements-26.txt + pip_wheel unittest2 + else + pip_wheel -r testsuite/requirements.txt -if [[ "$WITH_OPTIONAL_DEPS" == "yes" ]]; then - sudo apt-get install -y yum libaugeas0 augeas-lenses libacl1-dev libssl-dev \ - python-gamin python-selinux + if [[ ${PYVER:0:1} == "3" ]]; then + # TODO: Move to "requirements.txt" if all the new errors are fixed. + pip_wheel 'pylint>1.4' + fi + fi - pip install PyYAML pyinotify boto pylibacl Jinja2 mercurial guppy cherrypy python-augeas + if [[ "$WITH_OPTIONAL_DEPS" == "yes" ]]; then + pip_wheel PyYAML pyinotify boto pylibacl Jinja2 \ + cherrypy python-augeas nose-show-skipped - if [[ ${PYVER:0:1} == "2" ]]; then - pip install cheetah m2crypto + if [[ $PYVER == "2.6" ]]; then + pip install \ + --global-option='build_ext' \ + --global-option='--include-dirs=/usr/include/x86_64-linux-gnu' \ + m2crypto - if [[ $PYVER != "2.7" ]]; then - pip install 'django<1.7' 'South<0.8' + pip_wheel 'django<1.7' 'South<0.8' 'mercurial<4.3' cheetah guppy else - pip install django + if [[ $PYVER == "2.7" ]]; then + pip_wheel m2crypto guppy + fi + + pip_wheel django mercurial cheetah3 fi fi fi + +# Use system site-packages and pymodules +if [[ "$WITH_SYSTEM_SITE_PACKAGES" == "yes" ]]; then + cat <<EOF > "$SITE_PACKAGES/system-packages.pth" +/usr/lib/python$PYVER/site-packages/ +/usr/lib/python$PYVER/dist-packages/ +/usr/lib/pymodules/python$PYVER/ +EOF +fi + +# Setup the local xml schema cache +download_schema() { + if [[ ! -e "$1" ]]; then + wget -O "$1" "$2" + fi +} + +mkdir -p "$HOME/.cache/xml/" +download_schema "$HOME/.cache/xml/XMLSchema.xsd" "http://www.w3.org/2001/XMLSchema.xsd" +download_schema "$HOME/.cache/xml/xml.xsd" "http://www.w3.org/2001/xml.xsd" + +cat > "$HOME/.cache/xml/catalog.xml" <<EOF +<?xml version="1.0"?> +<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog"> + <system systemId="http://www.w3.org/2001/XMLSchema.xsd" uri="$HOME/.cache/xml/XMLSchema.xsd" /> + <system systemId="http://www.w3.org/2001/xml.xsd" uri="$HOME/.cache/xml/xml.xsd" /> + <nextCatalog catalog="/etc/xml/catalog.xml" /> +</catalog> +EOF diff --git a/testsuite/prepare-python.sh b/testsuite/prepare-python.sh new file mode 100755 index 000000000..7b72a6dc4 --- /dev/null +++ b/testsuite/prepare-python.sh @@ -0,0 +1,8 @@ +#!/bin/sh + +if [ -n "$PYTHON" ]; then + echo "Try to use custom python version: $PYTHON" + pip install 'virtualenv<1.8' + mkdir -p "$HOME/custom-virtualenv" + virtualenv -p "python$PYTHON" --use-distribute "$HOME/custom-virtualenv" +fi diff --git a/testsuite/pylintrc.conf b/testsuite/pylintrc.conf index 50ece77db..ce7e407df 100644 --- a/testsuite/pylintrc.conf +++ b/testsuite/pylintrc.conf @@ -19,7 +19,7 @@ persistent=no # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. -load-plugins=ext.exception_messages,ext.ssl_protocols +load-plugins=ext.exception_messages,ext.ssl_protocols,ext.pylint_compat [MESSAGES CONTROL] diff --git a/testsuite/requirements-26.txt b/testsuite/requirements-26.txt new file mode 100644 index 000000000..f85dc6de4 --- /dev/null +++ b/testsuite/requirements-26.txt @@ -0,0 +1,9 @@ +lxml +python-daemon<2.0.0 +argparse +genshi + +nose +mock +pylint<0.29 +pep8 diff --git a/testsuite/requirements-legacy.txt b/testsuite/requirements-legacy.txt new file mode 100644 index 000000000..7d918cb45 --- /dev/null +++ b/testsuite/requirements-legacy.txt @@ -0,0 +1,14 @@ +lxml<3.4 +lockfile<0.9 +python-daemon<1.4 +argparse +ssl + +nose +nose-exclude<0.2 +mock<1.1 +unittest2<0.6 +logilab-common==0.53.0 +logilab-astng==0.20.3 +pylint<0.22 +pep8<1.3 diff --git a/testsuite/requirements.txt b/testsuite/requirements.txt index 0d8c297aa..665ed961d 100644 --- a/testsuite/requirements.txt +++ b/testsuite/requirements.txt @@ -1,9 +1,10 @@ lxml +python-daemon +genshi +argparse + nose mock -sphinx<1.5 pylint<0.29 pep8 -python-daemon<2.0.0 -genshi -argparse +sphinx diff --git a/testsuite/test.sh b/testsuite/test.sh new file mode 100755 index 000000000..739c3c2b0 --- /dev/null +++ b/testsuite/test.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +NOSE_OPTS="" + +if [ "$WITH_OPTIONAL_DEPS" = "yes" ]; then + NOSE_OPTS="--show-skipped" +fi + +exec nosetests $NOSE_OPTS testsuite |