From 796a9f1504ea088bca412b8af787b735943245cf Mon Sep 17 00:00:00 2001 From: Robert Guo Date: Tue, 15 Jun 2021 17:51:01 -0400 Subject: SERVER-57439 add unittest task with undodb recordings to ! RHEL 8 --- .../resmokelib/testing/testcases/cpp_unittest.py | 24 ++++++++++++++++++++++ .../resmokelib/testing/testcases/interface.py | 16 ++++++++++++--- .../resmokelib/testing/testcases/jstest.py | 15 ++++++++++---- 3 files changed, 48 insertions(+), 7 deletions(-) (limited to 'buildscripts/resmokelib/testing') diff --git a/buildscripts/resmokelib/testing/testcases/cpp_unittest.py b/buildscripts/resmokelib/testing/testcases/cpp_unittest.py index 08b4a7e0cbd..9162bce16c9 100644 --- a/buildscripts/resmokelib/testing/testcases/cpp_unittest.py +++ b/buildscripts/resmokelib/testing/testcases/cpp_unittest.py @@ -1,5 +1,7 @@ """The unittest.TestCase for C++ unit tests.""" +import os +from buildscripts.resmokelib import config from buildscripts.resmokelib import core from buildscripts.resmokelib import utils from buildscripts.resmokelib.testing.testcases import interface @@ -18,6 +20,28 @@ class CPPUnitTestCase(interface.ProcessTestCase): self.program_executable = program_executable self.program_options = utils.default_if_none(program_options, {}).copy() + def run_test(self): + """Run the test.""" + try: + super().run_test() + except self.failureException: + if config.UNDO_RECORDER_PATH: + # Record the list of failed tests so we can upload them to the Evergreen task. + # Non-recorded tests rely on the core dump content to identify the test binaries. + with open("failed_recorded_tests.txt", 'a') as failure_list: + failure_list.write(self.program_executable) + failure_list.write("\n") + self.logger.exception( + "*** Failed test run was recorded. ***\n" + "For instructions on using the recording instead of core dumps, see\n" + "https://wiki.corp.mongodb.com/display/COREENG/Time+Travel+Debugging+in+MongoDB\n" + "For questions or bug reports, please reach our in #server-testing") + + # Archive any available recordings if there's any failure. It's possible a problem + # with the recorder will cause no recordings to be generated. + self._cull_recordings(os.path.basename(self.program_executable)) + raise + def _make_process(self): self.program_options["job_num"] = self.fixture.job_num self.program_options["test_id"] = self._id diff --git a/buildscripts/resmokelib/testing/testcases/interface.py b/buildscripts/resmokelib/testing/testcases/interface.py index 474ddb2ae01..67733e74737 100644 --- a/buildscripts/resmokelib/testing/testcases/interface.py +++ b/buildscripts/resmokelib/testing/testcases/interface.py @@ -2,12 +2,13 @@ This is used to perform the actual test case. """ - +import glob import os import os.path import unittest import uuid +from buildscripts.resmokelib import config from buildscripts.resmokelib import logging from buildscripts.resmokelib.utils import registry @@ -116,8 +117,8 @@ class ProcessTestCase(TestCase): # pylint: disable=abstract-method def run_test(self): """Run the test.""" try: - shell = self._make_process() - self._execute(shell) + proc = self._make_process() + self._execute(proc) except self.failureException: raise except: @@ -145,3 +146,12 @@ class ProcessTestCase(TestCase): # pylint: disable=abstract-method def _make_process(self): """Return a new Process instance that could be used to run the test or log the command.""" raise NotImplementedError("_make_process must be implemented by TestCase subclasses") + + def _cull_recordings(self, program_executable): + """Move recordings if test fails so it doesn't get deleted.""" + # Only store my recordings. Concurrent processes may generate their own recordings that we + # should ignore. There's a problem with duplicate program names under different directories + # But that should be rare and there's no harm in having more recordings stored. + for recording in glob.glob(program_executable + "*.undo"): + self.logger.info("Keeping recording %s", recording) + os.rename(recording, recording + '.tokeep') diff --git a/buildscripts/resmokelib/testing/testcases/jstest.py b/buildscripts/resmokelib/testing/testcases/jstest.py index b2ab85df514..f6ae1033e94 100644 --- a/buildscripts/resmokelib/testing/testcases/jstest.py +++ b/buildscripts/resmokelib/testing/testcases/jstest.py @@ -230,10 +230,17 @@ class JSTestCase(interface.ProcessTestCase): def run_test(self): """Execute the test.""" - if self.num_clients == 1: - self._run_single_copy() - else: - self._run_multiple_copies() + try: + if self.num_clients == 1: + self._run_single_copy() + else: + self._run_multiple_copies() + except: + # Archive any available recordings if there's any failure. It's possible a problem + # with the recorder will cause no recordings to be generated. There will also be + # recordings of other processes, we keep them to avoid complicating this code. + self._cull_recordings("mongo") + raise def _raise_if_unsafe_exit(self, return_code): """Determine if a return code represents and unsafe exit.""" -- cgit v1.2.1