summaryrefslogtreecommitdiff
path: root/src/mongo/gotools/test/qa-tests/buildscripts/resmoke.py
diff options
context:
space:
mode:
authorRamon Fernandez <ramon@mongodb.com>2016-08-25 16:34:34 -0400
committerRamon Fernandez <ramon@mongodb.com>2016-08-25 16:54:18 -0400
commitc330c9991ab45e7d0685d53e699ef26dba065660 (patch)
tree3dc5cd06b5f6c7eaaa4cb20cbe763504c14a772b /src/mongo/gotools/test/qa-tests/buildscripts/resmoke.py
parenteb62b862d5ebf179a1bcd9f394070e69c30188ab (diff)
downloadmongo-c330c9991ab45e7d0685d53e699ef26dba065660.tar.gz
Import tools: 5b883d86fdb4df55036d5dba2ca6f9dfa0750b44 from branch v3.3
ref: 1ac1389bda..5b883d86fd for: 3.3.12 SERVER-25814 Initial vendor import: tools
Diffstat (limited to 'src/mongo/gotools/test/qa-tests/buildscripts/resmoke.py')
-rwxr-xr-xsrc/mongo/gotools/test/qa-tests/buildscripts/resmoke.py216
1 files changed, 216 insertions, 0 deletions
diff --git a/src/mongo/gotools/test/qa-tests/buildscripts/resmoke.py b/src/mongo/gotools/test/qa-tests/buildscripts/resmoke.py
new file mode 100755
index 00000000000..a6cb03cb620
--- /dev/null
+++ b/src/mongo/gotools/test/qa-tests/buildscripts/resmoke.py
@@ -0,0 +1,216 @@
+#!/usr/bin/env python
+
+"""
+Command line utility for executing MongoDB tests of all kinds.
+"""
+
+from __future__ import absolute_import
+
+import json
+import os.path
+import random
+import signal
+import sys
+import time
+import traceback
+
+# Get relative imports to work when the package is not installed on the PYTHONPATH.
+if __name__ == "__main__" and __package__ is None:
+ sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+ from buildscripts import resmokelib
+
+
+def _execute_suite(suite, logging_config):
+ """
+ Executes each test group of 'suite', failing fast if requested.
+
+ Returns true if the execution of the suite was interrupted by the
+ user, and false otherwise.
+ """
+
+ logger = resmokelib.logging.loggers.EXECUTOR
+
+ for group in suite.test_groups:
+ if resmokelib.config.SHUFFLE:
+ logger.info("Shuffling order of tests for %ss in suite %s. The seed is %d.",
+ group.test_kind, suite.get_name(), resmokelib.config.RANDOM_SEED)
+ random.seed(resmokelib.config.RANDOM_SEED)
+ random.shuffle(group.tests)
+
+ if resmokelib.config.DRY_RUN == "tests":
+ sb = []
+ sb.append("Tests that would be run for %ss in suite %s:"
+ % (group.test_kind, suite.get_name()))
+ if len(group.tests) > 0:
+ for test in group.tests:
+ sb.append(test)
+ else:
+ sb.append("(no tests)")
+ logger.info("\n".join(sb))
+
+ # Set a successful return code on the test group because we want to output the tests
+ # that would get run by any other suites the user specified.
+ group.return_code = 0
+ continue
+
+ if len(group.tests) == 0:
+ logger.info("Skipping %ss, no tests to run", group.test_kind)
+ continue
+
+ group_config = suite.get_executor_config().get(group.test_kind, {})
+ executor = resmokelib.testing.executor.TestGroupExecutor(logger,
+ group,
+ logging_config,
+ **group_config)
+
+ try:
+ executor.run()
+ if resmokelib.config.FAIL_FAST and group.return_code != 0:
+ suite.return_code = group.return_code
+ return False
+ except resmokelib.errors.UserInterrupt:
+ suite.return_code = 130 # Simulate SIGINT as exit code.
+ return True
+ except:
+ logger.exception("Encountered an error when running %ss of suite %s.",
+ group.test_kind, suite.get_name())
+ suite.return_code = 2
+ return False
+
+
+def _log_summary(logger, suites, time_taken):
+ if len(suites) > 1:
+ sb = []
+ sb.append("Summary of all suites: %d suites ran in %0.2f seconds"
+ % (len(suites), time_taken))
+ for suite in suites:
+ suite_sb = []
+ suite.summarize(suite_sb)
+ sb.append(" %s: %s" % (suite.get_name(), "\n ".join(suite_sb)))
+
+ logger.info("=" * 80)
+ logger.info("\n".join(sb))
+
+
+def _summarize_suite(suite):
+ sb = []
+ suite.summarize(sb)
+ return "\n".join(sb)
+
+
+def _dump_suite_config(suite, logging_config):
+ """
+ Returns a string that represents the YAML configuration of a suite.
+
+ TODO: include the "options" key in the result
+ """
+
+ sb = []
+ sb.append("YAML configuration of suite %s" % (suite.get_name()))
+ sb.append(resmokelib.utils.dump_yaml({"selector": suite.get_selector_config()}))
+ sb.append("")
+ sb.append(resmokelib.utils.dump_yaml({"executor": suite.get_executor_config()}))
+ sb.append("")
+ sb.append(resmokelib.utils.dump_yaml({"logging": logging_config}))
+ return "\n".join(sb)
+
+
+def _write_report_file(suites, pathname):
+ """
+ Writes the report.json file if requested.
+ """
+
+ reports = []
+ for suite in suites:
+ for group in suite.test_groups:
+ reports.extend(group.get_reports())
+
+ combined_report_dict = resmokelib.testing.report.TestReport.combine(*reports).as_dict()
+ with open(pathname, "w") as fp:
+ json.dump(combined_report_dict, fp)
+
+
+def main():
+ start_time = time.time()
+
+ values, args = resmokelib.parser.parse_command_line()
+
+ logging_config = resmokelib.parser.get_logging_config(values)
+ resmokelib.logging.config.apply_config(logging_config)
+ resmokelib.logging.flush.start_thread()
+
+ resmokelib.parser.update_config_vars(values)
+
+ exec_logger = resmokelib.logging.loggers.EXECUTOR
+ resmoke_logger = resmokelib.logging.loggers.new_logger("resmoke", parent=exec_logger)
+
+ if values.list_suites:
+ suite_names = resmokelib.parser.get_named_suites()
+ resmoke_logger.info("Suites available to execute:\n%s", "\n".join(suite_names))
+ sys.exit(0)
+
+ interrupted = False
+ suites = resmokelib.parser.get_suites(values, args)
+ try:
+ for suite in suites:
+ resmoke_logger.info(_dump_suite_config(suite, logging_config))
+
+ suite.record_start()
+ interrupted = _execute_suite(suite, logging_config)
+ suite.record_end()
+
+ resmoke_logger.info("=" * 80)
+ resmoke_logger.info("Summary of %s suite: %s",
+ suite.get_name(), _summarize_suite(suite))
+
+ if interrupted or (resmokelib.config.FAIL_FAST and suite.return_code != 0):
+ time_taken = time.time() - start_time
+ _log_summary(resmoke_logger, suites, time_taken)
+ sys.exit(suite.return_code)
+
+ time_taken = time.time() - start_time
+ _log_summary(resmoke_logger, suites, time_taken)
+
+ # Exit with a nonzero code if any of the suites failed.
+ exit_code = max(suite.return_code for suite in suites)
+ sys.exit(exit_code)
+ finally:
+ if not interrupted:
+ resmokelib.logging.flush.stop_thread()
+
+ if resmokelib.config.REPORT_FILE is not None:
+ _write_report_file(suites, resmokelib.config.REPORT_FILE)
+
+
+if __name__ == "__main__":
+
+ def _dump_stacks(signum, frame):
+ """
+ Signal handler that will dump the stacks of all threads.
+ """
+
+ header_msg = "Dumping stacks due to SIGUSR1 signal"
+
+ sb = []
+ sb.append("=" * len(header_msg))
+ sb.append(header_msg)
+ sb.append("=" * len(header_msg))
+
+ frames = sys._current_frames()
+ sb.append("Total threads: %d" % (len(frames)))
+ sb.append("")
+
+ for thread_id in frames:
+ stack = frames[thread_id]
+ sb.append("Thread %d:" % (thread_id))
+ sb.append("".join(traceback.format_stack(stack)))
+
+ sb.append("=" * len(header_msg))
+ print "\n".join(sb)
+
+ try:
+ signal.signal(signal.SIGUSR1, _dump_stacks)
+ except AttributeError:
+ print "Cannot catch signals on Windows"
+
+ main()