Files
mongo/buildscripts/tests/resmokelib/testing/test_job.py
Juan Gu 7209d62b77 SERVER-99522 Delete dead py linters (#31760)
GitOrigin-RevId: 3aedfa559dda734d4d89fefe0fe1154a5a3cf04d
2025-04-09 19:33:45 +00:00

333 lines
14 KiB
Python

"""Unit tests for the resmokelib.testing.executor module."""
import logging
import threading
import unittest
import mock
from opentelemetry.context.context import Context
from buildscripts.resmokelib import errors
from buildscripts.resmokelib.testing import job, queue_element
from buildscripts.resmokelib.testing.fixtures import interface as _fixtures
from buildscripts.resmokelib.testing.fixtures.fixturelib import FixtureLib
from buildscripts.resmokelib.utils import queue as _queue
class TestJob(unittest.TestCase):
TESTS = ["jstests/core/and.js", "jstests/core/or.js"]
@staticmethod
def mock_testcase(test_name):
testcase = mock.Mock()
testcase.test_name = test_name
testcase.REGISTERED_NAME = "js_test"
testcase.logger = logging.getLogger("job_unittest")
return testcase
@staticmethod
def mock_interrupt_flag():
interrupt_flag = mock.Mock()
interrupt_flag.is_set = lambda: False
return interrupt_flag
@staticmethod
def get_suite_options(
num_repeat_tests=None,
time_repeat_tests_secs=None,
num_repeat_tests_min=None,
num_repeat_tests_max=None,
):
suite_options = mock.Mock()
suite_options.num_repeat_tests = num_repeat_tests
suite_options.time_repeat_tests_secs = time_repeat_tests_secs
suite_options.num_repeat_tests_min = num_repeat_tests_min
suite_options.num_repeat_tests_max = num_repeat_tests_max
return suite_options
@staticmethod
def queue_tests(tests, queue, queue_elem_type, suite_options):
for test in tests:
queue_elem = queue_elem_type(TestJob.mock_testcase(test), {}, suite_options)
queue.put(queue_elem)
@staticmethod
def expected_run_num(time_repeat_tests_secs, test_time_secs):
"""Return the number of times a test is expected to run."""
return time_repeat_tests_secs / test_time_secs + 1
def test__run_num_repeat(self):
num_repeat_tests = 1
queue = _queue.Queue()
suite_options = self.get_suite_options(num_repeat_tests=num_repeat_tests)
mock_time = MockTime(1)
job_object = UnitJob(suite_options)
self.queue_tests(self.TESTS, queue, queue_element.QueueElem, suite_options)
job_object._get_time = mock_time.time
job_object._run(queue, self.mock_interrupt_flag())
self.assertEqual(job_object.total_test_num, num_repeat_tests * len(self.TESTS))
for test in self.TESTS:
self.assertEqual(job_object.tests[test], num_repeat_tests)
def test__run_time_repeat_time_no_min_max(self):
increment = 1
time_repeat_tests_secs = 10
expected_tests_run = self.expected_run_num(time_repeat_tests_secs, increment)
queue = _queue.Queue()
suite_options = self.get_suite_options(time_repeat_tests_secs=time_repeat_tests_secs)
mock_time = MockTime(increment)
job_object = UnitJob(suite_options)
self.queue_tests(self.TESTS, queue, queue_element.QueueElemRepeatTime, suite_options)
job_object._get_time = mock_time.time
job_object._run(queue, self.mock_interrupt_flag())
self.assertEqual(job_object.total_test_num, expected_tests_run * len(self.TESTS))
for test in self.TESTS:
self.assertEqual(job_object.tests[test], expected_tests_run)
def test__run_time_repeat_time_no_min(self):
increment = 1
time_repeat_tests_secs = 10
num_repeat_tests_max = 100
expected_tests_run = self.expected_run_num(time_repeat_tests_secs, increment)
queue = _queue.Queue()
suite_options = self.get_suite_options(
time_repeat_tests_secs=time_repeat_tests_secs, num_repeat_tests_max=num_repeat_tests_max
)
mock_time = MockTime(increment)
job_object = UnitJob(suite_options)
self.queue_tests(self.TESTS, queue, queue_element.QueueElemRepeatTime, suite_options)
job_object._get_time = mock_time.time
job_object._run(queue, self.mock_interrupt_flag())
self.assertLess(job_object.total_test_num, num_repeat_tests_max * len(self.TESTS))
for test in self.TESTS:
self.assertEqual(job_object.tests[test], expected_tests_run)
def test__run_time_repeat_time_no_max(self):
increment = 1
time_repeat_tests_secs = 10
num_repeat_tests_min = 1
expected_tests_run = self.expected_run_num(time_repeat_tests_secs, increment)
queue = _queue.Queue()
suite_options = self.get_suite_options(
time_repeat_tests_secs=time_repeat_tests_secs, num_repeat_tests_min=num_repeat_tests_min
)
mock_time = MockTime(increment)
job_object = UnitJob(suite_options)
self.queue_tests(self.TESTS, queue, queue_element.QueueElemRepeatTime, suite_options)
job_object._get_time = mock_time.time
job_object._run(queue, self.mock_interrupt_flag())
self.assertGreater(job_object.total_test_num, num_repeat_tests_min * len(self.TESTS))
for test in self.TESTS:
self.assertEqual(job_object.tests[test], expected_tests_run)
def test__run_time_repeat_time(self):
increment = 1
time_repeat_tests_secs = 10
num_repeat_tests_min = 1
num_repeat_tests_max = 100
expected_tests_run = self.expected_run_num(time_repeat_tests_secs, increment)
queue = _queue.Queue()
suite_options = self.get_suite_options(
time_repeat_tests_secs=time_repeat_tests_secs,
num_repeat_tests_min=num_repeat_tests_min,
num_repeat_tests_max=num_repeat_tests_max,
)
mock_time = MockTime(increment)
job_object = UnitJob(suite_options)
self.queue_tests(self.TESTS, queue, queue_element.QueueElemRepeatTime, suite_options)
job_object._get_time = mock_time.time
job_object._run(queue, self.mock_interrupt_flag())
self.assertGreater(job_object.total_test_num, num_repeat_tests_min * len(self.TESTS))
self.assertLess(job_object.total_test_num, num_repeat_tests_max * len(self.TESTS))
for test in self.TESTS:
self.assertEqual(job_object.tests[test], expected_tests_run)
def test__run_time_repeat_min(self):
increment = 1
time_repeat_tests_secs = 2
num_repeat_tests_min = 3
num_repeat_tests_max = 100
queue = _queue.Queue()
suite_options = self.get_suite_options(
time_repeat_tests_secs=time_repeat_tests_secs,
num_repeat_tests_min=num_repeat_tests_min,
num_repeat_tests_max=num_repeat_tests_max,
)
mock_time = MockTime(increment)
job_object = UnitJob(suite_options)
self.queue_tests(self.TESTS, queue, queue_element.QueueElemRepeatTime, suite_options)
job_object._get_time = mock_time.time
job_object._run(queue, self.mock_interrupt_flag())
self.assertEqual(job_object.total_test_num, num_repeat_tests_min * len(self.TESTS))
for test in self.TESTS:
self.assertEqual(job_object.tests[test], num_repeat_tests_min)
def test__run_time_repeat_max(self):
increment = 1
time_repeat_tests_secs = 30
num_repeat_tests_min = 1
num_repeat_tests_max = 10
expected_time_repeat_tests = self.expected_run_num(time_repeat_tests_secs, increment)
queue = _queue.Queue()
suite_options = self.get_suite_options(
time_repeat_tests_secs=time_repeat_tests_secs,
num_repeat_tests_min=num_repeat_tests_min,
num_repeat_tests_max=num_repeat_tests_max,
)
mock_time = MockTime(increment)
job_object = UnitJob(suite_options)
self.queue_tests(self.TESTS, queue, queue_element.QueueElemRepeatTime, suite_options)
job_object._get_time = mock_time.time
job_object._run(queue, self.mock_interrupt_flag())
self.assertEqual(job_object.total_test_num, num_repeat_tests_max * len(self.TESTS))
for test in self.TESTS:
self.assertEqual(job_object.tests[test], num_repeat_tests_max)
self.assertLess(job_object.tests[test], expected_time_repeat_tests)
class MockTime(object):
"""Class to mock time.time."""
def __init__(self, increment):
"""Initialize with an increment which simulates a time increment."""
self._time = 0
self._increment = increment
def time(self):
"""Simulate time.time by incrementing for every invocation."""
cur_time = self._time
self._time += self._increment
return cur_time
class UnitJob(job.Job):
def __init__(self, suite_options):
super(UnitJob, self).__init__(
0,
logging.getLogger("job_unittest"),
None,
[],
None,
None,
suite_options,
logging.getLogger("job_unittest"),
)
self.total_test_num = 0
self.tests = {}
def _execute_test(self, test, hook_failure_flag=None):
self.total_test_num += 1
if test.test_name not in self.tests:
self.tests[test.test_name] = 0
self.tests[test.test_name] += 1
class TestFixtureSetupAndTeardown(unittest.TestCase):
"""Test cases for error handling around setup_fixture() and teardown_fixture()."""
def setUp(self):
logger = logging.getLogger("job_unittest")
self.__job_object = job.Job(
job_num=0,
logger=logger,
fixture=None,
hooks=[],
report=None,
archival=None,
suite_options=None,
test_queue_logger=logger,
)
self.__context = Context(trace_id=0, span_id=0, is_remote=False)
# Initialize the Job instance such that its setup_fixture() and teardown_fixture() methods
# always indicate success. The settings for these mocked method will be changed in the
# individual test cases below.
self.__job_object.manager.setup_fixture = mock.Mock(return_value=True)
self.__job_object.manager.teardown_fixture = mock.Mock(return_value=True)
def __assert_when_run_tests(self, setup_succeeded=True, teardown_succeeded=True):
queue = _queue.Queue()
interrupt_flag = threading.Event()
setup_flag = threading.Event()
teardown_flag = threading.Event()
self.__job_object.start(queue, interrupt_flag, self.__context, setup_flag, teardown_flag)
self.assertEqual(setup_succeeded, not interrupt_flag.is_set())
self.assertEqual(setup_succeeded, not setup_flag.is_set())
self.assertEqual(teardown_succeeded, not teardown_flag.is_set())
# teardown_fixture() should be called even if setup_fixture() raises an exception.
self.__job_object.manager.setup_fixture.assert_called()
self.__job_object.manager.teardown_fixture.assert_called()
def test_setup_and_teardown_both_succeed(self):
self.__assert_when_run_tests()
def test_setup_returns_failure(self):
self.__job_object.manager.setup_fixture.return_value = False
self.__assert_when_run_tests(setup_succeeded=False)
def test_setup_raises_logging_config_exception(self):
self.__job_object.manager.setup_fixture.side_effect = errors.LoggerRuntimeConfigError(
"Logging configuration error intentionally raised in unit test"
)
self.__assert_when_run_tests(setup_succeeded=False)
def test_setup_raises_unexpected_exception(self):
self.__job_object.manager.setup_fixture.side_effect = Exception(
"Generic error intentionally raised in unit test"
)
self.__assert_when_run_tests(setup_succeeded=False)
def test_teardown_returns_failure(self):
self.__job_object.manager.teardown_fixture.return_value = False
self.__assert_when_run_tests(teardown_succeeded=False)
def test_teardown_raises_logging_config_exception(self):
self.__job_object.manager.teardown_fixture.side_effect = errors.LoggerRuntimeConfigError(
"Logging configuration error intentionally raised in unit test"
)
self.__assert_when_run_tests(teardown_succeeded=False)
def test_teardown_raises_unexpected_exception(self):
self.__job_object.manager.teardown_fixture.side_effect = Exception(
"Generic error intentionally raised in unit test"
)
self.__assert_when_run_tests(teardown_succeeded=False)
class TestNoOpFixtureSetupAndTeardown(unittest.TestCase):
"""Test cases for NoOpFixture handling in setup_fixture() and teardown_fixture()."""
def setUp(self):
self.logger = logging.getLogger("job_unittest")
fixturelib = FixtureLib()
self.__noop_fixture = _fixtures.NoOpFixture(
logger=self.logger, job_num=0, fixturelib=fixturelib
)
self.__noop_fixture.setup = mock.Mock()
self.__noop_fixture.teardown = mock.Mock()
test_report = mock.Mock()
test_report.find_test_info().status = "pass"
self.__job_object = job.Job(
job_num=0,
logger=self.logger,
fixture=self.__noop_fixture,
hooks=[],
report=test_report,
archival=None,
suite_options=None,
test_queue_logger=self.logger,
)
def test_setup_called_for_noop_fixture(self):
self.assertTrue(self.__job_object.manager.setup_fixture(self.logger))
self.__noop_fixture.setup.assert_called_once_with()
def test_teardown_called_for_noop_fixture(self):
self.assertTrue(self.__job_object.manager.teardown_fixture(self.logger))
self.__noop_fixture.teardown.assert_called_once_with(finished=True)