| #!/usr/bin/env python3 |
| # -*- coding: utf-8 -*- |
| # Copyright 2019 The ChromiumOS Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Tests for modifying a tryjob.""" |
| |
| |
| import json |
| import unittest |
| import unittest.mock as mock |
| |
| import get_llvm_hash |
| import modify_a_tryjob |
| import test_helpers |
| import update_packages_and_run_tests |
| import update_tryjob_status |
| |
| |
| class ModifyATryjobTest(unittest.TestCase): |
| """Unittests for modifying a tryjob.""" |
| |
| def testNoTryjobsInStatusFile(self): |
| bisect_test_contents = {"start": 369410, "end": 369420, "jobs": []} |
| |
| # Create a temporary .JSON file to simulate a .JSON file that has bisection |
| # contents. |
| with test_helpers.CreateTemporaryJsonFile() as temp_json_file: |
| with open(temp_json_file, "w") as f: |
| test_helpers.WritePrettyJsonFile(bisect_test_contents, f) |
| |
| revision_to_modify = 369411 |
| |
| args_output = test_helpers.ArgsOutputTest() |
| args_output.builders = None |
| args_output.options = None |
| |
| # Verify the exception is raised there are no tryjobs in the status file |
| # and the mode is not to 'add' a tryjob. |
| with self.assertRaises(SystemExit) as err: |
| modify_a_tryjob.PerformTryjobModification( |
| revision_to_modify, |
| modify_a_tryjob.ModifyTryjob.REMOVE, |
| temp_json_file, |
| args_output.extra_change_lists, |
| args_output.options, |
| args_output.builders, |
| args_output.chroot_path, |
| args_output.verbose, |
| ) |
| |
| self.assertEqual( |
| str(err.exception), "No tryjobs in %s" % temp_json_file |
| ) |
| |
| # Simulate the behavior of `FindTryjobIndex()` when the index of the tryjob |
| # was not found. |
| @mock.patch.object( |
| update_tryjob_status, "FindTryjobIndex", return_value=None |
| ) |
| def testNoTryjobIndexFound(self, mock_find_tryjob_index): |
| bisect_test_contents = { |
| "start": 369410, |
| "end": 369420, |
| "jobs": [ |
| {"rev": 369411, "status": "pending", "buildbucket_id": 1200} |
| ], |
| } |
| |
| # Create a temporary .JSON file to simulate a .JSON file that has bisection |
| # contents. |
| with test_helpers.CreateTemporaryJsonFile() as temp_json_file: |
| with open(temp_json_file, "w") as f: |
| test_helpers.WritePrettyJsonFile(bisect_test_contents, f) |
| |
| revision_to_modify = 369412 |
| |
| args_output = test_helpers.ArgsOutputTest() |
| args_output.builders = None |
| args_output.options = None |
| |
| # Verify the exception is raised when the index of the tryjob was not |
| # found in the status file and the mode is not to 'add' a tryjob. |
| with self.assertRaises(ValueError) as err: |
| modify_a_tryjob.PerformTryjobModification( |
| revision_to_modify, |
| modify_a_tryjob.ModifyTryjob.REMOVE, |
| temp_json_file, |
| args_output.extra_change_lists, |
| args_output.options, |
| args_output.builders, |
| args_output.chroot_path, |
| args_output.verbose, |
| ) |
| |
| self.assertEqual( |
| str(err.exception), |
| "Unable to find tryjob for %d in %s" |
| % (revision_to_modify, temp_json_file), |
| ) |
| |
| mock_find_tryjob_index.assert_called_once() |
| |
| # Simulate the behavior of `FindTryjobIndex()` when the index of the tryjob |
| # was found. |
| @mock.patch.object(update_tryjob_status, "FindTryjobIndex", return_value=0) |
| def testSuccessfullyRemovedTryjobInStatusFile(self, mock_find_tryjob_index): |
| bisect_test_contents = { |
| "start": 369410, |
| "end": 369420, |
| "jobs": [ |
| {"rev": 369414, "status": "pending", "buildbucket_id": 1200} |
| ], |
| } |
| |
| # Create a temporary .JSON file to simulate a .JSON file that has bisection |
| # contents. |
| with test_helpers.CreateTemporaryJsonFile() as temp_json_file: |
| with open(temp_json_file, "w") as f: |
| test_helpers.WritePrettyJsonFile(bisect_test_contents, f) |
| |
| revision_to_modify = 369414 |
| |
| args_output = test_helpers.ArgsOutputTest() |
| args_output.builders = None |
| args_output.options = None |
| |
| modify_a_tryjob.PerformTryjobModification( |
| revision_to_modify, |
| modify_a_tryjob.ModifyTryjob.REMOVE, |
| temp_json_file, |
| args_output.extra_change_lists, |
| args_output.options, |
| args_output.builders, |
| args_output.chroot_path, |
| args_output.verbose, |
| ) |
| |
| # Verify that the tryjob was removed from the status file. |
| with open(temp_json_file) as status_file: |
| bisect_contents = json.load(status_file) |
| |
| expected_file_contents = { |
| "start": 369410, |
| "end": 369420, |
| "jobs": [], |
| } |
| |
| self.assertDictEqual(bisect_contents, expected_file_contents) |
| |
| mock_find_tryjob_index.assert_called_once() |
| |
| # Simulate the behavior of `RunTryJobs()` when successfully submitted a |
| # tryjob. |
| @mock.patch.object(update_packages_and_run_tests, "RunTryJobs") |
| # Simulate the behavior of `FindTryjobIndex()` when the index of the tryjob |
| # was found. |
| @mock.patch.object(update_tryjob_status, "FindTryjobIndex", return_value=0) |
| def testSuccessfullyRelaunchedTryjob( |
| self, mock_find_tryjob_index, mock_run_tryjob |
| ): |
| |
| bisect_test_contents = { |
| "start": 369410, |
| "end": 369420, |
| "jobs": [ |
| { |
| "rev": 369411, |
| "status": "bad", |
| "link": "https://some_tryjob_link.com", |
| "buildbucket_id": 1200, |
| "cl": 123, |
| "extra_cls": None, |
| "options": None, |
| "builder": ["some-builder-tryjob"], |
| } |
| ], |
| } |
| |
| tryjob_result = [ |
| {"link": "https://some_new_tryjob_link.com", "buildbucket_id": 20} |
| ] |
| |
| mock_run_tryjob.return_value = tryjob_result |
| |
| # Create a temporary .JSON file to simulate a .JSON file that has bisection |
| # contents. |
| with test_helpers.CreateTemporaryJsonFile() as temp_json_file: |
| with open(temp_json_file, "w") as f: |
| test_helpers.WritePrettyJsonFile(bisect_test_contents, f) |
| |
| revision_to_modify = 369411 |
| |
| args_output = test_helpers.ArgsOutputTest() |
| args_output.builders = None |
| args_output.options = None |
| |
| modify_a_tryjob.PerformTryjobModification( |
| revision_to_modify, |
| modify_a_tryjob.ModifyTryjob.RELAUNCH, |
| temp_json_file, |
| args_output.extra_change_lists, |
| args_output.options, |
| args_output.builders, |
| args_output.chroot_path, |
| args_output.verbose, |
| ) |
| |
| # Verify that the tryjob's information was updated after submtting the |
| # tryjob. |
| with open(temp_json_file) as status_file: |
| bisect_contents = json.load(status_file) |
| |
| expected_file_contents = { |
| "start": 369410, |
| "end": 369420, |
| "jobs": [ |
| { |
| "rev": 369411, |
| "status": "pending", |
| "link": "https://some_new_tryjob_link.com", |
| "buildbucket_id": 20, |
| "cl": 123, |
| "extra_cls": None, |
| "options": None, |
| "builder": ["some-builder-tryjob"], |
| } |
| ], |
| } |
| |
| self.assertDictEqual(bisect_contents, expected_file_contents) |
| |
| mock_find_tryjob_index.assert_called_once() |
| |
| mock_run_tryjob.assert_called_once() |
| |
| # Simulate the behavior of `FindTryjobIndex()` when the index of the tryjob |
| # was found. |
| @mock.patch.object(update_tryjob_status, "FindTryjobIndex", return_value=0) |
| def testAddingTryjobThatAlreadyExists(self, mock_find_tryjob_index): |
| bisect_test_contents = { |
| "start": 369410, |
| "end": 369420, |
| "jobs": [ |
| {"rev": 369411, "status": "bad", "builder": ["some-builder"]} |
| ], |
| } |
| |
| # Create a temporary .JSON file to simulate a .JSON file that has bisection |
| # contents. |
| with test_helpers.CreateTemporaryJsonFile() as temp_json_file: |
| with open(temp_json_file, "w") as f: |
| test_helpers.WritePrettyJsonFile(bisect_test_contents, f) |
| |
| revision_to_add = 369411 |
| |
| # Index of the tryjob in 'jobs' list. |
| tryjob_index = 0 |
| |
| args_output = test_helpers.ArgsOutputTest() |
| args_output.options = None |
| |
| # Verify the exception is raised when the tryjob that is going to added |
| # already exists in the status file (found its index). |
| with self.assertRaises(ValueError) as err: |
| modify_a_tryjob.PerformTryjobModification( |
| revision_to_add, |
| modify_a_tryjob.ModifyTryjob.ADD, |
| temp_json_file, |
| args_output.extra_change_lists, |
| args_output.options, |
| args_output.builders, |
| args_output.chroot_path, |
| args_output.verbose, |
| ) |
| |
| self.assertEqual( |
| str(err.exception), |
| "Tryjob already exists (index is %d) in %s." |
| % (tryjob_index, temp_json_file), |
| ) |
| |
| mock_find_tryjob_index.assert_called_once() |
| |
| # Simulate the behavior of `FindTryjobIndex()` when the tryjob was not found. |
| @mock.patch.object( |
| update_tryjob_status, "FindTryjobIndex", return_value=None |
| ) |
| def testSuccessfullyDidNotAddTryjobOutsideOfBisectionBounds( |
| self, mock_find_tryjob_index |
| ): |
| |
| bisect_test_contents = { |
| "start": 369410, |
| "end": 369420, |
| "jobs": [{"rev": 369411, "status": "bad"}], |
| } |
| |
| # Create a temporary .JSON file to simulate a .JSON file that has bisection |
| # contents. |
| with test_helpers.CreateTemporaryJsonFile() as temp_json_file: |
| with open(temp_json_file, "w") as f: |
| test_helpers.WritePrettyJsonFile(bisect_test_contents, f) |
| |
| # Add a revision that is outside of 'start' and 'end'. |
| revision_to_add = 369450 |
| |
| args_output = test_helpers.ArgsOutputTest() |
| args_output.options = None |
| |
| # Verify the exception is raised when adding a tryjob that does not exist |
| # and is not within 'start' and 'end'. |
| with self.assertRaises(ValueError) as err: |
| modify_a_tryjob.PerformTryjobModification( |
| revision_to_add, |
| modify_a_tryjob.ModifyTryjob.ADD, |
| temp_json_file, |
| args_output.extra_change_lists, |
| args_output.options, |
| args_output.builders, |
| args_output.chroot_path, |
| args_output.verbose, |
| ) |
| |
| self.assertEqual( |
| str(err.exception), |
| "Failed to add tryjob to %s" % temp_json_file, |
| ) |
| |
| mock_find_tryjob_index.assert_called_once() |
| |
| # Simulate the behavior of `AddTryjob()` when successfully submitted the |
| # tryjob and constructed the tryjob information (a dictionary). |
| @mock.patch.object(modify_a_tryjob, "AddTryjob") |
| # Simulate the behavior of `GetLLVMHashAndVersionFromSVNOption()` when |
| # successfully retrieved the git hash of the revision to launch a tryjob for. |
| @mock.patch.object( |
| get_llvm_hash, |
| "GetLLVMHashAndVersionFromSVNOption", |
| return_value=("a123testhash1", 369418), |
| ) |
| # Simulate the behavior of `FindTryjobIndex()` when the tryjob was not found. |
| @mock.patch.object( |
| update_tryjob_status, "FindTryjobIndex", return_value=None |
| ) |
| def testSuccessfullyAddedTryjob( |
| self, mock_find_tryjob_index, mock_get_llvm_hash, mock_add_tryjob |
| ): |
| |
| bisect_test_contents = { |
| "start": 369410, |
| "end": 369420, |
| "jobs": [{"rev": 369411, "status": "bad"}], |
| } |
| |
| # Create a temporary .JSON file to simulate a .JSON file that has bisection |
| # contents. |
| with test_helpers.CreateTemporaryJsonFile() as temp_json_file: |
| with open(temp_json_file, "w") as f: |
| test_helpers.WritePrettyJsonFile(bisect_test_contents, f) |
| |
| # Add a revision that is outside of 'start' and 'end'. |
| revision_to_add = 369418 |
| |
| args_output = test_helpers.ArgsOutputTest() |
| args_output.options = None |
| |
| new_tryjob_info = { |
| "rev": revision_to_add, |
| "status": "pending", |
| "options": args_output.options, |
| "extra_cls": args_output.extra_change_lists, |
| "builder": args_output.builders, |
| } |
| |
| mock_add_tryjob.return_value = new_tryjob_info |
| |
| modify_a_tryjob.PerformTryjobModification( |
| revision_to_add, |
| modify_a_tryjob.ModifyTryjob.ADD, |
| temp_json_file, |
| args_output.extra_change_lists, |
| args_output.options, |
| args_output.builders, |
| args_output.chroot_path, |
| args_output.verbose, |
| ) |
| |
| # Verify that the tryjob was added to the status file. |
| with open(temp_json_file) as status_file: |
| bisect_contents = json.load(status_file) |
| |
| expected_file_contents = { |
| "start": 369410, |
| "end": 369420, |
| "jobs": [{"rev": 369411, "status": "bad"}, new_tryjob_info], |
| } |
| |
| self.assertDictEqual(bisect_contents, expected_file_contents) |
| |
| mock_find_tryjob_index.assert_called_once() |
| |
| mock_get_llvm_hash.assert_called_once_with(revision_to_add) |
| |
| mock_add_tryjob.assert_called_once() |
| |
| # Simulate the behavior of `FindTryjobIndex()` when the tryjob was found. |
| @mock.patch.object(update_tryjob_status, "FindTryjobIndex", return_value=0) |
| def testModifyATryjobOptionDoesNotExist(self, mock_find_tryjob_index): |
| bisect_test_contents = { |
| "start": 369410, |
| "end": 369420, |
| "jobs": [{"rev": 369414, "status": "bad"}], |
| } |
| |
| # Create a temporary .JSON file to simulate a .JSON file that has bisection |
| # contents. |
| with test_helpers.CreateTemporaryJsonFile() as temp_json_file: |
| with open(temp_json_file, "w") as f: |
| test_helpers.WritePrettyJsonFile(bisect_test_contents, f) |
| |
| # Add a revision that is outside of 'start' and 'end'. |
| revision_to_modify = 369414 |
| |
| args_output = test_helpers.ArgsOutputTest() |
| args_output.builders = None |
| args_output.options = None |
| |
| # Verify the exception is raised when the modify a tryjob option does not |
| # exist. |
| with self.assertRaises(ValueError) as err: |
| modify_a_tryjob.PerformTryjobModification( |
| revision_to_modify, |
| "remove_link", |
| temp_json_file, |
| args_output.extra_change_lists, |
| args_output.options, |
| args_output.builders, |
| args_output.chroot_path, |
| args_output.verbose, |
| ) |
| |
| self.assertEqual( |
| str(err.exception), |
| 'Invalid "modify_tryjob" option provided: remove_link', |
| ) |
| |
| mock_find_tryjob_index.assert_called_once() |
| |
| |
| if __name__ == "__main__": |
| unittest.main() |