diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2017-08-20 21:02:43 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2017-08-20 21:02:43 +0000 |
| commit | 15c5c77fa04cd97e1057e8a585f669fc49da0d92 (patch) | |
| tree | 9047e00a30ccb7b81dbe7227c8c883cbafb5d2dd /utils | |
| parent | 4e20bb0468b8d0db13287e666b482eb93689be99 (diff) | |
Notes
Diffstat (limited to 'utils')
| -rw-r--r-- | utils/lit/lit/LitConfig.py | 2 | ||||
| -rw-r--r-- | utils/lit/lit/TestRunner.py | 2 | ||||
| -rw-r--r-- | utils/lit/lit/formats/__init__.py | 7 | ||||
| -rw-r--r-- | utils/lit/lit/formats/base.py | 157 | ||||
| -rw-r--r-- | utils/lit/lit/formats/shtest.py | 33 | ||||
| -rw-r--r-- | utils/lit/lit/run.py | 13 | ||||
| -rw-r--r-- | utils/lit/tests/Inputs/max-failures/lit.cfg | 6 | ||||
| -rw-r--r-- | utils/lit/tests/max-failures.py | 8 | ||||
| -rw-r--r-- | utils/lit/tests/selecting.py | 2 | ||||
| -rwxr-xr-x | utils/release/test-release.sh | 21 |
10 files changed, 155 insertions, 96 deletions
diff --git a/utils/lit/lit/LitConfig.py b/utils/lit/lit/LitConfig.py index 2ef0a8f77ec9..3351ebed54bd 100644 --- a/utils/lit/lit/LitConfig.py +++ b/utils/lit/lit/LitConfig.py @@ -25,7 +25,7 @@ class LitConfig(object): params, config_prefix = None, maxIndividualTestTime = 0, maxFailures = None, - parallelism_groups = [], + parallelism_groups = {}, echo_all_commands = False): # The name of the test runner. self.progname = progname diff --git a/utils/lit/lit/TestRunner.py b/utils/lit/lit/TestRunner.py index 46bcac4b306e..a60a0f854870 100644 --- a/utils/lit/lit/TestRunner.py +++ b/utils/lit/lit/TestRunner.py @@ -313,7 +313,7 @@ def processRedirects(cmd, stdin_source, cmd_shenv, opened_files): elif op == ('<',): redirects[0] = [filename, 'r', None] else: - raise InternalShellError(cmd, "Unsupported redirect: %r" % (r,)) + raise InternalShellError(cmd, "Unsupported redirect: %r" % ((op, filename),)) # Open file descriptors in a second pass. std_fds = [None, None, None] diff --git a/utils/lit/lit/formats/__init__.py b/utils/lit/lit/formats/__init__.py index 7d14ca4b535a..3ff46e93ead2 100644 --- a/utils/lit/lit/formats/__init__.py +++ b/utils/lit/lit/formats/__init__.py @@ -1,3 +1,8 @@ -from lit.formats.base import TestFormat # noqa: F401 +from lit.formats.base import ( # noqa: F401 + TestFormat, + FileBasedTest, + OneCommandPerFileTest +) + from lit.formats.googletest import GoogleTest # noqa: F401 from lit.formats.shtest import ShTest # noqa: F401 diff --git a/utils/lit/lit/formats/base.py b/utils/lit/lit/formats/base.py index baa9ff1d3b7d..6721d17e334e 100644 --- a/utils/lit/lit/formats/base.py +++ b/utils/lit/lit/formats/base.py @@ -1,50 +1,117 @@ -import abc +from __future__ import absolute_import +import os + +import lit.Test +import lit.util class TestFormat(object): - """Base class for test formats. - - A TestFormat encapsulates logic for finding and executing a certain type of - test. For example, a subclass FooTestFormat would contain the logic for - finding tests written in the 'Foo' format, and the logic for running a - single one. - - TestFormat is an Abstract Base Class (ABC). It uses the Python abc.ABCMeta - type and associated @abc.abstractmethod decorator. Together, these provide - subclass behaviour which is notionally similar to C++ pure virtual classes: - only subclasses which implement all abstract methods can be instantiated - (the implementation may come from an intermediate base). - - For details on ABCs, see: https://docs.python.org/2/library/abc.html. Note - that Python ABCs have extensive abilities beyond what is used here. For - TestFormat, we only care about enforcing that abstract methods are - implemented. - """ - - __metaclass__ = abc.ABCMeta - - @abc.abstractmethod - def getTestsInDirectory(self, testSuite, path_in_suite, litConfig, - localConfig): - """Finds tests of this format in the given directory. - - Args: - testSuite: a Test.TestSuite object. - path_in_suite: the subpath under testSuite to look for tests. - litConfig: the LitConfig for the test suite. - localConfig: a LitConfig with local specializations. - - Returns: - An iterable of Test.Test objects. - """ - - @abc.abstractmethod + pass + +### + +class FileBasedTest(TestFormat): + def getTestsInDirectory(self, testSuite, path_in_suite, + litConfig, localConfig): + source_path = testSuite.getSourcePath(path_in_suite) + for filename in os.listdir(source_path): + # Ignore dot files and excluded tests. + if (filename.startswith('.') or + filename in localConfig.excludes): + continue + + filepath = os.path.join(source_path, filename) + if not os.path.isdir(filepath): + base,ext = os.path.splitext(filename) + if ext in localConfig.suffixes: + yield lit.Test.Test(testSuite, path_in_suite + (filename,), + localConfig) + +### + +import re +import tempfile + +class OneCommandPerFileTest(TestFormat): + # FIXME: Refactor into generic test for running some command on a directory + # of inputs. + + def __init__(self, command, dir, recursive=False, + pattern=".*", useTempInput=False): + if isinstance(command, str): + self.command = [command] + else: + self.command = list(command) + if dir is not None: + dir = str(dir) + self.dir = dir + self.recursive = bool(recursive) + self.pattern = re.compile(pattern) + self.useTempInput = useTempInput + + def getTestsInDirectory(self, testSuite, path_in_suite, + litConfig, localConfig): + dir = self.dir + if dir is None: + dir = testSuite.getSourcePath(path_in_suite) + + for dirname,subdirs,filenames in os.walk(dir): + if not self.recursive: + subdirs[:] = [] + + subdirs[:] = [d for d in subdirs + if (d != '.svn' and + d not in localConfig.excludes)] + + for filename in filenames: + if (filename.startswith('.') or + not self.pattern.match(filename) or + filename in localConfig.excludes): + continue + + path = os.path.join(dirname,filename) + suffix = path[len(dir):] + if suffix.startswith(os.sep): + suffix = suffix[1:] + test = lit.Test.Test( + testSuite, path_in_suite + tuple(suffix.split(os.sep)), + localConfig) + # FIXME: Hack? + test.source_path = path + yield test + + def createTempInput(self, tmp, test): + raise NotImplementedError('This is an abstract method.') + def execute(self, test, litConfig): - """Runs the given 'test', which is of this format. + if test.config.unsupported: + return (lit.Test.UNSUPPORTED, 'Test is unsupported') + + cmd = list(self.command) + + # If using temp input, create a temporary file and hand it to the + # subclass. + if self.useTempInput: + tmp = tempfile.NamedTemporaryFile(suffix='.cpp') + self.createTempInput(tmp, test) + tmp.flush() + cmd.append(tmp.name) + elif hasattr(test, 'source_path'): + cmd.append(test.source_path) + else: + cmd.append(test.getSourcePath()) + + out, err, exitCode = lit.util.executeCommand(cmd) + + diags = out + err + if not exitCode and not diags.strip(): + return lit.Test.PASS,'' - Args: - test: a Test.Test object describing the test to run. - litConfig: the LitConfig for the test suite. + # Try to include some useful information. + report = """Command: %s\n""" % ' '.join(["'%s'" % a + for a in cmd]) + if self.useTempInput: + report += """Temporary File: %s\n""" % tmp.name + report += "--\n%s--\n""" % open(tmp.name).read() + report += """Output:\n--\n%s--""" % diags - Returns: - A tuple of (status:Test.ResultCode, message:str) - """ + return lit.Test.FAIL, report diff --git a/utils/lit/lit/formats/shtest.py b/utils/lit/lit/formats/shtest.py index 01ecd192092e..fdc9bd0241f3 100644 --- a/utils/lit/lit/formats/shtest.py +++ b/utils/lit/lit/formats/shtest.py @@ -1,13 +1,12 @@ from __future__ import absolute_import -import os - -import lit.Test import lit.TestRunner import lit.util -from .base import TestFormat -class ShTest(TestFormat): +from .base import FileBasedTest + + +class ShTest(FileBasedTest): """ShTest is a format with one file per test. This is the primary format for regression tests as described in the LLVM @@ -18,31 +17,9 @@ class ShTest(TestFormat): The ShTest files contain some number of shell-like command pipelines, along with assertions about what should be in the output. """ - - def __init__(self, execute_external = False): - """Initializer. - - The 'execute_external' argument controls whether lit uses its internal - logic for command pipelines, or passes the command to a shell - subprocess. - - Args: - execute_external: (optional) If true, use shell subprocesses instead - of lit's internal pipeline logic. - """ + def __init__(self, execute_external=False): self.execute_external = execute_external - def getTestsInDirectory(self, testSuite, path_in_suite, - litConfig, localConfig): - """Yields test files matching 'suffixes' from the localConfig.""" - file_matches = lit.util.listdir_files( - testSuite.getSourcePath(path_in_suite), - localConfig.suffixes, localConfig.excludes) - for filename in file_matches: - yield lit.Test.Test(testSuite, path_in_suite + (filename,), - localConfig) - def execute(self, test, litConfig): - """Interprets and runs the given test file, and returns the result.""" return lit.TestRunner.executeShTest(test, litConfig, self.execute_external) diff --git a/utils/lit/lit/run.py b/utils/lit/lit/run.py index 1290c142c834..3e39bdb92203 100644 --- a/utils/lit/lit/run.py +++ b/utils/lit/lit/run.py @@ -44,6 +44,12 @@ class Run(object): def __init__(self, lit_config, tests): self.lit_config = lit_config self.tests = tests + # Set up semaphores to limit parallelism of certain classes of tests. + # For example, some ASan tests require lots of virtual memory and run + # faster with less parallelism on OS X. + self.parallelism_semaphores = \ + {k: multiprocessing.Semaphore(v) for k, v in + self.lit_config.parallelism_groups.items()} def execute_test(self, test): return _execute_test_impl(test, self.lit_config, @@ -74,13 +80,6 @@ class Run(object): if not self.tests or jobs == 0: return - # Set up semaphores to limit parallelism of certain classes of tests. - # For example, some ASan tests require lots of virtual memory and run - # faster with less parallelism on OS X. - self.parallelism_semaphores = \ - {k: multiprocessing.Semaphore(v) for k, v in - self.lit_config.parallelism_groups.items()} - # Install a console-control signal handler on Windows. if win32api is not None: def console_ctrl_handler(type): diff --git a/utils/lit/tests/Inputs/max-failures/lit.cfg b/utils/lit/tests/Inputs/max-failures/lit.cfg new file mode 100644 index 000000000000..50d07566e1cc --- /dev/null +++ b/utils/lit/tests/Inputs/max-failures/lit.cfg @@ -0,0 +1,6 @@ +import lit.formats +config.name = 'shtest-shell' +config.suffixes = ['.txt'] +config.test_format = lit.formats.ShTest() +config.test_source_root = os.path.dirname(__file__) + '/../shtest-shell' +config.test_exec_root = None diff --git a/utils/lit/tests/max-failures.py b/utils/lit/tests/max-failures.py index 5cc258dd08aa..bc58e9a4e47f 100644 --- a/utils/lit/tests/max-failures.py +++ b/utils/lit/tests/max-failures.py @@ -1,9 +1,9 @@ # Check the behavior of --max-failures option. # -# RUN: not %{lit} -j 1 -v %{inputs}/shtest-shell > %t.out -# RUN: not %{lit} --max-failures=1 -j 1 -v %{inputs}/shtest-shell >> %t.out -# RUN: not %{lit} --max-failures=2 -j 1 -v %{inputs}/shtest-shell >> %t.out -# RUN: not %{lit} --max-failures=0 -j 1 -v %{inputs}/shtest-shell 2>> %t.out +# RUN: not %{lit} -j 1 -v %{inputs}/max-failures > %t.out +# RUN: not %{lit} --max-failures=1 -j 1 -v %{inputs}/max-failures >> %t.out +# RUN: not %{lit} --max-failures=2 -j 1 -v %{inputs}/max-failures >> %t.out +# RUN: not %{lit} --max-failures=0 -j 1 -v %{inputs}/max-failures 2>> %t.out # RUN: FileCheck < %t.out %s # # END. diff --git a/utils/lit/tests/selecting.py b/utils/lit/tests/selecting.py index 19ba240f9b0f..4a0d08b860b8 100644 --- a/utils/lit/tests/selecting.py +++ b/utils/lit/tests/selecting.py @@ -9,7 +9,7 @@ # Check that regex-filtering based on environment variables work. # -# RUN: LIT_FILTER='o[a-z]e' %{lit} %{inputs}/discovery | FileCheck --check-prefix=CHECK-FILTER-ENV %s +# RUN: env LIT_FILTER='o[a-z]e' %{lit} %{inputs}/discovery | FileCheck --check-prefix=CHECK-FILTER-ENV %s # CHECK-FILTER-ENV: Testing: 2 of 5 tests diff --git a/utils/release/test-release.sh b/utils/release/test-release.sh index 02d8e7925f6e..66a2c578083e 100755 --- a/utils/release/test-release.sh +++ b/utils/release/test-release.sh @@ -403,14 +403,6 @@ function test_llvmCore() { fi if [ $do_test_suite = 'yes' ]; then - SandboxDir="$BuildDir/sandbox" - Lit=$SandboxDir/bin/lit - TestSuiteBuildDir="$BuildDir/test-suite-build" - TestSuiteSrcDir="$BuildDir/test-suite.src" - - virtualenv $SandboxDir - $SandboxDir/bin/python $BuildDir/llvm.src/utils/lit/setup.py install - mkdir -p $TestSuiteBuildDir cd $TestSuiteBuildDir env CC="$c_compiler" CXX="$cxx_compiler" \ cmake $TestSuiteSrcDir -DTEST_SUITE_LIT=$Lit @@ -466,6 +458,19 @@ if [ "$do_checkout" = "yes" ]; then export_sources fi +# Setup the test-suite. Do this early so we can catch failures before +# we do the full 3 stage build. +if [ $do_test_suite = "yes" ]; then + SandboxDir="$BuildDir/sandbox" + Lit=$SandboxDir/bin/lit + TestSuiteBuildDir="$BuildDir/test-suite-build" + TestSuiteSrcDir="$BuildDir/test-suite.src" + + virtualenv $SandboxDir + $SandboxDir/bin/python $BuildDir/llvm.src/utils/lit/setup.py install + mkdir -p $TestSuiteBuildDir +fi + ( Flavors="Release" if [ "$do_debug" = "yes" ]; then |
