Home | History | Annotate | Download | only in lit
      1 from __future__ import absolute_import
      2 import inspect
      3 import os
      4 import sys
      5 
      6 import lit.Test
      7 import lit.formats
      8 import lit.TestingConfig
      9 import lit.util
     10 
     11 # LitConfig must be a new style class for properties to work
     12 class LitConfig(object):
     13     """LitConfig - Configuration data for a 'lit' test runner instance, shared
     14     across all tests.
     15 
     16     The LitConfig object is also used to communicate with client configuration
     17     files, it is always passed in as the global variable 'lit' so that
     18     configuration files can access common functionality and internal components
     19     easily.
     20     """
     21 
     22     def __init__(self, progname, path, quiet,
     23                  useValgrind, valgrindLeakCheck, valgrindArgs,
     24                  noExecute, debug, isWindows, singleProcess,
     25                  params, config_prefix = None,
     26                  maxIndividualTestTime = 0,
     27                  maxFailures = None,
     28                  parallelism_groups = {},
     29                  echo_all_commands = False):
     30         # The name of the test runner.
     31         self.progname = progname
     32         # The items to add to the PATH environment variable.
     33         self.path = [str(p) for p in path]
     34         self.quiet = bool(quiet)
     35         self.useValgrind = bool(useValgrind)
     36         self.valgrindLeakCheck = bool(valgrindLeakCheck)
     37         self.valgrindUserArgs = list(valgrindArgs)
     38         self.noExecute = noExecute
     39         self.debug = debug
     40         self.singleProcess = singleProcess
     41         self.isWindows = bool(isWindows)
     42         self.params = dict(params)
     43         self.bashPath = None
     44 
     45         # Configuration files to look for when discovering test suites.
     46         self.config_prefix = config_prefix or 'lit'
     47         self.suffixes = ['cfg.py', 'cfg']
     48         self.config_names = ['%s.%s' % (self.config_prefix,x) for x in self.suffixes]
     49         self.site_config_names = ['%s.site.%s' % (self.config_prefix,x) for x in self.suffixes]
     50         self.local_config_names = ['%s.local.%s' % (self.config_prefix,x) for x in self.suffixes]
     51 
     52         self.numErrors = 0
     53         self.numWarnings = 0
     54 
     55         self.valgrindArgs = []
     56         if self.useValgrind:
     57             self.valgrindArgs = ['valgrind', '-q', '--run-libc-freeres=no',
     58                                  '--tool=memcheck', '--trace-children=yes',
     59                                  '--error-exitcode=123']
     60             if self.valgrindLeakCheck:
     61                 self.valgrindArgs.append('--leak-check=full')
     62             else:
     63                 # The default is 'summary'.
     64                 self.valgrindArgs.append('--leak-check=no')
     65             self.valgrindArgs.extend(self.valgrindUserArgs)
     66 
     67         self.maxIndividualTestTime = maxIndividualTestTime
     68         self.maxFailures = maxFailures
     69         self.parallelism_groups = parallelism_groups
     70         self.echo_all_commands = echo_all_commands
     71 
     72     @property
     73     def maxIndividualTestTime(self):
     74         """
     75             Interface for getting maximum time to spend executing
     76             a single test
     77         """
     78         return self._maxIndividualTestTime
     79 
     80     @maxIndividualTestTime.setter
     81     def maxIndividualTestTime(self, value):
     82         """
     83             Interface for setting maximum time to spend executing
     84             a single test
     85         """
     86         if not isinstance(value, int):
     87             self.fatal('maxIndividualTestTime must set to a value of type int.')
     88         self._maxIndividualTestTime = value
     89         if self.maxIndividualTestTime > 0:
     90             # The current implementation needs psutil to set
     91             # a timeout per test. Check it's available.
     92             # See lit.util.killProcessAndChildren()
     93             try:
     94                 import psutil  # noqa: F401
     95             except ImportError:
     96                 self.fatal("Setting a timeout per test requires the"
     97                            " Python psutil module but it could not be"
     98                            " found. Try installing it via pip or via"
     99                            " your operating system's package manager.")
    100         elif self.maxIndividualTestTime < 0:
    101             self.fatal('The timeout per test must be >= 0 seconds')
    102 
    103     def load_config(self, config, path):
    104         """load_config(config, path) - Load a config object from an alternate
    105         path."""
    106         if self.debug:
    107             self.note('load_config from %r' % path)
    108         config.load_from_path(path, self)
    109         return config
    110 
    111     def getBashPath(self):
    112         """getBashPath - Get the path to 'bash'"""
    113         if self.bashPath is not None:
    114             return self.bashPath
    115 
    116         self.bashPath = lit.util.which('bash', os.pathsep.join(self.path))
    117         if self.bashPath is None:
    118             self.bashPath = lit.util.which('bash')
    119 
    120         if self.bashPath is None:
    121             self.bashPath = ''
    122 
    123         return self.bashPath
    124 
    125     def getToolsPath(self, dir, paths, tools):
    126         if dir is not None and os.path.isabs(dir) and os.path.isdir(dir):
    127             if not lit.util.checkToolsPath(dir, tools):
    128                 return None
    129         else:
    130             dir = lit.util.whichTools(tools, paths)
    131 
    132         # bash
    133         self.bashPath = lit.util.which('bash', dir)
    134         if self.bashPath is None:
    135             self.bashPath = ''
    136 
    137         return dir
    138 
    139     def _write_message(self, kind, message):
    140         # Get the file/line where this message was generated.
    141         f = inspect.currentframe()
    142         # Step out of _write_message, and then out of wrapper.
    143         f = f.f_back.f_back
    144         file,line,_,_,_ = inspect.getframeinfo(f)
    145         location = '%s:%d' % (file, line)
    146 
    147         sys.stderr.write('%s: %s: %s: %s\n' % (self.progname, location,
    148                                                kind, message))
    149 
    150     def note(self, message):
    151         self._write_message('note', message)
    152 
    153     def warning(self, message):
    154         self._write_message('warning', message)
    155         self.numWarnings += 1
    156 
    157     def error(self, message):
    158         self._write_message('error', message)
    159         self.numErrors += 1
    160 
    161     def fatal(self, message):
    162         self._write_message('fatal', message)
    163         sys.exit(2)
    164