X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=tools%2Fbinman%2Fbinman.py;h=52c03f68c6d0c743250ae4ebb39ab26bfc62a252;hb=8acce60b10f2d60945b71f527fd29ee62242b175;hp=7fb67cb25f9c65dc58f7441ecb5a365bfef88d50;hpb=7588bf939090c1110f2067895f026ebe81b30d72;p=oweals%2Fu-boot.git diff --git a/tools/binman/binman.py b/tools/binman/binman.py index 7fb67cb25f..52c03f68c6 100755 --- a/tools/binman/binman.py +++ b/tools/binman/binman.py @@ -1,37 +1,72 @@ -#!/usr/bin/python +#!/usr/bin/env python2 +# SPDX-License-Identifier: GPL-2.0+ # Copyright (c) 2016 Google, Inc # Written by Simon Glass # -# SPDX-License-Identifier: GPL-2.0+ -# # Creates binary images from input files controlled by a description # """See README for more information""" +from __future__ import print_function + +from distutils.sysconfig import get_python_lib +import glob +import multiprocessing import os +import site import sys import traceback import unittest # Bring in the patman and dtoc libraries our_path = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join(our_path, '../patman')) -sys.path.append(os.path.join(our_path, '../dtoc')) +for dirname in ['../patman', '../dtoc', '..', '../concurrencytest']: + sys.path.insert(0, os.path.join(our_path, dirname)) + +# Bring in the libfdt module +sys.path.insert(0, 'scripts/dtc/pylibfdt') +sys.path.insert(0, os.path.join(our_path, + '../../build-sandbox_spl/scripts/dtc/pylibfdt')) -# Also allow entry-type modules to be brought in from the etype directory. -sys.path.append(os.path.join(our_path, 'etype')) +# When running under python-coverage on Ubuntu 16.04, the dist-packages +# directories are dropped from the python path. Add them in so that we can find +# the elffile module. We could use site.getsitepackages() here but unfortunately +# that is not available in a virtualenv. +sys.path.append(get_python_lib()) import cmdline import command +use_concurrent = True +try: + from concurrencytest import ConcurrentTestSuite, fork_for_tests +except: + use_concurrent = False import control +import test_util -def RunTests(): - """Run the functional tests and any embedded doctests""" +def RunTests(debug, verbosity, processes, test_preserve_dirs, args, toolpath): + """Run the functional tests and any embedded doctests + + Args: + debug: True to enable debugging, which shows a full stack trace on error + verbosity: Verbosity level to use + test_preserve_dirs: True to preserve the input directory used by tests + so that it can be examined afterwards (only useful for debugging + tests). If a single test is selected (in args[0]) it also preserves + the output directory for this test. Both directories are displayed + on the command line. + processes: Number of processes to use to run tests (None=same as #CPUs) + args: List of positional args provided to binman. This can hold a test + name to execute (as in 'binman -t testSections', for example) + toolpath: List of paths to use for tools + """ + import elf_test import entry_test import fdt_test - import func_test + import ftest + import image_test import test import doctest @@ -41,31 +76,87 @@ def RunTests(): suite.run(result) sys.argv = [sys.argv[0]] - for module in (func_test.TestFunctional, fdt_test.TestFdt, - entry_test.TestEntry): - suite = unittest.TestLoader().loadTestsFromTestCase(module) + if debug: + sys.argv.append('-D') + if verbosity: + sys.argv.append('-v%d' % verbosity) + if toolpath: + for path in toolpath: + sys.argv += ['--toolpath', path] + + # Run the entry tests first ,since these need to be the first to import the + # 'entry' module. + test_name = args and args[0] or None + suite = unittest.TestSuite() + loader = unittest.TestLoader() + for module in (entry_test.TestEntry, ftest.TestFunctional, fdt_test.TestFdt, + elf_test.TestElf, image_test.TestImage): + # Test the test module about our arguments, if it is interested + if hasattr(module, 'setup_test_args'): + setup_test_args = getattr(module, 'setup_test_args') + setup_test_args(preserve_indir=test_preserve_dirs, + preserve_outdirs=test_preserve_dirs and test_name is not None, + toolpath=toolpath) + if test_name: + try: + suite.addTests(loader.loadTestsFromName(test_name, module)) + except AttributeError: + continue + else: + suite.addTests(loader.loadTestsFromTestCase(module)) + if use_concurrent and processes != 1: + concurrent_suite = ConcurrentTestSuite(suite, + fork_for_tests(processes or multiprocessing.cpu_count())) + concurrent_suite.run(result) + else: suite.run(result) - print result + # Remove errors which just indicate a missing test. Since Python v3.5 If an + # ImportError or AttributeError occurs while traversing name then a + # synthetic test that raises that error when run will be returned. These + # errors are included in the errors accumulated by result.errors. + if test_name: + errors = [] + for test, err in result.errors: + if ("has no attribute '%s'" % test_name) not in err: + errors.append((test, err)) + result.testsRun -= 1 + result.errors = errors + + print(result) for test, err in result.errors: - print test.id(), err + print(test.id(), err) for test, err in result.failures: - print err + print(err, result.failures) + if result.skipped: + print('%d binman test%s SKIPPED:' % + (len(result.skipped), 's' if len(result.skipped) > 1 else '')) + for skip_info in result.skipped: + print('%s: %s' % (skip_info[0], skip_info[1])) + if result.errors or result.failures: + print('binman tests FAILED') + return 1 + return 0 + +def GetEntryModules(include_testing=True): + """Get a set of entry class implementations + + Returns: + Set of paths to entry class filenames + """ + glob_list = glob.glob(os.path.join(our_path, 'etype/*.py')) + return set([os.path.splitext(os.path.basename(item))[0] + for item in glob_list + if include_testing or '_testing' not in item]) def RunTestCoverage(): """Run the tests and check that we get 100% coverage""" - # This uses the build output from sandbox_spl to get _libfdt.so - cmd = ('PYTHONPATH=%s/sandbox_spl/tools coverage run ' - '--include "tools/binman/*.py" --omit "*test*,*binman.py" ' - 'tools/binman/binman.py -t' % options.build_dir) - os.system(cmd) - stdout = command.Output('coverage', 'report') - coverage = stdout.splitlines()[-1].split(' ')[-1] - if coverage != '100%': - print stdout - print "Type 'coverage html' to get a report in htmlcov/index.html" - raise ValueError('Coverage error: %s, but should be 100%%' % coverage) - + glob_list = GetEntryModules(False) + all_set = set([os.path.splitext(os.path.basename(item))[0] + for item in glob_list if '_testing' not in item]) + test_util.RunTestCoverage('tools/binman/binman.py', None, + ['*test*', '*binman.py', 'tools/patman/*', 'tools/dtoc/*'], + options.build_dir, all_set) def RunBinman(options, args): """Main entry point to binman once arguments are parsed @@ -76,33 +167,27 @@ def RunBinman(options, args): """ ret_code = 0 - # For testing: This enables full exception traces. - #options.debug = True - if not options.debug: sys.tracebacklimit = 0 if options.test: - RunTests() + ret_code = RunTests(options.debug, options.verbosity, options.processes, + options.test_preserve_dirs, args[1:], + options.toolpath) elif options.test_coverage: RunTestCoverage() - elif options.full_help: - pager = os.getenv('PAGER') - if not pager: - pager = 'more' - fname = os.path.join(os.path.dirname(os.path.realpath(sys.argv[0])), - 'README') - command.Run(pager, fname) + elif options.entry_docs: + control.WriteEntryDocs(GetEntryModules()) else: try: ret_code = control.Binman(options, args) except Exception as e: - print 'binman: %s' % e + print('binman: %s' % e) if options.debug: - print + print() traceback.print_exc() ret_code = 1 return ret_code