Index: llvm/utils/lit/lit/LitConfig.py =================================================================== --- llvm/utils/lit/lit/LitConfig.py +++ llvm/utils/lit/lit/LitConfig.py @@ -67,6 +67,28 @@ self.parallelism_groups = parallelism_groups self.echo_all_commands = echo_all_commands + self._suite_setup_callbacks = [] + self._suite_teardown_callbacks = [] + + def __getstate__(self): + # An instance of LitConfig may be shared between multiple processes + # when using parallelism, which requires pickling that instance. + # However, pickling function objects is not always possible (or, in this + # case, always impossible), so we remove the callbacks from + # pickled instances. + # This is okay, because we only set them and run them in the parent + # lit.py process. Accessing them from subprocesses would be weird, + # so it's not supported. + state = dict(self.__dict__) + del state['_suite_setup_callbacks'] + del state['_suite_teardown_callbacks'] + return state + + def __setstate__(self, state): + self.__dict__.update(state) + self._suite_setup_callbacks = [] + self._suite_teardown_callbacks = [] + @property def maxIndividualTestTime(self): """ @@ -159,6 +181,42 @@ self.bashPath = '' return dir + + def suite_setup(self, callback): + ''' + Adds the callback to the list of setup callbacks that will be run + before running the test suite. + + Can be used as a decorator in lit configuration files like this: + + @lit_config.suite_setup + def setup(): + ... + ''' + self._suite_setup_callbacks.append(callback) + return callback + + def suite_teardown(self, callback): + ''' + Adds the callback to the list of teardown callbacks that will be run + after the test suite completes. + + Can be used as a decorator in lit configuration files like this: + + @lit_config.suite_teardown + def teardown(): + ... + ''' + self._suite_teardown_callbacks.append(callback) + return callback + + def run_suite_setup_callbacks(self): + for callback in self._suite_setup_callbacks: + callback() + + def run_suite_teardown_callbacks(self): + for callback in self._suite_teardown_callbacks: + callback() def _write_message(self, kind, message): # Get the file/line where this message was generated. Index: llvm/utils/lit/lit/run.py =================================================================== --- llvm/utils/lit/lit/run.py +++ llvm/utils/lit/lit/run.py @@ -58,12 +58,19 @@ timeout = self.timeout or one_week deadline = time.time() + timeout - self._execute(deadline) + try: + self.lit_config.run_suite_setup_callbacks() + self._execute(deadline) + finally: + self.lit_config.run_suite_teardown_callbacks() # Mark any tests that weren't run as UNRESOLVED. for test in self.tests: if test.result is None: test.setResult(lit.Test.Result(lit.Test.UNRESOLVED, '', 0.0)) + + def _execute(self, deadline): + raise NotImplementedError("Should be implemented in a subclass") # TODO(yln): as the comment says.. this is racing with the main thread waiting # for results Index: llvm/utils/lit/tests/Inputs/setup-teardown/lit.cfg =================================================================== --- /dev/null +++ llvm/utils/lit/tests/Inputs/setup-teardown/lit.cfg @@ -0,0 +1,14 @@ +import lit.formats +config.name = 'setup-teardown' +config.suffixes = ['.txt'] +config.test_format = lit.formats.ShTest() +config.test_source_root = None +config.test_exec_root = None + +@lit_config.suite_setup +def setup(): + print("Running setup code...") + +@lit_config.suite_teardown +def teardown(): + print("Running teardown code...") Index: llvm/utils/lit/tests/Inputs/setup-teardown/test1.txt =================================================================== --- /dev/null +++ llvm/utils/lit/tests/Inputs/setup-teardown/test1.txt @@ -0,0 +1 @@ +# RUN: true Index: llvm/utils/lit/tests/Inputs/setup-teardown/test2.txt =================================================================== --- /dev/null +++ llvm/utils/lit/tests/Inputs/setup-teardown/test2.txt @@ -0,0 +1 @@ +# RUN: false Index: llvm/utils/lit/tests/setup-teardown.py =================================================================== --- /dev/null +++ llvm/utils/lit/tests/setup-teardown.py @@ -0,0 +1,9 @@ +# RUN: not %{lit} -j1 %{inputs}/setup-teardown | FileCheck %s + +# CHECK: -- Testing: 2 tests, 1 workers -- +# CHECK: Running setup code... +# CHECK: PASS: setup-teardown :: test1.txt +# CHECK: FAIL: setup-teardown :: test2.txt +# CHECK: Running teardown code... +# CHECK: Expected Passes : 1 +# CHECK: Unexpected Failures: 1