summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Grundy <michael.grundy@10gen.com>2016-04-28 14:11:49 -0400
committerMike Grundy <michael.grundy@10gen.com>2016-05-10 09:51:17 -0400
commit686bd5e0aba3716f093ee9b6f9d8c67f2faef3d9 (patch)
tree92434d0615dec7bebbb264cb56221aa4b416d72a
parent6218a59683bf97c6cb7f198f9d9eccc0371f8bb7 (diff)
downloadmongo-686bd5e0aba3716f093ee9b6f9d8c67f2faef3d9.tar.gz
SERVER-21841 Add mode to resmoke.py to list under what suites a test runs
-rwxr-xr-xbuildscripts/resmoke.py23
-rw-r--r--buildscripts/resmokelib/config.py10
-rw-r--r--buildscripts/resmokelib/parser.py33
-rw-r--r--buildscripts/resmokelib/selector.py10
4 files changed, 74 insertions, 2 deletions
diff --git a/buildscripts/resmoke.py b/buildscripts/resmoke.py
index a6cb03cb620..8afa1d5e77c 100755
--- a/buildscripts/resmoke.py
+++ b/buildscripts/resmoke.py
@@ -115,6 +115,20 @@ def _dump_suite_config(suite, logging_config):
return "\n".join(sb)
+def find_suites_by_test(suites):
+ """
+ Looks up what other resmoke suites run the tests specified in the suites
+ parameter. Returns a dict keyed by test name, value is array of suite names.
+ """
+
+ memberships = {}
+ test_membership = resmokelib.parser.create_test_membership_map()
+ for suite in suites:
+ for group in suite.test_groups:
+ for test in group.tests:
+ memberships[test] = test_membership[test]
+ return memberships
+
def _write_report_file(suites, pathname):
"""
Writes the report.json file if requested.
@@ -151,6 +165,15 @@ def main():
interrupted = False
suites = resmokelib.parser.get_suites(values, args)
+
+ # Run the suite finder after the test suite parsing is complete.
+ if values.find_suites:
+ suites_by_test = find_suites_by_test(suites)
+ for test in sorted(suites_by_test):
+ suite_names = suites_by_test[test]
+ resmoke_logger.info("%s will be run by the following suite(s): %s", test, suite_names)
+ sys.exit(0)
+
try:
for suite in suites:
resmoke_logger.info(_dump_suite_config(suite, logging_config))
diff --git a/buildscripts/resmokelib/config.py b/buildscripts/resmokelib/config.py
index d19ca0181df..950a0f8ffa2 100644
--- a/buildscripts/resmokelib/config.py
+++ b/buildscripts/resmokelib/config.py
@@ -170,3 +170,13 @@ WT_INDEX_CONFIG = None
# Default sort order for test execution. Will only be changed if --suites wasn't specified.
ORDER_TESTS_BY_NAME = True
+
+# Default file names for externally generated lists of tests created during the build.
+DEFAULT_UNIT_TEST_LIST = "build/unittests.txt"
+DEFAULT_INTEGRATION_TEST_LIST = "build/integration_tests.txt"
+
+# External files or executables, used as suite selectors, that are created during the build and
+# therefore might not be available when creating a test membership map.
+EXTERNAL_SUITE_SELECTORS = [DEFAULT_UNIT_TEST_LIST,
+ DEFAULT_INTEGRATION_TEST_LIST,
+ DEFAULT_DBTEST_EXECUTABLE]
diff --git a/buildscripts/resmokelib/parser.py b/buildscripts/resmokelib/parser.py
index c170e4c218d..9966fff46c6 100644
--- a/buildscripts/resmokelib/parser.py
+++ b/buildscripts/resmokelib/parser.py
@@ -4,6 +4,7 @@ Parser for command line arguments.
from __future__ import absolute_import
+import collections
import os
import os.path
import optparse
@@ -102,6 +103,9 @@ def parse_command_line():
help=("Comma separated list of tags. Any jstest that contains any of the"
" specified tags will be excluded from any suites that are run."))
+ parser.add_option("-f", "--findSuites", action="store_true", dest="find_suites",
+ help="List the names of the suites that will execute the specified tests.")
+
parser.add_option("--includeWithAllTags", dest="include_with_all_tags", metavar="TAG1,TAG2",
help=("Comma separated list of tags. For the jstest portion of the suite(s),"
" only tests which have all of the specified tags will be run."))
@@ -195,6 +199,7 @@ def parse_command_line():
parser.set_defaults(executor_file="with_server",
logger_file="console",
dry_run="off",
+ find_suites=False,
list_suites=False,
prealloc_journal="off")
@@ -252,6 +257,34 @@ def update_config_vars(values):
raise optparse.OptionValueError("Unknown option(s): %s" % (config.keys()))
+def create_test_membership_map(fail_on_missing_selector=False):
+ """
+ Returns a dict keyed by test name containing all of the suites that will run that test.
+ 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)
+ suite = testing.suite.Suite(suite_name, suite_config)
+ except IOError as err:
+ # If unittests.txt or integration_tests.txt aren't there we'll ignore the error because
+ # unittests haven't been built yet (this is highly likely using find interactively).
+ if err.filename in _config.EXTERNAL_SUITE_SELECTORS:
+ if not fail_on_missing_selector:
+ continue
+ raise
+
+ for group in suite.test_groups:
+ for testfile in group.tests:
+ if isinstance(testfile, dict):
+ continue
+ test_membership[testfile].append(suite_name)
+ return test_membership
+
+
def get_suites(values, args):
if (values.suite_files is None and not args) or (values.suite_files is not None and args):
raise optparse.OptionValueError("Must specify either --suites or a list of tests")
diff --git a/buildscripts/resmokelib/selector.py b/buildscripts/resmokelib/selector.py
index c2dc0fca41b..be9359b5d28 100644
--- a/buildscripts/resmokelib/selector.py
+++ b/buildscripts/resmokelib/selector.py
@@ -7,6 +7,7 @@ on whether they apply to C++ unit tests, dbtests, or JS tests.
from __future__ import absolute_import
+import errno
import fnmatch
import os.path
import subprocess
@@ -43,14 +44,16 @@ def _filter_cpp_tests(kind, root, include_files, exclude_files):
return list(remaining)
return tests
-def filter_cpp_unit_tests(root="build/unittests.txt", include_files=None, exclude_files=None):
+def filter_cpp_unit_tests(root=config.DEFAULT_UNIT_TEST_LIST,
+ include_files=None,
+ exclude_files=None):
"""
Filters out what C++ unit tests to run.
"""
return _filter_cpp_tests("C++ unit test", root, include_files, exclude_files)
-def filter_cpp_integration_tests(root="build/integration_tests.txt",
+def filter_cpp_integration_tests(root=config.DEFAULT_INTEGRATION_TEST_LIST,
include_files=None,
exclude_files=None):
"""
@@ -78,6 +81,9 @@ def filter_dbtests(binary=None, include_suites=None):
if sys.platform == "win32" and os.path.splitext(binary)[1] != ".exe":
binary += ".exe"
+ if not os.path.isfile(binary):
+ raise IOError(errno.ENOENT, "File not found", binary)
+
program = subprocess.Popen([binary, "--list"], stdout=subprocess.PIPE)
stdout = program.communicate()[0]