summaryrefslogtreecommitdiff
path: root/buildscripts/tests/test_evergreen_gen_build_variant.py
diff options
context:
space:
mode:
Diffstat (limited to 'buildscripts/tests/test_evergreen_gen_build_variant.py')
-rw-r--r--buildscripts/tests/test_evergreen_gen_build_variant.py382
1 files changed, 382 insertions, 0 deletions
diff --git a/buildscripts/tests/test_evergreen_gen_build_variant.py b/buildscripts/tests/test_evergreen_gen_build_variant.py
new file mode 100644
index 00000000000..7ece404ab36
--- /dev/null
+++ b/buildscripts/tests/test_evergreen_gen_build_variant.py
@@ -0,0 +1,382 @@
+"""Unit tests for the generate_resmoke_suite script."""
+import unittest
+
+from mock import MagicMock
+
+from buildscripts import evergreen_gen_build_variant as under_test
+from buildscripts.ciconfig.evergreen import Variant, Task
+
+# pylint: disable=missing-docstring,invalid-name,unused-argument,no-self-use,protected-access
+# pylint: disable=too-many-locals,too-many-lines,too-many-public-methods,no-value-for-parameter
+
+
+def build_mock_build_variant(expansions=None, task_list=None):
+ task_spec_list = [{"name": task.name} for task in task_list] if task_list else []
+ config = {
+ "tasks": task_spec_list,
+ }
+ if expansions:
+ config["expansions"] = expansions
+
+ if task_list is None:
+ task_list = []
+ task_map = {task.name: task for task in task_list}
+
+ return Variant(config, task_map, {})
+
+
+def build_mock_task(name, run_vars=None, depends_on=None):
+ config = {
+ "name":
+ name, "commands": [
+ {"func": "do setup"},
+ {
+ "func": "generate resmoke tasks",
+ "vars": run_vars if run_vars else {},
+ },
+ ]
+ }
+
+ if depends_on is not None:
+ config["depends_on"] = depends_on
+ return Task(config)
+
+
+def build_mock_project_config(variant=None, task_defs=None):
+ mock_project = MagicMock()
+ if variant:
+ mock_project.get_variant.return_value = variant
+
+ if task_defs:
+ mock_project.get_task.side_effect = task_defs
+
+ return mock_project
+
+
+def build_mock_expansions():
+ mock_expansions = MagicMock()
+ mock_expansions.config_location.return_value = "/path/to/config"
+ mock_expansions.get_max_sub_suites.return_value = 998
+ mock_expansions.task_name = "generating_task"
+ return mock_expansions
+
+
+def build_mock_evg_api(build_task_list):
+ mock_evg_api = MagicMock()
+ mock_evg_api.build_by_id.return_value.get_tasks.return_value = build_task_list
+ return mock_evg_api
+
+
+def build_mock_orchestrator(build_expansions=None, task_def_list=None, build_task_list=None):
+ if build_expansions is None:
+ build_expansions = {}
+ if task_def_list is None:
+ task_def_list = []
+ if build_task_list is None:
+ build_task_list = []
+
+ mock_build_variant = build_mock_build_variant(build_expansions, task_def_list)
+ mock_project = build_mock_project_config(mock_build_variant, task_def_list)
+ mock_evg_expansions = build_mock_expansions()
+ mock_evg_api = build_mock_evg_api(build_task_list)
+
+ return under_test.GenerateBuildVariantOrchestrator(
+ gen_task_validation=MagicMock(),
+ gen_task_options=MagicMock(),
+ evg_project_config=mock_project,
+ evg_expansions=mock_evg_expansions,
+ evg_api=mock_evg_api,
+ )
+
+
+class TestEvgExpansions(unittest.TestCase):
+ def test_get_max_sub_suites_should_use_patch_value_in_patches(self):
+ evg_expansions = under_test.EvgExpansions(
+ is_patch=True,
+ max_sub_suites=5,
+ mainline_max_sub_suites=1,
+ build_id="build_id",
+ build_variant="build_variant",
+ project="project",
+ revision="revision",
+ task_name="task_name",
+ task_id="task_id",
+ )
+
+ self.assertEqual(evg_expansions.get_max_sub_suites(), evg_expansions.max_sub_suites)
+
+ def test_get_max_sub_suites_should_use_mainline_value_in_non_patches(self):
+ evg_expansions = under_test.EvgExpansions(
+ is_patch=False,
+ max_sub_suites=5,
+ mainline_max_sub_suites=1,
+ build_id="build_id",
+ build_variant="build_variant",
+ project="project",
+ revision="revision",
+ task_name="task_name",
+ task_id="task_id",
+ )
+
+ self.assertEqual(evg_expansions.get_max_sub_suites(),
+ evg_expansions.mainline_max_sub_suites)
+
+ def test_get_max_sub_suites_should_use_mainline_value_if_patch_status_unknown(self):
+ evg_expansions = under_test.EvgExpansions(
+ is_patch=None,
+ max_sub_suites=5,
+ mainline_max_sub_suites=1,
+ build_id="build_id",
+ build_variant="build_variant",
+ project="project",
+ revision="revision",
+ task_name="task_name",
+ task_id="task_id",
+ )
+
+ self.assertEqual(evg_expansions.get_max_sub_suites(),
+ evg_expansions.mainline_max_sub_suites)
+
+
+class TestTranslateRunVar(unittest.TestCase):
+ def test_normal_value_should_be_returned(self):
+ run_var = "some value"
+ mock_build_variant = build_mock_build_variant()
+ self.assertEqual(run_var, under_test.translate_run_var(run_var, mock_build_variant))
+
+ def test_expansion_should_be_returned_from_build_variant(self):
+ run_var = "${my_expansion}"
+ value = "my value"
+ mock_build_variant = build_mock_build_variant(expansions={"my_expansion": value})
+ self.assertEqual(value, under_test.translate_run_var(run_var, mock_build_variant))
+
+ def test_expansion_not_found_should_return_none(self):
+ run_var = "${my_expansion}"
+ mock_build_variant = build_mock_build_variant(expansions={})
+ self.assertIsNone(under_test.translate_run_var(run_var, mock_build_variant))
+
+ def test_expansion_not_found_should_return_default(self):
+ run_var = "${my_expansion|default}"
+ mock_build_variant = build_mock_build_variant(expansions={})
+ self.assertEqual("default", under_test.translate_run_var(run_var, mock_build_variant))
+
+ def test_expansion_should_be_returned_from_build_variant_even_with_default(self):
+ run_var = "${my_expansion|default}"
+ value = "my value"
+ mock_build_variant = build_mock_build_variant(expansions={"my_expansion": value})
+ self.assertEqual(value, under_test.translate_run_var(run_var, mock_build_variant))
+
+
+class TestTaskDefToSplitParams(unittest.TestCase):
+ def test_params_should_be_generated(self):
+ run_vars = {
+ "resmoke_args": "run tests",
+ }
+ mock_task_def = build_mock_task("my_task", run_vars)
+ mock_orchestrator = build_mock_orchestrator(task_def_list=[mock_task_def])
+
+ split_param = mock_orchestrator.task_def_to_split_params(mock_task_def, "build_variant")
+
+ self.assertEqual("build_variant", split_param.build_variant)
+ self.assertEqual("my_task", split_param.task_name)
+ self.assertEqual("my_task", split_param.suite_name)
+ self.assertEqual("my_task", split_param.filename)
+
+ def test_params_should_allow_suite_to_be_overridden(self):
+ run_vars = {
+ "resmoke_args": "run tests",
+ "suite": "the suite",
+ }
+ mock_task_def = build_mock_task("my_task", run_vars)
+ mock_orchestrator = build_mock_orchestrator(task_def_list=[mock_task_def])
+
+ split_param = mock_orchestrator.task_def_to_split_params(mock_task_def, "build_variant")
+
+ self.assertEqual("build_variant", split_param.build_variant)
+ self.assertEqual("my_task", split_param.task_name)
+ self.assertEqual("the suite", split_param.suite_name)
+ self.assertEqual("the suite", split_param.filename)
+
+
+class TestDetermineTaskDependencies(unittest.TestCase):
+ def test_running_task_should_not_be_included_in_depends_on(self):
+ run_vars = {
+ "resmoke_args": "run tests",
+ }
+ depends_on = [
+ {"name": "compile"},
+ {"name": "build_variant_gen"},
+ ]
+ mock_task_def = build_mock_task("my_task", run_vars, depends_on=depends_on)
+ mock_orchestrator = build_mock_orchestrator(task_def_list=[mock_task_def])
+
+ dependencies = mock_orchestrator.determine_task_dependencies(mock_task_def)
+
+ self.assertIn("compile", dependencies)
+ self.assertNotIn("generating_task", dependencies)
+
+
+class TestTaskDefToGenParams(unittest.TestCase):
+ def test_params_should_be_generated(self):
+ run_vars = {
+ "resmoke_args": "run tests",
+ }
+ mock_task_def = build_mock_task("my_task", run_vars)
+ mock_orchestrator = build_mock_orchestrator(task_def_list=[mock_task_def])
+
+ gen_params = mock_orchestrator.task_def_to_gen_params(mock_task_def, "build_variant")
+
+ self.assertFalse(gen_params.require_multiversion_setup)
+ self.assertEqual("run tests", gen_params.resmoke_args)
+ self.assertEqual(mock_orchestrator.evg_expansions.config_location.return_value,
+ gen_params.config_location)
+ self.assertIsNone(gen_params.large_distro_name)
+ self.assertFalse(gen_params.use_large_distro)
+
+ def test_params_should_be_overwritable(self):
+ run_vars = {
+ "resmoke_args": "run tests",
+ "use_large_distro": "true",
+ }
+ mock_task_def = build_mock_task("my_task", run_vars)
+ build_expansions = {"large_distro_name": "my large distro"}
+ mock_orchestrator = build_mock_orchestrator(build_expansions=build_expansions,
+ task_def_list=[mock_task_def])
+ gen_params = mock_orchestrator.task_def_to_gen_params(mock_task_def, "build_variant")
+
+ self.assertFalse(gen_params.require_multiversion_setup)
+ self.assertEqual("run tests", gen_params.resmoke_args)
+ self.assertEqual(mock_orchestrator.evg_expansions.config_location.return_value,
+ gen_params.config_location)
+ self.assertEqual("my large distro", gen_params.large_distro_name)
+ self.assertTrue(gen_params.use_large_distro)
+
+
+class TestTaskDefToFuzzerParams(unittest.TestCase):
+ def test_params_should_be_generated(self):
+ run_vars = {
+ "num_files": "5",
+ "num_tasks": "3",
+ }
+ mock_task_def = build_mock_task("my_fuzzer_gen", run_vars)
+ mock_orchestrator = build_mock_orchestrator(task_def_list=[mock_task_def])
+ fuzzer_params = mock_orchestrator.task_def_to_fuzzer_params(mock_task_def, "build_variant")
+
+ self.assertEqual("my_fuzzer", fuzzer_params.task_name)
+ self.assertEqual(5, fuzzer_params.num_files)
+ self.assertEqual(3, fuzzer_params.num_tasks)
+ self.assertEqual("jstestfuzz", fuzzer_params.npm_command)
+ self.assertEqual(mock_orchestrator.evg_expansions.config_location.return_value,
+ fuzzer_params.config_location)
+ self.assertIsNone(fuzzer_params.large_distro_name)
+ self.assertFalse(fuzzer_params.use_large_distro)
+
+ def test_num_tasks_respects_max_sub_suites(self):
+ run_vars = {
+ "num_files": "5",
+ "num_tasks": "3",
+ }
+ mock_task_def = build_mock_task("my_fuzzer_gen", run_vars)
+ mock_orchestrator = build_mock_orchestrator(task_def_list=[mock_task_def])
+ mock_orchestrator.evg_expansions.get_max_sub_suites.return_value = 1
+ fuzzer_params = mock_orchestrator.task_def_to_fuzzer_params(mock_task_def, "build_variant")
+
+ self.assertEqual(5, fuzzer_params.num_files)
+ self.assertEqual(1, fuzzer_params.num_tasks)
+
+ def test_params_should_be_overwritable(self):
+ run_vars = {
+ "num_files": "${file_count|8}",
+ "num_tasks": "3",
+ "use_large_distro": "true",
+ "npm_command": "aggfuzzer",
+ }
+ mock_task_def = build_mock_task("my_fuzzer_gen", run_vars)
+ build_expansions = {"large_distro_name": "my large distro"}
+ mock_orchestrator = build_mock_orchestrator(build_expansions=build_expansions,
+ task_def_list=[mock_task_def])
+
+ fuzzer_params = mock_orchestrator.task_def_to_fuzzer_params(mock_task_def, "build_variant")
+
+ self.assertEqual("my_fuzzer", fuzzer_params.task_name)
+ self.assertEqual(8, fuzzer_params.num_files)
+ self.assertEqual(3, fuzzer_params.num_tasks)
+ self.assertEqual("aggfuzzer", fuzzer_params.npm_command)
+ self.assertEqual(mock_orchestrator.evg_expansions.config_location.return_value,
+ fuzzer_params.config_location)
+ self.assertEqual("my large distro", fuzzer_params.large_distro_name)
+ self.assertTrue(fuzzer_params.use_large_distro)
+
+
+class TestGenerateBuildVariant(unittest.TestCase):
+ def test_a_whole_build_variant(self):
+ gen_run_vars = {
+ "resmoke_args": "run tests",
+ }
+ mv_gen_run_vars = {
+ "resmoke_args": "run tests",
+ "suite": "some suite",
+ }
+ fuzz_run_vars = {
+ "num_files": "5",
+ "num_tasks": "3",
+ "is_jstestfuzz": "true",
+ }
+ mv_fuzz_run_vars = {
+ "num_files": "5",
+ "num_tasks": "3",
+ "is_jstestfuzz": "true",
+ "suite": "aggfuzzer",
+ }
+ mock_task_defs = [
+ build_mock_task("my_gen_task", gen_run_vars),
+ build_mock_task("my_fuzzer_task", fuzz_run_vars),
+ build_mock_task("my_mv_fuzzer_task", mv_fuzz_run_vars),
+ build_mock_task("my_mv_gen_task", mv_gen_run_vars),
+ ]
+ mock_orchestrator = build_mock_orchestrator(task_def_list=mock_task_defs)
+ builder = MagicMock()
+
+ builder = mock_orchestrator.generate_build_variant(builder, "build variant")
+
+ self.assertEqual(builder.generate_suite.call_count, 2)
+ self.assertEqual(builder.generate_fuzzer.call_count, 2)
+
+
+class TestAdjustTaskPriority(unittest.TestCase):
+ def test_task_is_updates(self):
+ starting_priority = 42
+ task_id = "task 314"
+ mock_task = MagicMock(task_id=task_id, priority=starting_priority)
+ mock_orchestrator = build_mock_orchestrator()
+
+ mock_orchestrator.adjust_task_priority(mock_task)
+
+ mock_orchestrator.evg_api.configure_task.assert_called_with(task_id,
+ priority=starting_priority + 1)
+
+ def test_task_should_only_reach_99(self):
+ starting_priority = 99
+ task_id = "task 314"
+ mock_task = MagicMock(task_id=task_id, priority=starting_priority)
+ mock_orchestrator = build_mock_orchestrator()
+
+ mock_orchestrator.adjust_task_priority(mock_task)
+
+ mock_orchestrator.evg_api.configure_task.assert_called_with(task_id,
+ priority=starting_priority)
+
+
+class TestAdjustGenTasksPriority(unittest.TestCase):
+ def test_gen_tasks_in_task_list_are_adjusted(self):
+ gen_tasks = {"task_3", "task_8", "task_13"}
+ n_build_tasks = 25
+ mock_task_list = [
+ MagicMock(build_variant='dummy_variant', display_name=f"task_{i}", priority=0)
+ for i in range(n_build_tasks)
+ ]
+ mock_orchestrator = build_mock_orchestrator(build_task_list=mock_task_list)
+
+ n_tasks_adjusted = mock_orchestrator.adjust_gen_tasks_priority(gen_tasks)
+
+ self.assertEqual(len(gen_tasks), n_tasks_adjusted)