def find_regression_range(testcase_id, job_type):
    'Attempt to find when the testcase regressed.'
    deadline = tasks.get_task_completion_deadline()
    testcase = data_handler.get_testcase_by_id(testcase_id)
    if (not testcase):
        return
    if testcase.regression:
        logs.log_error(('Regression range is already set as %s, skip.' % testcase.regression))
        return
    if build_manager.is_custom_binary():
        testcase.regression = 'NA'
        data_handler.update_testcase_comment(testcase, data_types.TaskState.ERROR, 'Not applicable for custom binaries')
        return
    data_handler.update_testcase_comment(testcase, data_types.TaskState.STARTED)
    (file_list, _, testcase_file_path) = setup.setup_testcase(testcase, job_type)
    if (not file_list):
        testcase = data_handler.get_testcase_by_id(testcase_id)
        data_handler.update_testcase_comment(testcase, data_types.TaskState.ERROR, 'Failed to setup testcase')
        tasks.add_task('regression', testcase_id, job_type)
        return
    build_bucket_path = build_manager.get_primary_bucket_path()
    revision_list = build_manager.get_revisions_list(build_bucket_path, testcase=testcase)
    if (not revision_list):
        testcase = data_handler.get_testcase_by_id(testcase_id)
        data_handler.update_testcase_comment(testcase, data_types.TaskState.ERROR, 'Failed to fetch revision list')
        tasks.add_task('regression', testcase_id, job_type)
        return
    environment.set_value('CACHE_STORE', False)
    min_revision = testcase.get_metadata('last_regression_min')
    max_revision = testcase.get_metadata('last_regression_max')
    first_run = ((not min_revision) and (not max_revision))
    if (not min_revision):
        min_revision = revisions.get_first_revision_in_list(revision_list)
    if (not max_revision):
        max_revision = testcase.crash_revision
    min_index = revisions.find_min_revision_index(revision_list, min_revision)
    if (min_index is None):
        raise errors.BuildNotFoundError(min_revision, job_type)
    max_index = revisions.find_max_revision_index(revision_list, max_revision)
    if (max_index is None):
        raise errors.BuildNotFoundError(max_revision, job_type)
    max_revision = revision_list[max_index]
    crashes_in_max_revision = _testcase_reproduces_in_revision(testcase, testcase_file_path, job_type, max_revision, should_log=False)
    if (not crashes_in_max_revision):
        testcase = data_handler.get_testcase_by_id(testcase_id)
        error_message = ('Known crash revision %d did not crash' % max_revision)
        data_handler.update_testcase_comment(testcase, data_types.TaskState.ERROR, error_message)
        task_creation.mark_unreproducible_if_flaky(testcase, True)
        return
    task_creation.mark_unreproducible_if_flaky(testcase, False)
    if (first_run and found_regression_near_extreme_revisions(testcase, testcase_file_path, job_type, revision_list, min_index, max_index)):
        return
    while (time.time() < deadline):
        min_revision = revision_list[min_index]
        max_revision = revision_list[max_index]
        if ((max_index - min_index) <= 1):
            if (not validate_regression_range(testcase, testcase_file_path, job_type, revision_list, min_index)):
                return
            save_regression_range(testcase_id, min_revision, max_revision)
            return
        middle_index = ((min_index + max_index) // 2)
        middle_revision = revision_list[middle_index]
        try:
            is_crash = _testcase_reproduces_in_revision(testcase, testcase_file_path, job_type, middle_revision, min_revision=min_revision, max_revision=max_revision)
        except errors.BadBuildError:
            del revision_list[middle_index]
            max_index -= 1
            continue
        if is_crash:
            max_index = middle_index
        else:
            min_index = middle_index
        _save_current_regression_range_indices(testcase_id, revision_list[min_index], revision_list[max_index])
    testcase = data_handler.get_testcase_by_id(testcase_id)
    error_message = ('Timed out, current range r%d:r%d' % (revision_list[min_index], revision_list[max_index]))
    data_handler.update_testcase_comment(testcase, data_types.TaskState.ERROR, error_message)
    tasks.add_task('regression', testcase_id, job_type)
Attempt to find when the testcase regressed.
def find_regression_range(testcase_id, job_type):
    
    deadline = tasks.get_task_completion_deadline()
    testcase = data_handler.get_testcase_by_id(testcase_id)
    if (not testcase):
        return
    if testcase.regression:
        logs.log_error(('Regression range is already set as %s, skip.' % testcase.regression))
        return
    if build_manager.is_custom_binary():
        testcase.regression = 'NA'
        data_handler.update_testcase_comment(testcase, data_types.TaskState.ERROR, 'Not applicable for custom binaries')
        return
    data_handler.update_testcase_comment(testcase, data_types.TaskState.STARTED)
    (file_list, _, testcase_file_path) = setup.setup_testcase(testcase, job_type)
    if (not file_list):
        testcase = data_handler.get_testcase_by_id(testcase_id)
        data_handler.update_testcase_comment(testcase, data_types.TaskState.ERROR, 'Failed to setup testcase')
        tasks.add_task('regression', testcase_id, job_type)
        return
    build_bucket_path = build_manager.get_primary_bucket_path()
    revision_list = build_manager.get_revisions_list(build_bucket_path, testcase=testcase)
    if (not revision_list):
        testcase = data_handler.get_testcase_by_id(testcase_id)
        data_handler.update_testcase_comment(testcase, data_types.TaskState.ERROR, 'Failed to fetch revision list')
        tasks.add_task('regression', testcase_id, job_type)
        return
    environment.set_value('CACHE_STORE', False)
    min_revision = testcase.get_metadata('last_regression_min')
    max_revision = testcase.get_metadata('last_regression_max')
    first_run = ((not min_revision) and (not max_revision))
    if (not min_revision):
        min_revision = revisions.get_first_revision_in_list(revision_list)
    if (not max_revision):
        max_revision = testcase.crash_revision
    min_index = revisions.find_min_revision_index(revision_list, min_revision)
    if (min_index is None):
        raise errors.BuildNotFoundError(min_revision, job_type)
    max_index = revisions.find_max_revision_index(revision_list, max_revision)
    if (max_index is None):
        raise errors.BuildNotFoundError(max_revision, job_type)
    max_revision = revision_list[max_index]
    crashes_in_max_revision = _testcase_reproduces_in_revision(testcase, testcase_file_path, job_type, max_revision, should_log=False)
    if (not crashes_in_max_revision):
        testcase = data_handler.get_testcase_by_id(testcase_id)
        error_message = ('Known crash revision %d did not crash' % max_revision)
        data_handler.update_testcase_comment(testcase, data_types.TaskState.ERROR, error_message)
        task_creation.mark_unreproducible_if_flaky(testcase, True)
        return
    task_creation.mark_unreproducible_if_flaky(testcase, False)
    if (first_run and found_regression_near_extreme_revisions(testcase, testcase_file_path, job_type, revision_list, min_index, max_index)):
        return
    while (time.time() < deadline):
        min_revision = revision_list[min_index]
        max_revision = revision_list[max_index]
        if ((max_index - min_index) <= 1):
            if (not validate_regression_range(testcase, testcase_file_path, job_type, revision_list, min_index)):
                return
            save_regression_range(testcase_id, min_revision, max_revision)
            return
        middle_index = ((min_index + max_index) // 2)
        middle_revision = revision_list[middle_index]
        try:
            is_crash = _testcase_reproduces_in_revision(testcase, testcase_file_path, job_type, middle_revision, min_revision=min_revision, max_revision=max_revision)
        except errors.BadBuildError:
            del revision_list[middle_index]
            max_index -= 1
            continue
        if is_crash:
            max_index = middle_index
        else:
            min_index = middle_index
        _save_current_regression_range_indices(testcase_id, revision_list[min_index], revision_list[max_index])
    testcase = data_handler.get_testcase_by_id(testcase_id)
    error_message = ('Timed out, current range r%d:r%d' % (revision_list[min_index], revision_list[max_index]))
    data_handler.update_testcase_comment(testcase, data_types.TaskState.ERROR, error_message)
    tasks.add_task('regression', testcase_id, job_type)