public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/portage:repoman commit in: repoman/pym/repoman/tests/simple/, repoman/pym/repoman/tests/, repoman/
@ 2016-05-14 18:33 Brian Dolbec
  2016-05-15 23:51 ` [gentoo-commits] proj/portage:master " Brian Dolbec
  0 siblings, 1 reply; 3+ messages in thread
From: Brian Dolbec @ 2016-05-14 18:33 UTC (permalink / raw
  To: gentoo-commits

commit:     50f3664b855b4ea70860fbea1827a68cd0da127a
Author:     Brian Dolbec <dolsen <AT> gentoo <DOT> org>
AuthorDate: Sat May 14 18:11:17 2016 +0000
Commit:     Brian Dolbec <dolsen <AT> gentoo <DOT> org>
CommitDate: Sat May 14 18:29:40 2016 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=50f3664b

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 |   7 +-
 repoman/runtests                                | 180 ++++++++++++
 5 files changed, 545 insertions(+), 5 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..ae5194f 100644
--- a/repoman/pym/repoman/tests/simple/test_simple.py
+++ b/repoman/pym/repoman/tests/simple/test_simple.py
@@ -10,10 +10,13 @@ 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
+
+REPOMAN_BASE_PATH = os.path.join(PORTAGE_BASE_PATH, 'repoman')
+
 
 class SimpleRepomanTestCase(TestCase):
 
@@ -128,7 +131,7 @@ class SimpleRepomanTestCase(TestCase):
 		}
 		licenses = ["GPL-2"]
 		arch_list = ["x86"]
-		metadata_xsd = os.path.join(PORTAGE_BASE_PATH, "cnf/metadata.xsd")
+		metadata_xsd = os.path.join(REPOMAN_BASE_PATH, "cnf/metadata.xsd")
 		metadata_xml_files = (
 			(
 				"dev-libs/A",

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)


^ permalink raw reply related	[flat|nested] 3+ messages in thread
* [gentoo-commits] proj/portage:repoman commit in: repoman/pym/repoman/tests/simple/, repoman/pym/repoman/tests/, repoman/
@ 2016-05-14 18:12 Brian Dolbec
  0 siblings, 0 replies; 3+ messages in thread
From: Brian Dolbec @ 2016-05-14 18:12 UTC (permalink / raw
  To: gentoo-commits

commit:     0aac71f5ed2eff3ad0a3cf9114c8e54b61269d4b
Author:     Brian Dolbec <dolsen <AT> gentoo <DOT> org>
AuthorDate: Sat May 14 18:11:17 2016 +0000
Commit:     Brian Dolbec <dolsen <AT> gentoo <DOT> org>
CommitDate: Sat May 14 18:11:17 2016 +0000
URL:        https://gitweb.gentoo.org/proj/portage.git/commit/?id=0aac71f5

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 |   7 +-
 repoman/runtests                                | 180 ++++++++++++
 5 files changed, 545 insertions(+), 5 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..ae5194f 100644
--- a/repoman/pym/repoman/tests/simple/test_simple.py
+++ b/repoman/pym/repoman/tests/simple/test_simple.py
@@ -10,10 +10,13 @@ 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
+
+REPOMAN_BASE_PATH = os.path.join(PORTAGE_BASE_PATH, 'repoman')
+
 
 class SimpleRepomanTestCase(TestCase):
 
@@ -128,7 +131,7 @@ class SimpleRepomanTestCase(TestCase):
 		}
 		licenses = ["GPL-2"]
 		arch_list = ["x86"]
-		metadata_xsd = os.path.join(PORTAGE_BASE_PATH, "cnf/metadata.xsd")
+		metadata_xsd = os.path.join(REPOMAN_BASE_PATH, "cnf/metadata.xsd")
 		metadata_xml_files = (
 			(
 				"dev-libs/A",

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)


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2016-05-15 23:51 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-05-14 18:33 [gentoo-commits] proj/portage:repoman commit in: repoman/pym/repoman/tests/simple/, repoman/pym/repoman/tests/, repoman/ Brian Dolbec
2016-05-15 23:51 ` [gentoo-commits] proj/portage:master " Brian Dolbec
  -- strict thread matches above, loose matches on Subject: below --
2016-05-14 18:12 [gentoo-commits] proj/portage:repoman " Brian Dolbec

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox