summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Bradford <david.bradford@mongodb.com>2019-07-08 18:12:47 -0400
committerDavid Bradford <david.bradford@mongodb.com>2019-07-08 18:12:47 -0400
commite5d7c73e7eb9f3bfe70925dd3154ca348b1ee285 (patch)
tree2ac6b928e36ec6958d9c5ffa7c44dd9b27af20d1
parentc6468f7d3ac783b4bcdeb6744fc976c8ecee2969 (diff)
downloadmongo-e5d7c73e7eb9f3bfe70925dd3154ca348b1ee285.tar.gz
SERVER-41940: Use evergreen.py in burn_in_tests
-rw-r--r--buildscripts/burn_in_tags.py2
-rw-r--r--buildscripts/burn_in_tests.py102
-rw-r--r--buildscripts/tests/test_burn_in_tests.py143
-rw-r--r--buildscripts/util/read_config.py2
4 files changed, 88 insertions, 161 deletions
diff --git a/buildscripts/burn_in_tags.py b/buildscripts/burn_in_tags.py
index 15b00e5c1c6..9b595ecd624 100644
--- a/buildscripts/burn_in_tags.py
+++ b/buildscripts/burn_in_tags.py
@@ -125,7 +125,7 @@ def _generate_evg_tasks(evergreen_api, shrub_config, expansions_file_data, build
"""
for buildvariant, run_buildvariant in buildvariant_map.items():
config_options = _get_config_options(expansions_file_data, buildvariant, run_buildvariant)
- tests_by_task = create_tests_by_task(config_options)
+ tests_by_task = create_tests_by_task(config_options, evergreen_api)
if tests_by_task:
_generate_evg_buildvariant(shrub_config, buildvariant, run_buildvariant)
create_generate_tasks_config(evergreen_api, shrub_config, config_options, tests_by_task,
diff --git a/buildscripts/burn_in_tests.py b/buildscripts/burn_in_tests.py
index 9f098cf0ff2..c3dd28f1a95 100644
--- a/buildscripts/burn_in_tests.py
+++ b/buildscripts/burn_in_tests.py
@@ -7,10 +7,8 @@ import json
import optparse
import os.path
import subprocess
-import re
import shlex
import sys
-import urllib.parse
import datetime
import logging
@@ -36,14 +34,11 @@ if __name__ == "__main__" and __package__ is None:
from buildscripts import git
from buildscripts import resmokelib
from buildscripts.ciconfig import evergreen
-from buildscripts.client import evergreen as evergreen_client
from buildscripts.util import teststats
# pylint: enable=wrong-import-position
LOGGER = logging.getLogger(__name__)
-API_REST_PREFIX = "/rest/v1/"
-API_SERVER_DEFAULT = "https://evergreen.mongodb.com"
AVG_TEST_RUNTIME_ANALYSIS_DAYS = 14
AVG_TEST_TIME_MULTIPLIER = 3
CONFIG_FILE = "../src/.evergreen.yml"
@@ -185,48 +180,46 @@ def validate_options(parser, options):
check_variant(options.run_buildvariant, parser)
-def find_last_activated_task(revisions, variant, branch_name):
- """Get the git hash of the most recently activated build before this one."""
-
- project = "mongodb-mongo-" + branch_name
- build_prefix = "mongodb_mongo_" + branch_name + "_" + variant.replace("-", "_")
-
- evg_cfg = evergreen_client.read_evg_config()
- if evg_cfg is not None and "api_server_host" in evg_cfg:
- api_server = "{url.scheme}://{url.netloc}".format(
- url=urllib.parse.urlparse(evg_cfg["api_server_host"]))
- else:
- api_server = API_SERVER_DEFAULT
+def find_last_activated_task(revisions, variant, project, evg_api):
+ """
+ Search the given list of revisions for the first build that was activated in evergreen.
- api_prefix = api_server + API_REST_PREFIX
+ :param revisions: List of revisions to search.
+ :param variant: Build variant to query for.
+ :param project: Project being run against.
+ :param evg_api: Evergreen api.
+ :return: First revision from list that has been activated.
+ """
+ prefix = project.replace("-", "_")
for githash in revisions:
- url = "{}projects/{}/revisions/{}".format(api_prefix, project, githash)
- response = requests.get(url)
- revision_data = response.json()
+ version_id = f"{prefix}_{githash}"
+ version = evg_api.version_by_id(version_id)
- try:
- for build in revision_data["builds"]:
- if build.startswith(build_prefix):
- url = "{}builds/{}".format(api_prefix, build)
- build_resp = requests.get(url)
- build_data = build_resp.json()
- if build_data["activated"]:
- return build_data["revision"]
- except: # pylint: disable=bare-except
- # Sometimes build data is incomplete, as was the related build.
- pass
+ build = version.build_by_variant(variant)
+ if build.activated:
+ return githash
return None
-def find_changed_tests( # pylint: disable=too-many-locals
- branch_name, base_commit, max_revisions, buildvariant, check_evergreen):
- """Find the changed tests.
+def find_changed_tests( # pylint: disable=too-many-locals,too-many-arguments
+ branch_name, base_commit, max_revisions, buildvariant, project, check_evergreen, evg_api):
+ """
+ Find the changed tests.
Use git to find which files have changed in this patch.
TODO: This should be expanded to search for enterprise modules.
The returned file paths are in normalized form (see os.path.normpath(path)).
+
+ :param branch_name: Branch being run against.
+ :param base_commit: Commit changes are made on top of.
+ :param max_revisions: Max number of revisions to search through.
+ :param buildvariant: Build variant burn is being run on.
+ :param project: Project that is being run on.
+ :param check_evergreen: Should evergreen be checked for an activated build.
+ :param evg_api: Evergreen api.
+ :returns: List of changed tests.
"""
changed_tests = []
@@ -242,7 +235,7 @@ def find_changed_tests( # pylint: disable=too-many-locals
# previous commit when trying to find the most recent preceding commit that has been
# activated.
revs_to_check = repo.git_rev_list([base_commit, "--max-count=200", "--skip=1"]).splitlines()
- last_activated = find_last_activated_task(revs_to_check, buildvariant, branch_name)
+ last_activated = find_last_activated_task(revs_to_check, buildvariant, project, evg_api)
if last_activated is None:
# When the current commit is the first time 'buildvariant' has run, there won't be a
# commit among 'revs_to_check' that's been activated in Evergreen. We handle this by
@@ -289,7 +282,7 @@ def find_excludes(selector_file):
return ([], [], [])
with open(selector_file, "r") as fstream:
- yml = yaml.load(fstream)
+ yml = yaml.safe_load(fstream)
try:
js_test = yml["selector"]["js_test"]
@@ -543,11 +536,11 @@ def _generate_timeouts(options, commands, test, task_avg_test_runtime_stats):
commands.append(cmd_timeout.validate().resolve())
-def _get_task_runtime_history(evergreen_api, project, task, variant):
+def _get_task_runtime_history(evg_api, project, task, variant):
"""
Fetch historical average runtime for all tests in a task from Evergreen API.
- :param evergreen_api: Evergreen API.
+ :param evg_api: Evergreen API.
:param project: Project name.
:param task: Task name.
:param variant: Variant name.
@@ -556,10 +549,10 @@ def _get_task_runtime_history(evergreen_api, project, task, variant):
try:
end_date = datetime.datetime.utcnow().replace(microsecond=0)
start_date = end_date - datetime.timedelta(days=AVG_TEST_RUNTIME_ANALYSIS_DAYS)
- data = evergreen_api.test_stats_by_project(
- project, after_date=start_date.strftime("%Y-%m-%d"),
- before_date=end_date.strftime("%Y-%m-%d"), tasks=[task], variants=[variant],
- group_by="test", group_num_days=AVG_TEST_RUNTIME_ANALYSIS_DAYS)
+ data = evg_api.test_stats_by_project(project, after_date=start_date.strftime("%Y-%m-%d"),
+ before_date=end_date.strftime("%Y-%m-%d"),
+ tasks=[task], variants=[variant], group_by="test",
+ group_num_days=AVG_TEST_RUNTIME_ANALYSIS_DAYS)
test_runtimes = teststats.TestStats(data).get_tests_runtimes()
LOGGER.debug("Test_runtime data parsed from Evergreen history: %s", test_runtimes)
return test_runtimes
@@ -572,8 +565,7 @@ def _get_task_runtime_history(evergreen_api, project, task, variant):
raise
-def create_generate_tasks_config(evergreen_api, evg_config, options, tests_by_task,
- include_gen_task):
+def create_generate_tasks_config(evg_api, evg_config, options, tests_by_task, include_gen_task):
"""Create the config for the Evergreen generate.tasks file."""
# pylint: disable=too-many-locals
task_specs = []
@@ -582,8 +574,8 @@ def create_generate_tasks_config(evergreen_api, evg_config, options, tests_by_ta
task_names.append(BURN_IN_TESTS_GEN_TASK)
for task in sorted(tests_by_task):
multiversion_path = tests_by_task[task].get("use_multiversion")
- task_avg_test_runtime_stats = _get_task_runtime_history(evergreen_api, options.project,
- task, options.buildvariant)
+ task_avg_test_runtime_stats = _get_task_runtime_history(evg_api, options.project, task,
+ options.buildvariant)
for test_num, test in enumerate(tests_by_task[task]["tests"]):
sub_task_name = _sub_task_name(options, task, test_num)
task_names.append(sub_task_name)
@@ -612,18 +604,20 @@ def create_generate_tasks_config(evergreen_api, evg_config, options, tests_by_ta
return evg_config
-def create_tests_by_task(options):
+def create_tests_by_task(options, evg_api):
"""
Create a list of tests by task.
:param options: Options.
+ :param evg_api: Evergreen api.
:return: Tests by task
"""
# Parse the Evergreen project configuration file.
evergreen_conf = evergreen.parse_evergreen_file(EVERGREEN_FILE)
changed_tests = find_changed_tests(options.branch, options.base_commit, options.max_revisions,
- options.buildvariant, options.check_evergreen)
+ options.buildvariant, options.project,
+ options.check_evergreen, evg_api)
exclude_suites, exclude_tasks, exclude_tests = find_excludes(SELECTOR_FILE)
changed_tests = filter_tests(changed_tests, exclude_tests)
@@ -640,11 +634,11 @@ def create_tests_by_task(options):
return tests_by_task
-def create_generate_tasks_file(evergreen_api, options, tests_by_task):
+def create_generate_tasks_file(evg_api, options, tests_by_task):
"""Create the Evergreen generate.tasks file."""
evg_config = Configuration()
- evg_config = create_generate_tasks_config(evergreen_api, evg_config, options, tests_by_task,
+ evg_config = create_generate_tasks_config(evg_api, evg_config, options, tests_by_task,
include_gen_task=True)
_write_json_file(evg_config.to_map(), options.generate_tasks_file)
@@ -676,7 +670,7 @@ def run_tests(no_exec, tests_by_task, resmoke_cmd, report_file):
_write_json_file(test_results, report_file)
-def main(evergreen_api):
+def main(evg_api):
"""Execute Main program."""
logging.basicConfig(
@@ -700,13 +694,13 @@ def main(evergreen_api):
# Run the executor finder.
else:
- tests_by_task = create_tests_by_task(options)
+ tests_by_task = create_tests_by_task(options, evg_api)
if options.test_list_outfile:
_write_json_file(tests_by_task, options.test_list_outfile)
if options.generate_tasks_file:
- create_generate_tasks_file(evergreen_api, options, tests_by_task)
+ create_generate_tasks_file(evg_api, options, tests_by_task)
else:
run_tests(options.no_exec, tests_by_task, resmoke_cmd, options.report_file)
diff --git a/buildscripts/tests/test_burn_in_tests.py b/buildscripts/tests/test_burn_in_tests.py
index ac0f8fe44da..90b83758675 100644
--- a/buildscripts/tests/test_burn_in_tests.py
+++ b/buildscripts/tests/test_burn_in_tests.py
@@ -870,94 +870,47 @@ class RunTests(unittest.TestCase):
class FindLastActivated(unittest.TestCase):
-
- REVISION_BUILDS = {
- "rev1": {
- "not_mongodb_mongo_master_variant1_build1": {"activated": False}, # force line break
- "mongodb_mongo_unmaster_variant_build1": {"activated": True},
- "mongodb_mongo_master_variant1_build1": {"activated": True},
- "mongodb_mongo_master_variant2_build1": {"activated": False},
- "mongodb_mongo_master_variant3_build1": {"activated": False}
- },
- "rev2": {
- "not_mongodb_mongo_master_variant1_build1": {"activated": True},
- "mongodb_mongo_unmaster_variant_build1": {"activated": True},
- "mongodb_mongo_master_variant1_build1": {"activated": True},
- "mongodb_mongo_master_variant2_build1": {"activated": False}
- },
- "rev3": {
- "not_mongodb_mongo_master_variant1_build1": {"activated": True},
- "mongodb_mongo_unmaster_variant_build1": {"activated": True},
- "mongodb_mongo_master_variant1_build1": {"activated": True},
- "mongodb_mongo_master_variant2_build1": {"activated": False},
- },
- "rev4": {
- "not_mongodb_mongo_master_variant1_build1": {"activated": True},
- "mongodb_mongo_unmaster_variant_build1": {"activated": True},
- "mongodb_mongo_master_variant1_build1": {"activated": True}, # force line break
- "mongodb_mongo_master_variant2_build1": {"activated": False},
- "mongodb_mongo_master_variant3_build1": {"activated": True}
- },
- }
-
- @staticmethod
- def builds_url(build):
- """Return build URL."""
- return "{}{}builds/{}".format(burn_in.API_SERVER_DEFAULT, burn_in.API_REST_PREFIX, build)
-
- @staticmethod
- def revisions_url(project, revision):
- """Return revisions URL."""
- return "{}{}projects/{}/revisions/{}".format(burn_in.API_SERVER_DEFAULT,
- burn_in.API_REST_PREFIX, project, revision)
-
- @staticmethod
- def load_urls(request, project, revision_builds):
- """Store request in URLs to support REST APIs."""
-
- for revision in revision_builds:
- builds = revision_builds[revision]
- # The 'revisions' endpoint contains the list of builds.
- url = FindLastActivated.revisions_url(project, revision)
- build_list = []
- for build in builds:
- build_list.append("{}_{}".format(build, revision))
- build_data = {"builds": build_list}
- request.put(url, None, build_data)
-
- for build in builds:
- # The 'builds' endpoint contains the activated & revision field.
- url = FindLastActivated.builds_url("{}_{}".format(build, revision))
- build_data = builds[build]
- build_data["revision"] = revision
- request.put(url, None, build_data)
-
- def _test_find_last_activated_task(self, branch, variant, revision,
- revisions=REVISION_BUILDS.keys()):
- with patch(BURN_IN + ".requests", MockRequests()),\
- patch(EVG_CLIENT + ".read_evg_config", return_value=None):
- self.load_urls(burn_in.requests, "mongodb-mongo-master", self.REVISION_BUILDS)
- last_revision = burn_in.find_last_activated_task(revisions, variant, branch)
- self.assertEqual(last_revision, revision)
-
def test_find_last_activated_task_first_rev(self):
- self._test_find_last_activated_task("master", "variant1", "rev1")
+ rev_list = ["rev1", "rev2", "rev3"]
+ variant = "build_variant_0"
+ branch = "master"
+ evg_api = MagicMock()
+
+ revision = burn_in.find_last_activated_task(rev_list, variant, branch, evg_api)
+ self.assertEqual(revision, rev_list[0])
def test_find_last_activated_task_last_rev(self):
- self._test_find_last_activated_task("master", "variant3", "rev4")
+ rev_list = ["rev1", "rev2", "rev3"]
+ variant = "build_variant_0"
+ branch = "master"
+ evg_api = MagicMock()
+ evg_api.version_by_id.return_value.build_by_variant.side_effect = [
+ MagicMock(activated=False),
+ MagicMock(activated=False),
+ MagicMock(activated=True),
+ ]
- def test_find_last_activated_task_no_rev(self):
- self._test_find_last_activated_task("master", "variant2", None)
+ revision = burn_in.find_last_activated_task(rev_list, variant, branch, evg_api)
+ self.assertEqual(revision, rev_list[2])
- def test_find_last_activated_task_no_variant(self):
- self._test_find_last_activated_task("master", "novariant", None)
+ def test_find_last_activated_task_no_rev(self):
+ rev_list = ["rev1", "rev2", "rev3"]
+ variant = "build_variant_0"
+ branch = "master"
+ evg_api = MagicMock()
+ evg_api.version_by_id.return_value.build_by_variant.return_value.activated = False
- def test_find_last_activated_task_no_branch(self):
- with self.assertRaises(AttributeError):
- self._test_find_last_activated_task("nobranch", "variant2", None)
+ revision = burn_in.find_last_activated_task(rev_list, variant, branch, evg_api)
+ self.assertIsNone(revision)
def test_find_last_activated_norevisions(self):
- self._test_find_last_activated_task("master", "novariant", None, [])
+ rev_list = []
+ variant = "build_variant_0"
+ branch = "master"
+ evg_api = MagicMock()
+
+ revision = burn_in.find_last_activated_task(rev_list, variant, branch, evg_api)
+ self.assertIsNone(revision)
MEMBERS_MAP = {
@@ -1175,6 +1128,7 @@ class FindChangedTests(unittest.TestCase):
self, commit, max_revisions, variant, check_evg, rev1, rev2, rev_diff, untracked_files,
last_activated_task=None):
branch = "master"
+ project = "project"
# pylint: disable=attribute-defined-outside-init
self.rev1 = rev1
self.rev2 = rev2
@@ -1187,11 +1141,12 @@ class FindChangedTests(unittest.TestCase):
self.expected_changed_tests += rev_diff.get(commit, [])
self.expected_changed_tests += untracked_files
# pylint: enable=attribute-defined-outside-init
- with patch(EVG_CLIENT + ".read_evg_config", return_value=None),\
- patch(GIT + ".Repository", self._mock_git_repository),\
+ evg_api = MagicMock()
+ with patch(GIT + ".Repository", self._mock_git_repository),\
patch("os.path.isfile", return_value=True),\
patch(BURN_IN + ".find_last_activated_task", return_value=last_activated_task):
- return burn_in.find_changed_tests(branch, commit, max_revisions, variant, check_evg)
+ return burn_in.find_changed_tests(branch, commit, max_revisions, variant, project,
+ check_evg, evg_api)
def test_find_changed_tests(self):
commit = "3"
@@ -1350,25 +1305,3 @@ class MockGitRepository(object):
modified_files = [" M {}".format(untracked) for untracked in diff_list]
untracked_files = ["?? {}".format(untracked) for untracked in self.untracked_files]
return "\n".join(modified_files + untracked_files)
-
-
-class MockResponse(object):
- def __init__(self, response, json_data):
- self.response = response
- self.json_data = json_data
-
- def json(self):
- return self.json_data
-
-
-class MockRequests(object):
- def __init__(self):
- self.responses = {}
-
- def put(self, url, response, json_data):
- self.responses[url] = MockResponse(response, json_data)
-
- def get(self, url):
- if url in self.responses:
- return self.responses[url]
- return None
diff --git a/buildscripts/util/read_config.py b/buildscripts/util/read_config.py
index aad2b9a150c..a937908670a 100644
--- a/buildscripts/util/read_config.py
+++ b/buildscripts/util/read_config.py
@@ -39,6 +39,6 @@ def read_config_file(config_file):
config_file_data = {}
if config_file:
with open(config_file) as file_handle:
- config_file_data = yaml.load(file_handle)
+ config_file_data = yaml.safe_load(file_handle)
return config_file_data