diff options
author | Yves Duhem <yves.duhem@mongodb.com> | 2018-02-23 18:22:33 -0500 |
---|---|---|
committer | Yves Duhem <yves.duhem@mongodb.com> | 2018-02-23 18:23:48 -0500 |
commit | 649502fd5942d5a572c6a55cfbca61ce1c9611d0 (patch) | |
tree | 4428c847c6c2b4a97d11e0bea2d7fe0cd7c2cb87 | |
parent | a430d6886290129605dde5ed86589dffb84345e1 (diff) | |
download | mongo-649502fd5942d5a572c6a55cfbca61ce1c9611d0.tar.gz |
SERVER-33397 New suitesconfig module
-rw-r--r-- | buildscripts/burn_in_tests.py | 8 | ||||
-rwxr-xr-x | buildscripts/resmoke.py | 8 | ||||
-rw-r--r-- | buildscripts/resmokelib/__init__.py | 2 | ||||
-rw-r--r-- | buildscripts/resmokelib/parser.py | 106 | ||||
-rw-r--r-- | buildscripts/resmokelib/suitesconfig.py | 114 | ||||
-rwxr-xr-x | buildscripts/update_test_lifecycle.py | 2 |
6 files changed, 131 insertions, 109 deletions
diff --git a/buildscripts/burn_in_tests.py b/buildscripts/burn_in_tests.py index 69cf37e0f38..fa37a810190 100644 --- a/buildscripts/burn_in_tests.py +++ b/buildscripts/burn_in_tests.py @@ -243,7 +243,7 @@ def find_tests_by_executor(suites): """ memberships = {} - test_membership = resmokelib.parser.create_test_membership_map() + test_membership = resmokelib.suitesconfig.create_test_membership_map() for suite in suites: for test in suite.tests: memberships[test] = test_membership[test] @@ -258,7 +258,7 @@ def create_executor_list(suites, exclude_suites): """ memberships = collections.defaultdict(list) - test_membership = resmokelib.parser.create_test_membership_map() + test_membership = resmokelib.suitesconfig.create_test_membership_map() for suite in suites: for test in suite.tests: for executor in set(test_membership[test]) - set(exclude_suites): @@ -384,7 +384,9 @@ def main(): if values.test_list_outfile is not None: _write_report_file({}, values.test_list_outfile) sys.exit(0) - suites = resmokelib.parser.get_suites(values, changed_tests) + suites = resmokelib.suitesconfig.get_suites( + suite_files=values.suite_files.split(","), + test_files=changed_tests) tests_by_executor = create_executor_list(suites, exclude_suites) tests_by_task = create_task_list(evergreen_conf, values.buildvariant, diff --git a/buildscripts/resmoke.py b/buildscripts/resmoke.py index fcf067ae7f1..4e59bc183a0 100755 --- a/buildscripts/resmoke.py +++ b/buildscripts/resmoke.py @@ -134,7 +134,7 @@ def find_suites_by_test(suites): """ memberships = {} - test_membership = resmokelib.parser.create_test_membership_map() + test_membership = resmokelib.suitesconfig.create_test_membership_map() for suite in suites: for test in suite.tests: memberships[test] = test_membership[test] @@ -142,7 +142,7 @@ def find_suites_by_test(suites): def _list_suites_and_exit(logger, exit_code=0): - suite_names = resmokelib.parser.get_named_suites() + suite_names = resmokelib.suitesconfig.get_named_suites() logger.info("Suites available to execute:\n%s", "\n".join(suite_names)) sys.exit(exit_code) @@ -168,7 +168,9 @@ class Main(object): Returns a list of resmokelib.testing.suite.Suite instances to execute. """ - return resmokelib.parser.get_suites(self.__values, self.__args) + return resmokelib.suitesconfig.get_suites( + suite_files=self.__values.suite_files.split(","), + test_files=self.__args) def run(self): """ diff --git a/buildscripts/resmokelib/__init__.py b/buildscripts/resmokelib/__init__.py index d8019dcf404..abebdc3c665 100644 --- a/buildscripts/resmokelib/__init__.py +++ b/buildscripts/resmokelib/__init__.py @@ -1,9 +1,11 @@ from __future__ import absolute_import +from . import config from . import errors from . import logging from . import parser from . import reportfile from . import sighandler +from . import suitesconfig from . import testing from . import utils diff --git a/buildscripts/resmokelib/parser.py b/buildscripts/resmokelib/parser.py index b300d573daf..b51dc239f35 100644 --- a/buildscripts/resmokelib/parser.py +++ b/buildscripts/resmokelib/parser.py @@ -4,14 +4,11 @@ Parser for command line arguments. from __future__ import absolute_import -import collections import os import os.path import optparse from . import config as _config -from . import errors -from . import testing from . import utils from .. import resmokeconfig @@ -141,7 +138,7 @@ def parse_command_line(): " run.")) parser.add_option("-n", action="store_const", const="tests", dest="dry_run", - help=("Outputs the tests that would be run.")) + help="Outputs the tests that would be run.") # TODO: add support for --dryRun=commands parser.add_option("--dryRun", type="choice", action="store", dest="dry_run", @@ -336,7 +333,7 @@ def validate_options(parser, options, args): if options.executor_file: parser.error("--executor is superseded by --suites; specify --suites={} {} to run the" - "test(s) under those suite configuration(s)" + " test(s) under those suite configuration(s)" .format(options.executor_file, " ".join(args))) @@ -424,75 +421,6 @@ def update_config_vars(values): raise optparse.OptionValueError("Unknown option(s): %s" % (config.keys())) -def create_test_membership_map(fail_on_missing_selector=False, test_kind=None): - """ - Returns a dict keyed by test name containing all of the suites that will run that test. - - If 'test_kind' is specified then only the mappings for that kind are returned. - Since this iterates through every available suite, it should only be run once. - """ - - test_membership = collections.defaultdict(list) - suite_names = get_named_suites() - for suite_name in suite_names: - try: - suite_config = _get_suite_config(suite_name) - if test_kind and suite_config.get("test_kind") != test_kind: - continue - suite = testing.suite.Suite(suite_name, suite_config) - except IOError as err: - # We ignore errors from missing files referenced in the test suite's "selector" - # section. Certain test suites (e.g. unittests.yml) have a dedicated text file to - # capture the list of tests they run; the text file may not be available if the - # associated SCons target hasn't been built yet. - if err.filename in _config.EXTERNAL_SUITE_SELECTORS: - if not fail_on_missing_selector: - continue - raise - - for testfile in suite.tests: - if isinstance(testfile, dict): - continue - test_membership[testfile].append(suite_name) - return test_membership - - -def get_suites(values, args): - suite_roots = None - if args: - # Do not change the execution order of the tests passed as args, unless a tag option is - # specified. If an option is specified, then sort the tests for consistent execution order. - _config.ORDER_TESTS_BY_NAME = any(tag_filter is not None for - tag_filter in (_config.EXCLUDE_WITH_ANY_TAGS, - _config.INCLUDE_WITH_ANY_TAGS)) - # Build configuration for list of files to run. - suite_roots = _get_suite_roots(args) - - suite_files = values.suite_files.split(",") - - suites = [] - for suite_filename in suite_files: - suite_config = _get_suite_config(suite_filename) - if suite_roots: - # Override the suite's default test files with those passed in from the command line. - suite_config.update(suite_roots) - suite = testing.suite.Suite(suite_filename, suite_config) - suites.append(suite) - return suites - - -def get_named_suites(): - """ - Returns the list of suites available to execute. - """ - - # Skip "with_*server" and "no_server" because they do not define any test files to run. - executor_only = set(["with_server", "with_external_server", "no_server"]) - suite_names = [suite for suite in resmokeconfig.NAMED_SUITES if suite not in executor_only] - suite_names.sort() - return suite_names - - def _get_logging_config(pathname): """ Attempts to read a YAML configuration from 'pathname' that describes @@ -502,11 +430,11 @@ def _get_logging_config(pathname): # Named loggers are specified as the basename of the file, without the .yml extension. if not utils.is_yaml_file(pathname) and not os.path.dirname(pathname): if pathname not in resmokeconfig.NAMED_LOGGERS: - raise optparse.OptionValueError("Unknown logger '%s'" % (pathname)) + raise optparse.OptionValueError("Unknown logger '%s'" % pathname) pathname = resmokeconfig.NAMED_LOGGERS[pathname] # Expand 'pathname' to full path. if not utils.is_yaml_file(pathname) or not os.path.isfile(pathname): - raise optparse.OptionValueError("Expected a logger YAML config, but got '%s'" % (pathname)) + raise optparse.OptionValueError("Expected a logger YAML config, but got '%s'" % pathname) return utils.load_yaml_file(pathname).pop("logging") @@ -523,32 +451,6 @@ def _get_options_config(pathname): return utils.load_yaml_file(pathname).pop("options") -def _get_suite_config(pathname): - """ - Attempts to read a YAML configuration from 'pathname' that describes - what tests to run and how to run them. - """ - return _get_yaml_config("suite", pathname) - - -def _get_suite_roots(files): - return {"selector": {"roots": files}} - - -def _get_yaml_config(kind, pathname): - # Named executors or suites are specified as the basename of the file, without the .yml - # extension. - if not utils.is_yaml_file(pathname) and not os.path.dirname(pathname): - if pathname not in resmokeconfig.NAMED_SUITES: - raise errors.SuiteNotFound("Unknown %s '%s'" % (kind, pathname)) - pathname = resmokeconfig.NAMED_SUITES[pathname] # Expand 'pathname' to full path. - - if not utils.is_yaml_file(pathname) or not os.path.isfile(pathname): - raise optparse.OptionValueError("Expected a %s YAML config, but got '%s'" - % (kind, pathname)) - return utils.load_yaml_file(pathname) - - def _expand_user(pathname): """ Wrapper around os.path.expanduser() to do nothing when given None. diff --git a/buildscripts/resmokelib/suitesconfig.py b/buildscripts/resmokelib/suitesconfig.py new file mode 100644 index 00000000000..dc668035c90 --- /dev/null +++ b/buildscripts/resmokelib/suitesconfig.py @@ -0,0 +1,114 @@ +"""Module for retrieving the configuration of resmoke.py test suites.""" + +from __future__ import absolute_import + +import collections +import optparse +import os + +from . import config as _config +from . import errors +from . import utils +from .testing import suite as _suite +from .. import resmokeconfig + + +def get_named_suites(): + """ + Returns the list of suites available to execute. + """ + + # Skip "with_*server" and "no_server" because they do not define any test files to run. + executor_only = {"with_server", "with_external_server", "no_server"} + suite_names = [suite for suite in resmokeconfig.NAMED_SUITES if suite not in executor_only] + suite_names.sort() + return suite_names + + +def create_test_membership_map(fail_on_missing_selector=False, test_kind=None): + """ + Returns a dict keyed by test name containing all of the suites that will run that test. + + If 'test_kind' is specified then only the mappings for that kind are returned. + Since this iterates through every available suite, it should only be run once. + """ + + test_membership = collections.defaultdict(list) + suite_names = get_named_suites() + for suite_name in suite_names: + try: + suite_config = _get_suite_config(suite_name) + if test_kind and suite_config.get("test_kind") != test_kind: + continue + suite = _suite.Suite(suite_name, suite_config) + except IOError as err: + # We ignore errors from missing files referenced in the test suite's "selector" + # section. Certain test suites (e.g. unittests.yml) have a dedicated text file to + # capture the list of tests they run; the text file may not be available if the + # associated SCons target hasn't been built yet. + if err.filename in _config.EXTERNAL_SUITE_SELECTORS: + if not fail_on_missing_selector: + continue + raise + + for testfile in suite.tests: + if isinstance(testfile, dict): + continue + test_membership[testfile].append(suite_name) + return test_membership + + +def get_suites(suite_files, test_files): + """Retrieves the Suite instances based on suite configuration files and override parameters. + + Args: + suite_files: A list of file paths pointing to suite YAML configuration files. For the suites + defined in 'buildscripts/resmokeconfig/suites/', a shorthand name consisting of the + filename without the extension can be used. + test_files: A list of file paths pointing to test files overriding the roots for the suites. + """ + suite_roots = None + if test_files: + # Do not change the execution order of the tests passed as args, unless a tag option is + # specified. If an option is specified, then sort the tests for consistent execution order. + _config.ORDER_TESTS_BY_NAME = any(tag_filter is not None for + tag_filter in (_config.EXCLUDE_WITH_ANY_TAGS, + _config.INCLUDE_WITH_ANY_TAGS)) + # Build configuration for list of files to run. + suite_roots = _make_suite_roots(test_files) + + suites = [] + for suite_filename in suite_files: + suite_config = _get_suite_config(suite_filename) + if suite_roots: + # Override the suite's default test files with those passed in from the command line. + suite_config.update(suite_roots) + suite = _suite.Suite(suite_filename, suite_config) + suites.append(suite) + return suites + + +def _make_suite_roots(files): + return {"selector": {"roots": files}} + + +def _get_suite_config(pathname): + """ + Attempts to read a YAML configuration from 'pathname' that describes + what tests to run and how to run them. + """ + return _get_yaml_config("suite", pathname) + + +def _get_yaml_config(kind, pathname): + # Named executors or suites are specified as the basename of the file, without the .yml + # extension. + if not utils.is_yaml_file(pathname) and not os.path.dirname(pathname): + if pathname not in resmokeconfig.NAMED_SUITES: + raise errors.SuiteNotFound("Unknown %s '%s'" % (kind, pathname)) + pathname = resmokeconfig.NAMED_SUITES[pathname] # Expand 'pathname' to full path. + + if not utils.is_yaml_file(pathname) or not os.path.isfile(pathname): + raise optparse.OptionValueError("Expected a %s YAML config, but got '%s'" + % (kind, pathname)) + return utils.load_yaml_file(pathname) diff --git a/buildscripts/update_test_lifecycle.py b/buildscripts/update_test_lifecycle.py index fe854bdf70c..a86c7719fc0 100755 --- a/buildscripts/update_test_lifecycle.py +++ b/buildscripts/update_test_lifecycle.py @@ -88,7 +88,7 @@ def get_suite_tasks_membership(evg_conf): def get_test_tasks_membership(evg_conf): """Return a dictionary with keys of all tests and list of associated tasks.""" - test_suites_membership = resmokelib.parser.create_test_membership_map(test_kind="js_test") + test_suites_membership = resmokelib.suitesconfig.create_test_membership_map(test_kind="js_test") suite_tasks_membership = get_suite_tasks_membership(evg_conf) test_tasks_membership = collections.defaultdict(list) for test in test_suites_membership.keys(): |