main.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. #!/usr/bin/env python3
  2. # SPDX-License-Identifier: GPL-2.0+
  3. # Copyright (c) 2016 Google, Inc
  4. # Written by Simon Glass <sjg@chromium.org>
  5. #
  6. # Creates binary images from input files controlled by a description
  7. #
  8. """See README for more information"""
  9. from distutils.sysconfig import get_python_lib
  10. import glob
  11. import multiprocessing
  12. import os
  13. import site
  14. import sys
  15. import traceback
  16. import unittest
  17. # Bring in the patman and dtoc libraries (but don't override the first path
  18. # in PYTHONPATH)
  19. our_path = os.path.dirname(os.path.realpath(__file__))
  20. for dirname in ['../patman', '../dtoc', '..', '../concurrencytest']:
  21. sys.path.insert(2, os.path.join(our_path, dirname))
  22. # Bring in the libfdt module
  23. sys.path.insert(2, 'scripts/dtc/pylibfdt')
  24. sys.path.insert(2, os.path.join(our_path,
  25. '../../build-sandbox_spl/scripts/dtc/pylibfdt'))
  26. # When running under python-coverage on Ubuntu 16.04, the dist-packages
  27. # directories are dropped from the python path. Add them in so that we can find
  28. # the elffile module. We could use site.getsitepackages() here but unfortunately
  29. # that is not available in a virtualenv.
  30. sys.path.append(get_python_lib())
  31. import cmdline
  32. import command
  33. use_concurrent = True
  34. try:
  35. from concurrencytest import ConcurrentTestSuite, fork_for_tests
  36. except:
  37. use_concurrent = False
  38. import control
  39. import test_util
  40. def RunTests(debug, verbosity, processes, test_preserve_dirs, args, toolpath):
  41. """Run the functional tests and any embedded doctests
  42. Args:
  43. debug: True to enable debugging, which shows a full stack trace on error
  44. verbosity: Verbosity level to use
  45. test_preserve_dirs: True to preserve the input directory used by tests
  46. so that it can be examined afterwards (only useful for debugging
  47. tests). If a single test is selected (in args[0]) it also preserves
  48. the output directory for this test. Both directories are displayed
  49. on the command line.
  50. processes: Number of processes to use to run tests (None=same as #CPUs)
  51. args: List of positional args provided to binman. This can hold a test
  52. name to execute (as in 'binman test testSections', for example)
  53. toolpath: List of paths to use for tools
  54. """
  55. import cbfs_util_test
  56. import elf_test
  57. import entry_test
  58. import fdt_test
  59. import ftest
  60. import image_test
  61. import test
  62. import doctest
  63. result = unittest.TestResult()
  64. for module in []:
  65. suite = doctest.DocTestSuite(module)
  66. suite.run(result)
  67. sys.argv = [sys.argv[0]]
  68. if debug:
  69. sys.argv.append('-D')
  70. if verbosity:
  71. sys.argv.append('-v%d' % verbosity)
  72. if toolpath:
  73. for path in toolpath:
  74. sys.argv += ['--toolpath', path]
  75. # Run the entry tests first ,since these need to be the first to import the
  76. # 'entry' module.
  77. test_name = args and args[0] or None
  78. suite = unittest.TestSuite()
  79. loader = unittest.TestLoader()
  80. for module in (entry_test.TestEntry, ftest.TestFunctional, fdt_test.TestFdt,
  81. elf_test.TestElf, image_test.TestImage,
  82. cbfs_util_test.TestCbfs):
  83. # Test the test module about our arguments, if it is interested
  84. if hasattr(module, 'setup_test_args'):
  85. setup_test_args = getattr(module, 'setup_test_args')
  86. setup_test_args(preserve_indir=test_preserve_dirs,
  87. preserve_outdirs=test_preserve_dirs and test_name is not None,
  88. toolpath=toolpath, verbosity=verbosity)
  89. if test_name:
  90. try:
  91. suite.addTests(loader.loadTestsFromName(test_name, module))
  92. except AttributeError:
  93. continue
  94. else:
  95. suite.addTests(loader.loadTestsFromTestCase(module))
  96. if use_concurrent and processes != 1:
  97. concurrent_suite = ConcurrentTestSuite(suite,
  98. fork_for_tests(processes or multiprocessing.cpu_count()))
  99. concurrent_suite.run(result)
  100. else:
  101. suite.run(result)
  102. # Remove errors which just indicate a missing test. Since Python v3.5 If an
  103. # ImportError or AttributeError occurs while traversing name then a
  104. # synthetic test that raises that error when run will be returned. These
  105. # errors are included in the errors accumulated by result.errors.
  106. if test_name:
  107. errors = []
  108. for test, err in result.errors:
  109. if ("has no attribute '%s'" % test_name) not in err:
  110. errors.append((test, err))
  111. result.testsRun -= 1
  112. result.errors = errors
  113. print(result)
  114. for test, err in result.errors:
  115. print(test.id(), err)
  116. for test, err in result.failures:
  117. print(err, result.failures)
  118. if result.skipped:
  119. print('%d binman test%s SKIPPED:' %
  120. (len(result.skipped), 's' if len(result.skipped) > 1 else ''))
  121. for skip_info in result.skipped:
  122. print('%s: %s' % (skip_info[0], skip_info[1]))
  123. if result.errors or result.failures:
  124. print('binman tests FAILED')
  125. return 1
  126. return 0
  127. def GetEntryModules(include_testing=True):
  128. """Get a set of entry class implementations
  129. Returns:
  130. Set of paths to entry class filenames
  131. """
  132. glob_list = glob.glob(os.path.join(our_path, 'etype/*.py'))
  133. return set([os.path.splitext(os.path.basename(item))[0]
  134. for item in glob_list
  135. if include_testing or '_testing' not in item])
  136. def RunTestCoverage():
  137. """Run the tests and check that we get 100% coverage"""
  138. glob_list = GetEntryModules(False)
  139. all_set = set([os.path.splitext(os.path.basename(item))[0]
  140. for item in glob_list if '_testing' not in item])
  141. test_util.RunTestCoverage('tools/binman/binman', None,
  142. ['*test*', '*main.py', 'tools/patman/*', 'tools/dtoc/*'],
  143. args.build_dir, all_set)
  144. def RunBinman(args):
  145. """Main entry point to binman once arguments are parsed
  146. Args:
  147. args: Command line arguments Namespace object
  148. """
  149. ret_code = 0
  150. if not args.debug:
  151. sys.tracebacklimit = 0
  152. if args.cmd == 'test':
  153. if args.test_coverage:
  154. RunTestCoverage()
  155. else:
  156. ret_code = RunTests(args.debug, args.verbosity, args.processes,
  157. args.test_preserve_dirs, args.tests,
  158. args.toolpath)
  159. elif args.cmd == 'entry-docs':
  160. control.WriteEntryDocs(GetEntryModules())
  161. else:
  162. try:
  163. ret_code = control.Binman(args)
  164. except Exception as e:
  165. print('binman: %s' % e)
  166. if args.debug:
  167. print()
  168. traceback.print_exc()
  169. ret_code = 1
  170. return ret_code
  171. if __name__ == "__main__":
  172. args = cmdline.ParseArgs(sys.argv[1:])
  173. ret_code = RunBinman(args)
  174. sys.exit(ret_code)