diff options
Diffstat (limited to 'buildscripts/resmokelib')
6 files changed, 45 insertions, 19 deletions
diff --git a/buildscripts/resmokelib/testing/fixtures/interface.py b/buildscripts/resmokelib/testing/fixtures/interface.py index b9b92a57a71..7eebc5071b4 100644 --- a/buildscripts/resmokelib/testing/fixtures/interface.py +++ b/buildscripts/resmokelib/testing/fixtures/interface.py @@ -65,7 +65,7 @@ class Fixture(object, metaclass=registry.make_registry_metaclass(_FIXTURES)): """Block until the fixture can be used for testing.""" pass - def teardown(self, finished=False): # noqa + def teardown(self, finished=False, kill=False): # noqa """Destroy the fixture. The fixture's logging handlers are closed if 'finished' is true, @@ -76,7 +76,7 @@ class Fixture(object, metaclass=registry.make_registry_metaclass(_FIXTURES)): """ try: - self._do_teardown() + self._do_teardown(kill=kill) finally: if finished: for handler in self.logger.handlers: @@ -84,7 +84,7 @@ class Fixture(object, metaclass=registry.make_registry_metaclass(_FIXTURES)): # want the logs to eventually get flushed. logging.flush.close_later(handler) - def _do_teardown(self): # noqa + def _do_teardown(self, kill=False): # noqa """Destroy the fixture. This method must be implemented by subclasses. @@ -243,7 +243,7 @@ class FixtureTeardownHandler(object): """ return self._message - def teardown(self, fixture, name): # noqa: D406,D407,D411,D413 + def teardown(self, fixture, name, kill=False): # noqa: D406,D407,D411,D413 """Tear down the given fixture and log errors instead of raising a ServerFailure exception. Args: @@ -254,7 +254,7 @@ class FixtureTeardownHandler(object): """ try: self._logger.info("Stopping %s...", name) - fixture.teardown() + fixture.teardown(kill=kill) self._logger.info("Successfully stopped %s.", name) return True except errors.ServerFailure as err: diff --git a/buildscripts/resmokelib/testing/fixtures/replicaset.py b/buildscripts/resmokelib/testing/fixtures/replicaset.py index 8c93ada0b24..7f4851128a2 100644 --- a/buildscripts/resmokelib/testing/fixtures/replicaset.py +++ b/buildscripts/resmokelib/testing/fixtures/replicaset.py @@ -400,7 +400,7 @@ class ReplicaSetFixture(interface.ReplFixture): # pylint: disable=too-many-inst for node in self.nodes: node.mongo_client().admin.command(cmd) - def _do_teardown(self): + def _do_teardown(self, kill=False): self.logger.info("Stopping all members of the replica set...") running_at_start = self.is_running() @@ -411,11 +411,11 @@ class ReplicaSetFixture(interface.ReplFixture): # pylint: disable=too-many-inst teardown_handler = interface.FixtureTeardownHandler(self.logger) if self.initial_sync_node: - teardown_handler.teardown(self.initial_sync_node, "initial sync node") + teardown_handler.teardown(self.initial_sync_node, "initial sync node", kill=kill) # Terminate the secondaries first to reduce noise in the logs. for node in reversed(self.nodes): - teardown_handler.teardown(node, "replica set member on port %d" % node.port) + teardown_handler.teardown(node, "replica set member on port %d" % node.port, kill=kill) if teardown_handler.was_successful(): self.logger.info("Successfully stopped all members of the replica set.") diff --git a/buildscripts/resmokelib/testing/fixtures/shardedcluster.py b/buildscripts/resmokelib/testing/fixtures/shardedcluster.py index edefdf11f9f..0c927304232 100644 --- a/buildscripts/resmokelib/testing/fixtures/shardedcluster.py +++ b/buildscripts/resmokelib/testing/fixtures/shardedcluster.py @@ -191,7 +191,7 @@ class ShardedClusterFixture(interface.Fixture): # pylint: disable=too-many-inst client.admin.command({"balancerStart": 1}, maxTimeMS=timeout_ms) self.logger.info("Started the balancer") - def _do_teardown(self): + def _do_teardown(self, kill=False): """Shut down the sharded cluster.""" self.logger.info("Stopping all members of the sharded cluster...") @@ -206,13 +206,13 @@ class ShardedClusterFixture(interface.Fixture): # pylint: disable=too-many-inst teardown_handler = interface.FixtureTeardownHandler(self.logger) if self.configsvr is not None: - teardown_handler.teardown(self.configsvr, "config server") + teardown_handler.teardown(self.configsvr, "config server", kill=kill) for mongos in self.mongos: - teardown_handler.teardown(mongos, "mongos") + teardown_handler.teardown(mongos, "mongos", kill=kill) for shard in self.shards: - teardown_handler.teardown(shard, "shard") + teardown_handler.teardown(shard, "shard", kill=kill) if teardown_handler.was_successful(): self.logger.info("Successfully stopped all members of the sharded cluster.") @@ -429,7 +429,7 @@ class _MongoSFixture(interface.Fixture): self.logger.info("Successfully contacted the mongos on port %d.", self.port) - def _do_teardown(self): + def _do_teardown(self, kill=False): if self.mongos is None: self.logger.warning("The mongos fixture has not been set up yet.") return # Teardown is still a success even if nothing is running. @@ -442,7 +442,7 @@ class _MongoSFixture(interface.Fixture): self.logger.warning(msg) raise errors.ServerFailure(msg) - self.mongos.stop() + self.mongos.stop(kill=kill) exit_code = self.mongos.wait() if exit_code == 0: diff --git a/buildscripts/resmokelib/testing/fixtures/standalone.py b/buildscripts/resmokelib/testing/fixtures/standalone.py index 686d360fb36..3c54f41f689 100644 --- a/buildscripts/resmokelib/testing/fixtures/standalone.py +++ b/buildscripts/resmokelib/testing/fixtures/standalone.py @@ -111,7 +111,7 @@ class MongoDFixture(interface.Fixture): self.logger.info("Successfully contacted the mongod on port %d.", self.port) - def _do_teardown(self): + def _do_teardown(self, kill=False): if self.mongod is None: self.logger.warning("The mongod fixture has not been set up yet.") return # Still a success even if nothing is running. @@ -124,10 +124,12 @@ class MongoDFixture(interface.Fixture): self.logger.warning(msg) raise errors.ServerFailure(msg) - self.mongod.stop() + self.mongod.stop(kill) exit_code = self.mongod.wait() - if exit_code == 0: + # SIGKILL has an exit code of 9 and Python's subprocess module returns + # negative versions of system calls. + if exit_code == 0 or (exit_code == -9 and kill): self.logger.info("Successfully stopped the mongod on port {:d}.".format(self.port)) else: self.logger.warning("Stopped the mongod on port {:d}. " diff --git a/buildscripts/resmokelib/testing/fixtures/yesfixture.py b/buildscripts/resmokelib/testing/fixtures/yesfixture.py index defdffb4058..310bd8c34b1 100644 --- a/buildscripts/resmokelib/testing/fixtures/yesfixture.py +++ b/buildscripts/resmokelib/testing/fixtures/yesfixture.py @@ -35,7 +35,7 @@ class YesFixture(interface.Fixture): # pylint: disable=abstract-method logger = self.logger.new_fixture_node_logger("yes{:d}".format(index)) return programs.generic_program(logger, ["yes", self.__message]) - def _do_teardown(self): + def _do_teardown(self, kill=False): running_at_start = self.is_running() success = True # Still a success even if nothing is running. @@ -49,7 +49,7 @@ class YesFixture(interface.Fixture): # pylint: disable=abstract-method if process is not None: if running_at_start: self.logger.info("Stopping yes process with pid %d...", process.pid) - process.stop() + process.stop(kill) exit_code = process.wait() success = (exit_code == -signal.SIGTERM) and success diff --git a/buildscripts/resmokelib/testing/testcases/fixture.py b/buildscripts/resmokelib/testing/testcases/fixture.py index dee7757c3d8..fb074fd050b 100644 --- a/buildscripts/resmokelib/testing/testcases/fixture.py +++ b/buildscripts/resmokelib/testing/testcases/fixture.py @@ -70,3 +70,27 @@ class FixtureTeardownTestCase(FixtureTestCase): except: self.logger.exception("An error occurred during the teardown of %s.", self.fixture) raise + + +class FixtureKillTestCase(FixtureTestCase): + """TestCase for killing a fixture. Intended for use before archiving a failed test.""" + + REGISTERED_NAME = registry.LEAVE_UNREGISTERED + PHASE = "kill" + + def __init__(self, logger, fixture, job_name): + """Initialize the FixtureKillTestCase.""" + FixtureTestCase.__init__(self, logger, job_name, self.PHASE) + self.fixture = fixture + + def run_test(self): + """Tear down the fixture.""" + try: + self.return_code = 2 # Test return code of 2 is used for fixture failures. + self.logger.info("Killing the fixture %s.", self.fixture) + self.fixture.teardown(finished=False, kill=True) + self.logger.info("Finished killing %s.", self.fixture) + self.return_code = 0 + except: + self.logger.exception("An error occurred while killing %s.", self.fixture) + raise |