diff options
Diffstat (limited to 'llvm_tools/llvm_bisection_unittest.py')
-rwxr-xr-x | llvm_tools/llvm_bisection_unittest.py | 552 |
1 files changed, 193 insertions, 359 deletions
diff --git a/llvm_tools/llvm_bisection_unittest.py b/llvm_tools/llvm_bisection_unittest.py index e730293b..8478f82e 100755 --- a/llvm_tools/llvm_bisection_unittest.py +++ b/llvm_tools/llvm_bisection_unittest.py @@ -16,45 +16,50 @@ import unittest.mock as mock import chroot import get_llvm_hash +import git_llvm_rev import llvm_bisection import modify_a_tryjob import test_helpers -import update_tryjob_status class LLVMBisectionTest(unittest.TestCase): """Unittests for LLVM bisection.""" - def testStartAndEndDoNotMatchJsonStartAndEnd(self): + def testGetRemainingRangePassed(self): start = 100 end = 150 - json_start = 110 - json_end = 150 - - # Verify the exception is raised when the start and end revision for LLVM - # bisection do not match the .JSON's 'start' and 'end' values. - with self.assertRaises(ValueError) as err: - llvm_bisection._ValidateStartAndEndAgainstJSONStartAndEnd( - start, end, json_start, json_end) - - expected_error_message = ('The start %d or the end %d version provided is ' - 'different than "start" %d or "end" %d in the ' - '.JSON file' % (start, end, json_start, json_end)) - - self.assertEqual(str(err.exception), expected_error_message) - - def testStartAndEndMatchJsonStartAndEnd(self): - start = 100 - end = 150 + test_tryjobs = [{ + 'rev': 110, + 'status': 'good', + 'link': 'https://some_tryjob_1_url.com' + }, { + 'rev': 120, + 'status': 'good', + 'link': 'https://some_tryjob_2_url.com' + }, { + 'rev': 130, + 'status': 'pending', + 'link': 'https://some_tryjob_3_url.com' + }, { + 'rev': 135, + 'status': 'skip', + 'link': 'https://some_tryjob_4_url.com' + }, { + 'rev': 140, + 'status': 'bad', + 'link': 'https://some_tryjob_5_url.com' + }] - json_start = 100 - json_end = 150 + # Tuple consists of the new good revision, the new bad revision, a set of + # 'pending' revisions, and a set of 'skip' revisions. + expected_revisions_tuple = 120, 140, {130}, {135} - llvm_bisection._ValidateStartAndEndAgainstJSONStartAndEnd( - start, end, json_start, json_end) + self.assertEqual( + llvm_bisection.GetRemainingRange(start, end, test_tryjobs), + expected_revisions_tuple) - def testTryjobStatusIsMissing(self): + def testGetRemainingRangeFailedWithMissingStatus(self): start = 100 end = 150 @@ -72,18 +77,14 @@ class LLVMBisectionTest(unittest.TestCase): 'link': 'https://some_tryjob_3_url.com' }] - # Verify the exception is raised when a tryjob does not have a value for - # the 'status' key or the 'status' key is missing. with self.assertRaises(ValueError) as err: - llvm_bisection.GetStartAndEndRevision(start, end, test_tryjobs) - - expected_error_message = ( - '"status" is missing or has no value, please ' - 'go to %s and update it' % test_tryjobs[1]['link']) + llvm_bisection.GetRemainingRange(start, end, test_tryjobs) - self.assertEqual(str(err.exception), expected_error_message) + error_message = ('"status" is missing or has no value, please ' + 'go to %s and update it' % test_tryjobs[1]['link']) + self.assertEqual(str(err.exception), error_message) - def testGoodRevisionGreaterThanBadRevision(self): + def testGetRemainingRangeFailedWithInvalidRange(self): start = 100 end = 150 @@ -101,206 +102,68 @@ class LLVMBisectionTest(unittest.TestCase): 'link': 'https://some_tryjob_3_url.com' }] - # Verify the exception is raised when the new 'start' revision is greater - # than the new 'bad' revision for bisection (i.e. bisection is broken). with self.assertRaises(AssertionError) as err: - llvm_bisection.GetStartAndEndRevision(start, end, test_tryjobs) + llvm_bisection.GetRemainingRange(start, end, test_tryjobs) - expected_error_message = ( - 'Bisection is broken because %d (good) is >= ' - '%d (bad)' % (test_tryjobs[2]['rev'], test_tryjobs[0]['rev'])) + expected_error_message = ('Bisection is broken because %d (good) is >= ' + '%d (bad)' % + (test_tryjobs[2]['rev'], test_tryjobs[0]['rev'])) self.assertEqual(str(err.exception), expected_error_message) - def testSuccessfullyGetNewStartAndNewEndRevision(self): - start = 100 - end = 150 - - test_tryjobs = [{ - 'rev': 110, - 'status': 'good', - 'link': 'https://some_tryjob_1_url.com' - }, { - 'rev': 120, - 'status': 'good', - 'link': 'https://some_tryjob_2_url.com' - }, { - 'rev': 130, - 'status': 'pending', - 'link': 'https://some_tryjob_3_url.com' - }, { - 'rev': 135, - 'status': 'skip', - 'link': 'https://some_tryjob_4_url.com' - }, { - 'rev': 140, - 'status': 'bad', - 'link': 'https://some_tryjob_5_url.com' - }] - - # Tuple consists of the new good revision, the new bad revision, a set of - # 'pending' revisions, and a set of 'skip' revisions. - expected_revisions_tuple = 120, 140, {130}, {135} - - self.assertTupleEqual( - llvm_bisection.GetStartAndEndRevision(start, end, test_tryjobs), - expected_revisions_tuple) - - @mock.patch.object(get_llvm_hash, 'GetGitHashFrom') - def testNoRevisionsBetweenStartAndEnd(self, mock_get_git_hash): - start = 100 - end = 110 - - test_pending_revisions = {107} - test_skip_revisions = {101, 102, 103, 104, 108, 109} - - # Simulate behavior of `GetGitHashFrom()` when the revision does not - # exist in the LLVM source tree. - def MockGetGitHashForRevisionRaiseException(_src_path, _revision): - raise ValueError('Revision does not exist') - - mock_get_git_hash.side_effect = MockGetGitHashForRevisionRaiseException - - parallel = 3 - - abs_path_to_src = '/abs/path/to/src' - - self.assertListEqual( - llvm_bisection.GetRevisionsBetweenBisection( - start, end, parallel, abs_path_to_src, test_pending_revisions, - test_skip_revisions), []) - - # Assume llvm_bisection module has imported GetGitHashFrom @mock.patch.object(get_llvm_hash, 'GetGitHashFrom') - def testSuccessfullyRetrievedRevisionsBetweenStartAndEnd( - self, mock_get_git_hash): - - start = 100 - end = 110 - - test_pending_revisions = set() - test_skip_revisions = {101, 102, 103, 104, 106, 108, 109} - + def testGetCommitsBetweenPassed(self, mock_get_git_hash): + start = git_llvm_rev.base_llvm_revision + end = start + 10 + test_pending_revisions = {start + 7} + test_skip_revisions = { + start + 1, start + 2, start + 4, start + 8, start + 9 + } parallel = 3 - abs_path_to_src = '/abs/path/to/src' - # Valid revision that exist in the LLVM source tree between 'start' and - # 'end' and were not in the 'pending' set or 'skip' set. - expected_revisions_between_start_and_end = [105, 107] - - self.assertListEqual( - llvm_bisection.GetRevisionsBetweenBisection( - start, end, parallel, abs_path_to_src, test_pending_revisions, - test_skip_revisions), expected_revisions_between_start_and_end) - - self.assertEqual(mock_get_git_hash.call_count, 2) + revs = ['a123testhash3', 'a123testhash5'] + mock_get_git_hash.side_effect = revs - # Simulate behavior of `GetGitHashFrom()` when successfully retrieved - # a list git hashes for each revision in the revisions list. - # Assume llvm_bisection module has imported GetGitHashFrom - @mock.patch.object(get_llvm_hash, 'GetGitHashFrom') - # Simulate behavior of `GetRevisionsBetweenBisection()` when successfully - # retrieved a list of valid revisions between 'start' and 'end'. - @mock.patch.object(llvm_bisection, 'GetRevisionsBetweenBisection') - # Simulate behavior of `CreatTempLLVMRepo()` when successfully created a - # worktree when a source path was not provided. - @mock.patch.object(get_llvm_hash, 'CreateTempLLVMRepo') - def testSuccessfullyGetRevisionsListAndHashList( - self, mock_create_temp_llvm_repo, mock_get_revisions_between_bisection, - mock_get_git_hash): - - expected_revisions_and_hash_tuple = ([102, 105, 108], [ - 'a123testhash1', 'a123testhash2', 'a123testhash3' - ]) - - @test_helpers.CallCountsToMockFunctions - def MockGetGitHashForRevision(call_count, _src_path, _rev): - # Simulate retrieving the git hash for the revision. - if call_count < 3: - return expected_revisions_and_hash_tuple[1][call_count] - - assert False, 'Called `GetGitHashFrom()` more than expected.' - - temp_worktree = '/abs/path/to/tmpDir' - - mock_create_temp_llvm_repo.return_value.__enter__.return_value.name = \ - temp_worktree - - # Simulate the valid revisions list. - mock_get_revisions_between_bisection.return_value = \ - expected_revisions_and_hash_tuple[0] - - # Simulate behavior of `GetGitHashFrom()` by using the testing - # function. - mock_get_git_hash.side_effect = MockGetGitHashForRevision - - start = 100 - end = 110 - parallel = 3 - src_path = None - pending_revisions = {103, 104} - skip_revisions = {101, 106, 107, 109} + git_hashes = [ + git_llvm_rev.base_llvm_revision + 3, git_llvm_rev.base_llvm_revision + 5 + ] - self.assertTupleEqual( - llvm_bisection.GetRevisionsListAndHashList( - start, end, parallel, src_path, pending_revisions, skip_revisions), - expected_revisions_and_hash_tuple) - - mock_get_revisions_between_bisection.assert_called_once() - - self.assertEqual(mock_get_git_hash.call_count, 3) + self.assertEqual( + llvm_bisection.GetCommitsBetween(start, end, parallel, abs_path_to_src, + test_pending_revisions, + test_skip_revisions), + (git_hashes, revs)) - def testSuccessfullyDieWithNoRevisionsError(self): + def testLoadStatusFilePassedWithExistingFile(self): start = 100 - end = 110 - - pending_revisions = {105, 108} - skip_revisions = {101, 102, 103, 104, 106, 107, 109} - - expected_no_revisions_message = ('No revisions between start %d and end ' - '%d to create tryjobs' % (start, end)) - - expected_no_revisions_message += '\nThe following tryjobs are pending:\n' \ - + '\n'.join(str(rev) for rev in pending_revisions) - - expected_no_revisions_message += '\nThe following tryjobs were skipped:\n' \ - + '\n'.join(str(rev) for rev in skip_revisions) - - # Verify that an exception is raised when there are no revisions to launch - # tryjobs for between 'start' and 'end' and some tryjobs are 'pending'. - with self.assertRaises(ValueError) as err: - llvm_bisection.DieWithNoRevisionsError(start, end, skip_revisions, - pending_revisions) + end = 150 - self.assertEqual(str(err.exception), expected_no_revisions_message) + test_bisect_state = {'start': start, 'end': end, 'jobs': []} - # Simulate behavior of `FindTryjobIndex()` when the index of the tryjob was - # found. - @mock.patch.object(update_tryjob_status, 'FindTryjobIndex', return_value=0) - def testTryjobExistsInRevisionsToLaunch(self, mock_find_tryjob_index): - test_existing_jobs = [{'rev': 102, 'status': 'good'}] + # Simulate that the status file exists. + with test_helpers.CreateTemporaryJsonFile() as temp_json_file: + with open(temp_json_file, 'w') as f: + test_helpers.WritePrettyJsonFile(test_bisect_state, f) - revision_to_launch = [102] + self.assertEqual( + llvm_bisection.LoadStatusFile(temp_json_file, start, end), + test_bisect_state) - expected_revision_that_exists = 102 + def testLoadStatusFilePassedWithoutExistingFile(self): + start = 200 + end = 250 - with self.assertRaises(ValueError) as err: - llvm_bisection.CheckForExistingTryjobsInRevisionsToLaunch( - revision_to_launch, test_existing_jobs) + expected_bisect_state = {'start': start, 'end': end, 'jobs': []} - expected_found_tryjob_index_error_message = ( - 'Revision %d exists already ' - 'in "jobs"' % expected_revision_that_exists) + last_tested = '/abs/path/to/file_that_does_not_exist.json' self.assertEqual( - str(err.exception), expected_found_tryjob_index_error_message) - - mock_find_tryjob_index.assert_called_once() + llvm_bisection.LoadStatusFile(last_tested, start, end), + expected_bisect_state) @mock.patch.object(modify_a_tryjob, 'AddTryjob') - def testSuccessfullyUpdatedStatusFileWhenExceptionIsRaised( - self, mock_add_tryjob): + def testBisectPassed(self, mock_add_tryjob): git_hash_list = ['a123testhash1', 'a123testhash2', 'a123testhash3'] revisions_list = [102, 104, 106] @@ -343,11 +206,11 @@ class LLVMBisectionTest(unittest.TestCase): # Verify that the status file is updated when an exception happened when # attempting to launch a revision (i.e. progress is not lost). with self.assertRaises(ValueError) as err: - llvm_bisection.UpdateBisection( - revisions_list, git_hash_list, bisection_contents, temp_json_file, - packages, args_output.chroot_path, patch_file, - args_output.extra_change_lists, args_output.options, - args_output.builders, args_output.verbose) + llvm_bisection.Bisect(revisions_list, git_hash_list, bisection_contents, + temp_json_file, packages, args_output.chroot_path, + patch_file, args_output.extra_change_lists, + args_output.options, args_output.builders, + args_output.verbose) expected_bisection_contents = { 'start': @@ -368,121 +231,128 @@ class LLVMBisectionTest(unittest.TestCase): with open(temp_json_file) as f: json_contents = json.load(f) - self.assertDictEqual(json_contents, expected_bisection_contents) + self.assertEqual(json_contents, expected_bisection_contents) self.assertEqual(str(err.exception), 'Unable to launch tryjob') self.assertEqual(mock_add_tryjob.call_count, 3) - # Simulate behavior of `GetGitHashFrom()` when successfully retrieved - # the git hash of the bad revision. Assume llvm_bisection has imported - # GetGitHashFrom @mock.patch.object( - get_llvm_hash, 'GetGitHashFrom', return_value='a123testhash4') - def testCompletedBisectionWhenProvidedSrcPath(self, mock_get_git_hash): - last_tested = '/some/last/tested_file.json' + get_llvm_hash.LLVMHash, 'GetLLVMHash', return_value='a123testhash4') + @mock.patch.object(llvm_bisection, 'GetCommitsBetween') + @mock.patch.object(llvm_bisection, 'GetRemainingRange') + @mock.patch.object(llvm_bisection, 'LoadStatusFile') + @mock.patch.object(chroot, 'VerifyOutsideChroot', return_value=True) + def testMainPassed(self, mock_outside_chroot, mock_load_status_file, + mock_get_range, mock_get_revision_and_hash_list, + _mock_get_bad_llvm_hash): - src_path = '/abs/path/to/src/path' + start = 500 + end = 502 + cl = 1 - # The bad revision. - end = 150 + bisect_state = { + 'start': start, + 'end': end, + 'jobs': [{ + 'rev': 501, + 'status': 'bad', + 'cl': cl + }] + } - llvm_bisection._NoteCompletedBisection(last_tested, src_path, end) + skip_revisions = {501} + pending_revisions = {} - mock_get_git_hash.assert_called_once() + mock_load_status_file.return_value = bisect_state - # Simulate behavior of `GetLLVMHash()` when successfully retrieved - # the git hash of the bad revision. - @mock.patch.object( - get_llvm_hash.LLVMHash, 'GetLLVMHash', return_value='a123testhash5') - def testCompletedBisectionWhenNotProvidedSrcPath(self, mock_get_git_hash): - last_tested = '/some/last/tested_file.json' + mock_get_range.return_value = (start, end, pending_revisions, + skip_revisions) - src_path = None + mock_get_revision_and_hash_list.return_value = [], [] - # The bad revision. - end = 200 + args_output = test_helpers.ArgsOutputTest() + args_output.start_rev = start + args_output.end_rev = end + args_output.parallel = 3 + args_output.src_path = None + args_output.chroot_path = 'somepath' - llvm_bisection._NoteCompletedBisection(last_tested, src_path, end) + self.assertEqual( + llvm_bisection.main(args_output), + llvm_bisection.BisectionExitStatus.BISECTION_COMPLETE.value) - mock_get_git_hash.assert_called_once() + mock_outside_chroot.assert_called_once() - def testSuccessfullyLoadedStatusFile(self): - start = 100 - end = 150 + mock_load_status_file.assert_called_once() - test_bisect_contents = {'start': start, 'end': end, 'jobs': []} + mock_get_range.assert_called_once() - # Simulate that the status file exists. - with test_helpers.CreateTemporaryJsonFile() as temp_json_file: - with open(temp_json_file, 'w') as f: - test_helpers.WritePrettyJsonFile(test_bisect_contents, f) + mock_get_revision_and_hash_list.assert_called_once() - self.assertDictEqual( - llvm_bisection.LoadStatusFile(temp_json_file, start, end), - test_bisect_contents) + @mock.patch.object(llvm_bisection, 'LoadStatusFile') + @mock.patch.object(chroot, 'VerifyOutsideChroot', return_value=True) + def testMainFailedWithInvalidRange(self, mock_outside_chroot, + mock_load_status_file): - def testLoadedStatusFileThatDoesNotExist(self): - start = 200 - end = 250 + start = 500 + end = 502 - expected_bisect_contents = {'start': start, 'end': end, 'jobs': []} + bisect_state = { + 'start': start - 1, + 'end': end, + } - last_tested = '/abs/path/to/file_that_does_not_exist.json' + mock_load_status_file.return_value = bisect_state - self.assertDictEqual( - llvm_bisection.LoadStatusFile(last_tested, start, end), - expected_bisect_contents) - - # Simulate behavior of `_NoteCompletedBisection()` when there are no more - # tryjobs to launch between start and end, so bisection is complete. - @mock.patch.object(llvm_bisection, '_NoteCompletedBisection') - @mock.patch.object(llvm_bisection, 'GetRevisionsListAndHashList') - @mock.patch.object(llvm_bisection, 'GetStartAndEndRevision') - # Simulate behavior of `_ValidateStartAndEndAgainstJSONStartAndEnd()` when - # both start and end revisions match. - @mock.patch.object(llvm_bisection, - '_ValidateStartAndEndAgainstJSONStartAndEnd') + args_output = test_helpers.ArgsOutputTest() + args_output.start_rev = start + args_output.end_rev = end + args_output.parallel = 3 + args_output.src_path = None + + with self.assertRaises(ValueError) as err: + llvm_bisection.main(args_output) + + error_message = (f'The start {start} or the end {end} version provided is ' + f'different than "start" {bisect_state["start"]} or "end" ' + f'{bisect_state["end"]} in the .JSON file') + + self.assertEqual(str(err.exception), error_message) + + mock_outside_chroot.assert_called_once() + + mock_load_status_file.assert_called_once() + + @mock.patch.object(llvm_bisection, 'GetCommitsBetween') + @mock.patch.object(llvm_bisection, 'GetRemainingRange') @mock.patch.object(llvm_bisection, 'LoadStatusFile') - # Simulate behavior of `VerifyOutsideChroot()` when successfully invoked the - # script outside of the chroot. @mock.patch.object(chroot, 'VerifyOutsideChroot', return_value=True) - def testSuccessfullyBisectedLLVM( - self, mock_outside_chroot, mock_load_status_file, - mock_validate_start_and_end, mock_get_start_and_end_revision, - mock_get_revision_and_hash_list, mock_note_completed_bisection): + def testMainFailedWithPendingBuilds(self, mock_outside_chroot, + mock_load_status_file, mock_get_range, + mock_get_revision_and_hash_list): start = 500 end = 502 + rev = 501 - bisect_contents = { + bisect_state = { 'start': start, 'end': end, 'jobs': [{ - 'rev': 501, - 'status': 'skip' + 'rev': rev, + 'status': 'pending' }] } - skip_revisions = {501} - pending_revisions = {} + skip_revisions = {} + pending_revisions = {rev} + + mock_load_status_file.return_value = bisect_state + + mock_get_range.return_value = (start, end, pending_revisions, + skip_revisions) - # Simulate behavior of `LoadStatusFile()` when successfully loaded the - # status file. - mock_load_status_file.return_value = bisect_contents - - # Simulate behavior of `GetStartAndEndRevision()` when successfully found - # the new start and end revision of the bisection. - # - # Returns new start revision, new end revision, a set of pending revisions, - # and a set of skip revisions. - mock_get_start_and_end_revision.return_value = (start, end, - pending_revisions, - skip_revisions) - - # Simulate behavior of `GetRevisionsListAndHashList()` when successfully - # retrieved valid revisions (along with their git hashes) between start and - # end (in this case, none). mock_get_revision_and_hash_list.return_value = [], [] args_output = test_helpers.ArgsOutputTest() @@ -491,111 +361,75 @@ class LLVMBisectionTest(unittest.TestCase): args_output.parallel = 3 args_output.src_path = None - self.assertEqual( - llvm_bisection.main(args_output), - llvm_bisection.BisectionExitStatus.BISECTION_COMPLETE.value) + with self.assertRaises(ValueError) as err: + llvm_bisection.main(args_output) + + error_message = (f'No revisions between start {start} and end {end} to ' + 'create tryjobs\nThe following tryjobs are pending:\n' + f'{rev}\n') + + self.assertEqual(str(err.exception), error_message) mock_outside_chroot.assert_called_once() mock_load_status_file.assert_called_once() - mock_validate_start_and_end.assert_called_once() - - mock_get_start_and_end_revision.assert_called_once() + mock_get_range.assert_called_once() mock_get_revision_and_hash_list.assert_called_once() - mock_note_completed_bisection.assert_called_once() - - @mock.patch.object(llvm_bisection, 'DieWithNoRevisionsError') - # Simulate behavior of `_NoteCompletedBisection()` when there are no more - # tryjobs to launch between start and end, so bisection is complete. - @mock.patch.object(llvm_bisection, 'GetRevisionsListAndHashList') - @mock.patch.object(llvm_bisection, 'GetStartAndEndRevision') - # Simulate behavior of `_ValidateStartAndEndAgainstJSONStartAndEnd()` when - # both start and end revisions match. - @mock.patch.object(llvm_bisection, - '_ValidateStartAndEndAgainstJSONStartAndEnd') + @mock.patch.object(llvm_bisection, 'GetCommitsBetween') + @mock.patch.object(llvm_bisection, 'GetRemainingRange') @mock.patch.object(llvm_bisection, 'LoadStatusFile') - # Simulate behavior of `VerifyOutsideChroot()` when successfully invoked the - # script outside of the chroot. @mock.patch.object(chroot, 'VerifyOutsideChroot', return_value=True) - def testNoMoreTryjobsToLaunch( - self, mock_outside_chroot, mock_load_status_file, - mock_validate_start_and_end, mock_get_start_and_end_revision, - mock_get_revision_and_hash_list, mock_die_with_no_revisions_error): + def testMainFailedWithDuplicateBuilds(self, mock_outside_chroot, + mock_load_status_file, mock_get_range, + mock_get_revision_and_hash_list): start = 500 end = 502 + rev = 501 + git_hash = 'a123testhash1' - bisect_contents = { + bisect_state = { 'start': start, 'end': end, 'jobs': [{ - 'rev': 501, + 'rev': rev, 'status': 'pending' }] } skip_revisions = {} - pending_revisions = {501} - - no_revisions_error_message = ('No more tryjobs to launch between %d and ' - '%d' % (start, end)) - - def MockNoRevisionsErrorException(_start, _end, _skip, _pending): - raise ValueError(no_revisions_error_message) - - # Simulate behavior of `LoadStatusFile()` when successfully loaded the - # status file. - mock_load_status_file.return_value = bisect_contents - - # Simulate behavior of `GetStartAndEndRevision()` when successfully found - # the new start and end revision of the bisection. - # - # Returns new start revision, new end revision, a set of pending revisions, - # and a set of skip revisions. - mock_get_start_and_end_revision.return_value = (start, end, - pending_revisions, - skip_revisions) - - # Simulate behavior of `GetRevisionsListAndHashList()` when successfully - # retrieved valid revisions (along with their git hashes) between start and - # end (in this case, none). - mock_get_revision_and_hash_list.return_value = [], [] + pending_revisions = {rev} + + mock_load_status_file.return_value = bisect_state - # Use the test function to simulate `DieWithNoRevisionsWithError()` - # behavior. - mock_die_with_no_revisions_error.side_effect = MockNoRevisionsErrorException + mock_get_range.return_value = (start, end, pending_revisions, + skip_revisions) + + mock_get_revision_and_hash_list.return_value = [rev], [git_hash] - # Simulate behavior of arguments passed into the command line. args_output = test_helpers.ArgsOutputTest() args_output.start_rev = start args_output.end_rev = end args_output.parallel = 3 args_output.src_path = None - # Verify the exception is raised when there are no more tryjobs to launch - # between start and end when there are tryjobs that are 'pending', so - # the actual bad revision can change when those tryjobs's 'status' are - # updated. with self.assertRaises(ValueError) as err: llvm_bisection.main(args_output) - self.assertEqual(str(err.exception), no_revisions_error_message) + error_message = ('Revision %d exists already in "jobs"' % rev) + self.assertEqual(str(err.exception), error_message) mock_outside_chroot.assert_called_once() mock_load_status_file.assert_called_once() - mock_validate_start_and_end.assert_called_once() - - mock_get_start_and_end_revision.assert_called_once() + mock_get_range.assert_called_once() mock_get_revision_and_hash_list.assert_called_once() - mock_die_with_no_revisions_error.assert_called_once() - if __name__ == '__main__': unittest.main() |