commit:     dfea6f5290fd1d3273a9a7181a38f18b3b1d855f
Author:     Brian Dolbec <dolsen <AT> gentoo <DOT> org>
AuthorDate: Sat May 14 18:00:33 2016 +0000
Commit:     Brian Dolbec <dolsen <AT> gentoo <DOT> org>
CommitDate: Sat May 14 18:02:17 2016 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=dfea6f52

repoman: Copy portage runtests file, edit & make them operational

Make copies of files as needed.
Edit the files for the appropriate namespaces.
Add in the parent portage python directory for it to import from.

 repoman/pym/repoman/tests/__init__.py           | 353 +++++++++++++++++++++++-
 repoman/pym/repoman/tests/runTests.py           |   9 +-
 repoman/pym/repoman/tests/simple/__test__.py    |   1 +
 repoman/pym/repoman/tests/simple/test_simple.py |   2 +-
 repoman/runtests                                | 180 ++++++++++++
 5 files changed, 541 insertions(+), 4 deletions(-)

diff --git a/repoman/pym/repoman/tests/__init__.py 
b/repoman/pym/repoman/tests/__init__.py
index 532918b..7243e7a 100644
--- a/repoman/pym/repoman/tests/__init__.py
+++ b/repoman/pym/repoman/tests/__init__.py
@@ -1,2 +1,353 @@
-# Copyright 2011 Gentoo Foundation
+# tests/__init__.py -- Portage Unit Test functionality
+# Copyright 2006-2013 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
+
+from __future__ import print_function
+
+import argparse
+import sys
+import time
+import unittest
+
+try:
+       from unittest.runner import _TextTestResult # new in python-2.7
+except ImportError:
+       from unittest import _TextTestResult
+
+try:
+       # They added the skip framework to python-2.7.
+       # Drop this once we drop python-2.6 support.
+       unittest_skip_shims = False
+       import unittest.SkipTest as SkipTest # new in python-2.7
+except ImportError:
+       unittest_skip_shims = True
+
+import portage
+from portage import os
+from portage import _encodings
+from portage import _unicode_decode
+from portage.const import (EPREFIX, GLOBAL_CONFIG_PATH, PORTAGE_BASE_PATH,
+       PORTAGE_BIN_PATH)
+
+
+if portage._not_installed:
+       cnf_path = os.path.join(PORTAGE_BASE_PATH, 'cnf')
+       cnf_etc_path = cnf_path
+       cnf_bindir = os.path.join(PORTAGE_BASE_PATH, 'repoman/bin')
+       cnf_sbindir = cnf_bindir
+else:
+       cnf_path = os.path.join(EPREFIX or '/', GLOBAL_CONFIG_PATH)
+       cnf_etc_path = os.path.join(EPREFIX or '/', 'etc')
+       cnf_eprefix = EPREFIX
+       cnf_bindir = os.path.join(EPREFIX or '/', 'usr', 'bin')
+       cnf_sbindir = os.path.join(EPREFIX or '/', 'usr', 'sbin')
+
+
+def main():
+       suite = unittest.TestSuite()
+       basedir = os.path.dirname(os.path.realpath(__file__))
+
+       usage = "usage: %s [options] [tests to run]" % 
os.path.basename(sys.argv[0])
+       parser = argparse.ArgumentParser(usage=usage)
+       parser.add_argument("-l", "--list", help="list all tests",
+               action="store_true", dest="list_tests")
+       options, args = parser.parse_known_args(args=sys.argv)
+
+       if (os.environ.get('NOCOLOR') in ('yes', 'true') or
+               os.environ.get('TERM') == 'dumb' or
+               not sys.stdout.isatty()):
+               portage.output.nocolor()
+
+       if options.list_tests:
+               testdir = os.path.dirname(sys.argv[0])
+               for mydir in getTestDirs(basedir):
+                       testsubdir = os.path.basename(mydir)
+                       for name in getTestNames(mydir):
+                               print("%s/%s/%s.py" % (testdir, testsubdir, 
name))
+               return os.EX_OK
+
+       if len(args) > 1:
+               suite.addTests(getTestFromCommandLine(args[1:], basedir))
+       else:
+               for mydir in getTestDirs(basedir):
+                       suite.addTests(getTests(os.path.join(basedir, mydir), 
basedir))
+
+       result = TextTestRunner(verbosity=2).run(suite)
+       if not result.wasSuccessful():
+               return 1
+       return os.EX_OK
+
+def my_import(name):
+       mod = __import__(name)
+       components = name.split('.')
+       for comp in components[1:]:
+               mod = getattr(mod, comp)
+       return mod
+
+def getTestFromCommandLine(args, base_path):
+       result = []
+       for arg in args:
+               realpath = os.path.realpath(arg)
+               path = os.path.dirname(realpath)
+               f = realpath[len(path)+1:]
+
+               if not f.startswith("test") or not f.endswith(".py"):
+                       raise Exception("Invalid argument: '%s'" % arg)
+
+               mymodule = f[:-3]
+               result.extend(getTestsFromFiles(path, base_path, [mymodule]))
+       return result
+
+def getTestDirs(base_path):
+       TEST_FILE = b'__test__.py'
+       testDirs = []
+
+       # the os.walk help mentions relative paths as being quirky
+       # I was tired of adding dirs to the list, so now we add __test__.py
+       # to each dir we want tested.
+       for root, dirs, files in os.walk(base_path):
+               try:
+                       root = _unicode_decode(root,
+                               encoding=_encodings['fs'], errors='strict')
+               except UnicodeDecodeError:
+                       continue
+
+               if TEST_FILE in files:
+                       testDirs.append(root)
+
+       testDirs.sort()
+       return testDirs
+
+def getTestNames(path):
+       files = os.listdir(path)
+       files = [f[:-3] for f in files if f.startswith("test") and 
f.endswith(".py")]
+       files.sort()
+       return files
+
+def getTestsFromFiles(path, base_path, files):
+       parent_path = path[len(base_path)+1:]
+       parent_module = ".".join(("repoman", "tests", parent_path))
+       parent_module = parent_module.replace('/', '.')
+       result = []
+       for mymodule in files:
+               # Make the trailing / a . for module importing
+               modname = ".".join((parent_module, mymodule))
+               mod = my_import(modname)
+               result.append(unittest.TestLoader().loadTestsFromModule(mod))
+       return result
+
+def getTests(path, base_path):
+       """
+
+       path is the path to a given subdir ( 'portage/' for example)
+       This does a simple filter on files in that dir to give us modules
+       to import
+
+       """
+       return getTestsFromFiles(path, base_path, getTestNames(path))
+
+class TextTestResult(_TextTestResult):
+       """
+       We need a subclass of unittest._TextTestResult to handle tests with TODO
+
+       This just adds an addTodo method that can be used to add tests
+       that are marked TODO; these can be displayed later
+       by the test runner.
+       """
+
+       def __init__(self, stream, descriptions, verbosity):
+               super(TextTestResult, self).__init__(stream, descriptions, 
verbosity)
+               self.todoed = []
+               self.portage_skipped = []
+
+       def addTodo(self, test, info):
+               self.todoed.append((test, info))
+               if self.showAll:
+                       self.stream.writeln("TODO")
+               elif self.dots:
+                       self.stream.write(".")
+
+       def addPortageSkip(self, test, info):
+               self.portage_skipped.append((test, info))
+               if self.showAll:
+                       self.stream.writeln("SKIP")
+               elif self.dots:
+                       self.stream.write(".")
+
+       def printErrors(self):
+               if self.dots or self.showAll:
+                       self.stream.writeln()
+                       self.printErrorList('ERROR', self.errors)
+                       self.printErrorList('FAIL', self.failures)
+                       self.printErrorList('TODO', self.todoed)
+                       self.printErrorList('SKIP', self.portage_skipped)
+
+class TestCase(unittest.TestCase):
+       """
+       We need a way to mark a unit test as "ok to fail"
+       This way someone can add a broken test and mark it as failed
+       and then fix the code later.  This may not be a great approach
+       (broken code!!??!11oneone) but it does happen at times.
+       """
+
+       def __init__(self, *pargs, **kwargs):
+               unittest.TestCase.__init__(self, *pargs, **kwargs)
+               self.todo = False
+               self.portage_skip = None
+               self.cnf_path = cnf_path
+               self.cnf_etc_path = cnf_etc_path
+               self.bindir = cnf_bindir
+               self.sbindir = cnf_sbindir
+
+       def defaultTestResult(self):
+               return TextTestResult()
+
+       def run(self, result=None):
+               if result is None: result = self.defaultTestResult()
+               result.startTest(self)
+               testMethod = getattr(self, self._testMethodName)
+               try:
+                       try:
+                               self.setUp()
+                       except SystemExit:
+                               raise
+                       except KeyboardInterrupt:
+                               raise
+                       except:
+                               result.addError(self, sys.exc_info())
+                               return
+
+                       ok = False
+                       try:
+                               testMethod()
+                               ok = True
+                       except SkipTest as e:
+                               result.addPortageSkip(self, "%s: SKIP: %s" %
+                                       (testMethod, str(e)))
+                       except self.failureException:
+                               if self.portage_skip is not None:
+                                       if self.portage_skip is True:
+                                               result.addPortageSkip(self, 
"%s: SKIP" % testMethod)
+                                       else:
+                                               result.addPortageSkip(self, 
"%s: SKIP: %s" %
+                                                       (testMethod, 
self.portage_skip))
+                               elif self.todo:
+                                       result.addTodo(self, "%s: TODO" % 
testMethod)
+                               else:
+                                       result.addFailure(self, sys.exc_info())
+                       except (KeyboardInterrupt, SystemExit):
+                               raise
+                       except:
+                               result.addError(self, sys.exc_info())
+
+                       try:
+                               self.tearDown()
+                       except SystemExit:
+                               raise
+                       except KeyboardInterrupt:
+                               raise
+                       except:
+                               result.addError(self, sys.exc_info())
+                               ok = False
+                       if ok:
+                               result.addSuccess(self)
+               finally:
+                       result.stopTest(self)
+
+       def assertRaisesMsg(self, msg, excClass, callableObj, *args, **kwargs):
+               """Fail unless an exception of class excClass is thrown
+                  by callableObj when invoked with arguments args and keyword
+                  arguments kwargs. If a different type of exception is
+                  thrown, it will not be caught, and the test case will be
+                  deemed to have suffered an error, exactly as for an
+                  unexpected exception.
+               """
+               try:
+                       callableObj(*args, **kwargs)
+               except excClass:
+                       return
+               else:
+                       if hasattr(excClass, '__name__'): excName = 
excClass.__name__
+                       else: excName = str(excClass)
+                       raise self.failureException("%s not raised: %s" % 
(excName, msg))
+
+       def assertExists(self, path):
+               """Make sure |path| exists"""
+               if not os.path.exists(path):
+                       msg = ['path is missing: %s' % (path,)]
+                       while path != '/':
+                               path = os.path.dirname(path)
+                               if not path:
+                                       # If we're given something like "foo", 
abort once we get to "".
+                                       break
+                               result = os.path.exists(path)
+                               msg.append('\tos.path.exists(%s): %s' % (path, 
result))
+                               if result:
+                                       msg.append('\tcontents: %r' % 
os.listdir(path))
+                                       break
+                       raise self.failureException('\n'.join(msg))
+
+       def assertNotExists(self, path):
+               """Make sure |path| does not exist"""
+               if os.path.exists(path):
+                       raise self.failureException('path exists when it should 
not: %s' % path)
+
+if unittest_skip_shims:
+       # Shim code for <python-2.7.
+       class SkipTest(Exception):
+               """unittest.SkipTest shim for <python-2.7"""
+
+       def skipTest(self, reason):
+               raise SkipTest(reason)
+       setattr(TestCase, 'skipTest', skipTest)
+
+       def assertIn(self, member, container, msg=None):
+               self.assertTrue(member in container, msg=msg)
+       setattr(TestCase, 'assertIn', assertIn)
+
+       def assertNotIn(self, member, container, msg=None):
+               self.assertFalse(member in container, msg=msg)
+       setattr(TestCase, 'assertNotIn', assertNotIn)
+
+class TextTestRunner(unittest.TextTestRunner):
+       """
+       We subclass unittest.TextTestRunner to output SKIP for tests that fail 
but are skippable
+       """
+
+       def _makeResult(self):
+               return TextTestResult(self.stream, self.descriptions, 
self.verbosity)
+
+       def run(self, test):
+               """
+               Run the given test case or test suite.
+               """
+               result = self._makeResult()
+               startTime = time.time()
+               test(result)
+               stopTime = time.time()
+               timeTaken = stopTime - startTime
+               result.printErrors()
+               self.stream.writeln(result.separator2)
+               run = result.testsRun
+               self.stream.writeln("Ran %d test%s in %.3fs" %
+                                                       (run, run != 1 and "s" 
or "", timeTaken))
+               self.stream.writeln()
+               if not result.wasSuccessful():
+                       self.stream.write("FAILED (")
+                       failed = len(result.failures)
+                       errored = len(result.errors)
+                       if failed:
+                               self.stream.write("failures=%d" % failed)
+                       if errored:
+                               if failed: self.stream.write(", ")
+                               self.stream.write("errors=%d" % errored)
+                       self.stream.writeln(")")
+               else:
+                       self.stream.writeln("OK")
+               return result
+
+test_cps = ['sys-apps/portage', 'virtual/portage']
+test_versions = ['1.0', '1.0-r1', '2.3_p4', '1.0_alpha57']
+test_slots = [None, '1', 'gentoo-sources-2.6.17', 'spankywashere']
+test_usedeps = ['foo', '-bar', ('foo', 'bar'),
+       ('foo', '-bar'), ('foo?', '!bar?')]

diff --git a/repoman/pym/repoman/tests/runTests.py 
b/repoman/pym/repoman/tests/runTests.py
index 9c45276..882911c 100644
--- a/repoman/pym/repoman/tests/runTests.py
+++ b/repoman/pym/repoman/tests/runTests.py
@@ -29,7 +29,12 @@ os.environ["PORTAGE_GRPNAME"] = 
grp.getgrgid(os.getgid()).gr_name
 
 # Insert our parent dir so we can do shiny import "tests"
 # This line courtesy of Marienz and Pkgcore ;)
-sys.path.insert(0, 
osp.dirname(osp.dirname(osp.dirname(osp.realpath(__file__)))))
+repoman_pym = osp.dirname(osp.dirname(osp.dirname(osp.realpath(__file__))))
+sys.path.insert(0, repoman_pym)
+
+# Add in the parent portage python modules
+portage_pym = osp.dirname(osp.dirname(repoman_pym))+'/pym'
+sys.path.insert(0, portage_pym)
 
 import portage
 portage._internal_caller = True
@@ -41,7 +46,7 @@ portage._disable_legacy_globals()
 if os.environ.get('NOCOLOR') in ('yes', 'true'):
        portage.output.nocolor()
 
-import portage.tests as tests
+import repoman.tests as tests
 from portage.const import PORTAGE_BIN_PATH
 path = os.environ.get("PATH", "").split(":")
 path = [x for x in path if x]

diff --git a/repoman/pym/repoman/tests/simple/__test__.py 
b/repoman/pym/repoman/tests/simple/__test__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/repoman/pym/repoman/tests/simple/__test__.py
@@ -0,0 +1 @@
+

diff --git a/repoman/pym/repoman/tests/simple/test_simple.py 
b/repoman/pym/repoman/tests/simple/test_simple.py
index 6a79761..72eae66 100644
--- a/repoman/pym/repoman/tests/simple/test_simple.py
+++ b/repoman/pym/repoman/tests/simple/test_simple.py
@@ -10,10 +10,10 @@ from portage import os
 from portage import _unicode_decode
 from portage.const import PORTAGE_BASE_PATH, PORTAGE_PYM_PATH
 from portage.process import find_binary
-from portage.tests import TestCase
 from portage.tests.resolver.ResolverPlayground import ResolverPlayground
 from portage.util import ensure_dirs
 from repoman.copyrights import update_copyright_year
+from repoman.tests import TestCase
 
 class SimpleRepomanTestCase(TestCase):
 

diff --git a/repoman/runtests b/repoman/runtests
new file mode 100755
index 0000000..bad83dc
--- /dev/null
+++ b/repoman/runtests
@@ -0,0 +1,180 @@
+#!/usr/bin/python
+# Copyright 2010-2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+#
+# Note: We don't want to import portage modules directly because we do things
+# like run the testsuite through multiple versions of python.
+
+"""Helper script to run portage unittests against different python versions.
+
+Note: Any additional arguments will be passed down directly to the underlying
+unittest runner.  This lets you select specific tests to execute.
+"""
+
+from __future__ import print_function
+
+import argparse
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+
+
+# These are the versions we fully support and require to pass tests.
+PYTHON_SUPPORTED_VERSIONS = [
+       '2.7',
+       '3.3',
+       '3.4',
+]
+# The rest are just "nice to have".
+PYTHON_NICE_VERSIONS = [
+       'pypy',
+       '3.5',
+]
+
+EPREFIX = os.environ.get('PORTAGE_OVERRIDE_EPREFIX', '/')
+
+
+class Colors(object):
+       """Simple object holding color constants."""
+
+       _COLORS_YES = ('y', 'yes', 'true')
+       _COLORS_NO = ('n', 'no', 'false')
+
+       WARN = GOOD = BAD = NORMAL = ''
+
+       def __init__(self, colorize=None):
+               if colorize is None:
+                       nocolors = os.environ.get('NOCOLOR', 'false')
+                       # Ugh, look away, for here we invert the world!
+                       if nocolors in self._COLORS_YES:
+                               colorize = False
+                       elif nocolors in self._COLORS_NO:
+                               colorize = True
+                       else:
+                               raise ValueError('$NOCOLORS is invalid: %s' % 
nocolors)
+               else:
+                       if colorize in self._COLORS_YES:
+                               colorize = True
+                       elif colorize in self._COLORS_NO:
+                               colorize = False
+                       else:
+                               raise ValueError('--colors is invalid: %s' % 
colorize)
+
+               if colorize:
+                       self.WARN = '\033[1;33m'
+                       self.GOOD = '\033[1;32m'
+                       self.BAD = '\033[1;31m'
+                       self.NORMAL = '\033[0m'
+
+
+def get_python_executable(ver):
+       """Find the right python executable for |ver|"""
+       if ver in ('pypy', 'pypy3'):
+               prog = ver
+       else:
+               prog = 'python' + ver
+       return os.path.join(EPREFIX, 'usr', 'bin', prog)
+
+
+def get_parser():
+       """Return a argument parser for this module"""
+       epilog = """Examples:
+List all the available unittests.
+$ %(prog)s --list
+
+Run against specific versions of python.
+$ %(prog)s --python-versions '2.7 3.3'
+
+Run just one unittest.
+$ %(prog)s pym/portage/tests/xpak/test_decodeint.py
+"""
+       parser = argparse.ArgumentParser(
+               description=__doc__,
+               formatter_class=argparse.RawDescriptionHelpFormatter,
+               epilog=epilog)
+       parser.add_argument('--keep-temp', default=False, action='store_true',
+               help='Do not delete the temporary directory when exiting')
+       parser.add_argument('--color', type=str, default=None,
+               help='Whether to use colorized output (default is auto)')
+       parser.add_argument('--python-versions', action='append',
+               help='Versions of python to test (default is test available)')
+       return parser
+
+
+def main(argv):
+       parser = get_parser()
+       opts, args = parser.parse_known_args(argv)
+       colors = Colors(colorize=opts.color)
+
+       # Figure out all the versions we want to test.
+       if opts.python_versions is None:
+               ignore_missing = True
+               pyversions = PYTHON_SUPPORTED_VERSIONS + PYTHON_NICE_VERSIONS
+       else:
+               ignore_missing = False
+               pyversions = []
+               for ver in opts.python_versions:
+                       if ver == 'supported':
+                               pyversions.extend(PYTHON_SUPPORTED_VERSIONS)
+                       else:
+                               pyversions.extend(ver.split())
+
+       tempdir = None
+       try:
+               # Set up a single tempdir for all the tests to use.
+               # This way we know the tests won't leak things on us.
+               tempdir = tempfile.mkdtemp(prefix='repoman.runtests.')
+               os.environ['TMPDIR'] = tempdir
+
+               # Actually test those versions now.
+               statuses = []
+               for ver in pyversions:
+                       prog = get_python_executable(ver)
+                       cmd = [prog, '-b', '-Wd', 
'pym/repoman/tests/runTests.py'] + args
+                       if os.access(prog, os.X_OK):
+                               print('%sTesting with Python %s...%s' %
+                                       (colors.GOOD, ver, colors.NORMAL))
+                               statuses.append((ver, subprocess.call(cmd)))
+                       elif not ignore_missing:
+                               print('%sCould not find requested Python %s%s' %
+                                       (colors.BAD, ver, colors.NORMAL))
+                               statuses.append((ver, 1))
+                       else:
+                               print('%sSkip Python %s...%s' %
+                                       (colors.WARN, ver, colors.NORMAL))
+                       print()
+       finally:
+               if tempdir is not None:
+                       if opts.keep_temp:
+                               print('Temporary directory left behind:\n%s' % 
tempdir)
+                       else:
+                               # Nuke our tempdir and anything that might be 
under it.
+                               shutil.rmtree(tempdir, True)
+
+       # Then summarize it all.
+       print('\nSummary:\n')
+       width = 10
+       header = '| %-*s | %s' % (width, 'Version', 'Status')
+       print('%s\n|%s' % (header, '-' * (len(header) - 1)))
+       exit_status = 0
+       for ver, status in statuses:
+               exit_status += status
+               if status:
+                       color = colors.BAD
+                       msg = 'FAIL'
+               else:
+                       color = colors.GOOD
+                       msg = 'PASS'
+               print('| %s%-*s%s | %s%s%s' %
+                       (color, width, ver, colors.NORMAL, color, msg, 
colors.NORMAL))
+       exit(exit_status)
+
+
+if __name__ == '__main__':
+       try:
+               main(sys.argv[1:])
+       except KeyboardInterrupt:
+               print('interrupted ...', file=sys.stderr)
+               exit(1)

Reply via email to