blob: 6bf7924e75e3705173f02c59848aa5102a49147d [file] [log] [blame]
# Copyright (c) 2010 Google Inc. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from datetime import datetime
import logging
import unittest
from webkitpy.common.net import bugzilla
from webkitpy.common.net.layouttestresults import LayoutTestResults
from webkitpy.common.system.executive import ScriptError
from webkitpy.common.system.outputcapture import OutputCapture
from webkitpy.layout_tests.models import test_results
from webkitpy.layout_tests.models import test_failures
from webkitpy.thirdparty.mock import Mock
from webkitpy.tool.bot.commitqueuetask import *
from webkitpy.tool.mocktool import MockTool
_log = logging.getLogger(__name__)
class MockCommitQueue(CommitQueueTaskDelegate):
def __init__(self, error_plan):
self._error_plan = error_plan
self._failure_status_id = 0
self._flaky_tests = []
def run_command(self, command):
_log.info("run_webkit_patch: %s" % command)
if self._error_plan:
error = self._error_plan.pop(0)
if error:
raise error
def command_passed(self, success_message, patch):
_log.info("command_passed: success_message='%s' patch='%s'" % (
success_message, patch.id()))
def command_failed(self, failure_message, script_error, patch):
_log.info("command_failed: failure_message='%s' script_error='%s' patch='%s'" % (
failure_message, script_error, patch.id()))
self._failure_status_id += 1
return self._failure_status_id
def refetch_patch(self, patch):
return patch
def test_results(self):
return LayoutTestResults(test_results=[], did_exceed_test_failure_limit=False)
def report_flaky_tests(self, patch, flaky_results, results_archive):
current_flaky_tests = [result.test_name for result in flaky_results]
self._flaky_tests += current_flaky_tests
_log.info("report_flaky_tests: patch='%s' flaky_tests='%s' archive='%s'" % (patch.id(), current_flaky_tests, results_archive.filename))
def get_reported_flaky_tests(self):
return self._flaky_tests
def archive_last_test_results(self, patch):
_log.info("archive_last_test_results: patch='%s'" % patch.id())
archive = Mock()
archive.filename = "mock-archive-%s.zip" % patch.id()
return archive
def build_style(self):
return "release"
def did_pass_testing_ews(self, patch):
return False
class FailingTestCommitQueue(MockCommitQueue):
def __init__(self, error_plan, test_failure_plan):
MockCommitQueue.__init__(self, error_plan)
self._test_run_counter = -1 # Special value to indicate tests have never been run.
self._test_failure_plan = test_failure_plan
def run_command(self, command):
if command[0] == "build-and-test":
self._test_run_counter += 1
MockCommitQueue.run_command(self, command)
def _mock_test_result(self, testname):
return test_results.TestResult(testname, [test_failures.FailureTextMismatch()])
def test_results(self):
# Doesn't make sense to ask for the test_results until the tests have run at least once.
assert(self._test_run_counter >= 0)
failures_for_run = self._test_failure_plan[self._test_run_counter]
assert(isinstance(failures_for_run, list))
results = LayoutTestResults(test_results=map(self._mock_test_result, failures_for_run), did_exceed_test_failure_limit=(len(failures_for_run) >= 10))
return results
class PatchAnalysisResult(object):
FAIL = "Fail"
DEFER = "Defer"
PASS = "Pass"
class MockSimpleTestPlanCommitQueue(MockCommitQueue):
def __init__(self, first_test_failures, second_test_failures, clean_test_failures):
MockCommitQueue.__init__(self, [])
self._did_run_clean_tests = False
self._patch_test_results = [first_test_failures, second_test_failures]
self._clean_test_results = [clean_test_failures]
self._current_test_results = []
def run_command(self, command):
MockCommitQueue.run_command(self, command)
if command[0] == "build-and-test":
if "--no-clean" in command:
self._current_test_results = self._patch_test_results.pop(0)
else:
self._current_test_results = self._clean_test_results.pop(0)
self._did_run_clean_tests = True
if self._current_test_results:
raise ScriptError("MOCK test failure")
def _mock_test_result(self, testname):
return test_results.TestResult(testname, [test_failures.FailureTextMismatch()])
def test_results(self):
assert(isinstance(self._current_test_results, list))
return LayoutTestResults(test_results=map(self._mock_test_result, self._current_test_results), did_exceed_test_failure_limit=(len(self._current_test_results) >= 10))
def did_run_clean_tests(self):
return self._did_run_clean_tests
# We use GoldenScriptError to make sure that the code under test throws the
# correct (i.e., golden) exception.
class GoldenScriptError(ScriptError):
pass
_lots_of_failing_tests = map(lambda num: "test-%s.html" % num, range(0, 100))
class CommitQueueTaskTest(unittest.TestCase):
def _run_and_expect_patch_analysis_result(self, commit_queue, expected_analysis_result, expected_reported_flaky_tests=[], expect_clean_tests_to_run=False, expected_failure_status_id=0):
tool = MockTool(log_executive=True)
patch = tool.bugs.fetch_attachment(10000)
task = CommitQueueTask(commit_queue, patch)
try:
result = task.run()
if result:
analysis_result = PatchAnalysisResult.PASS
else:
analysis_result = PatchAnalysisResult.DEFER
except ScriptError:
analysis_result = PatchAnalysisResult.FAIL
self.assertEqual(analysis_result, expected_analysis_result)
self.assertEqual(frozenset(commit_queue.get_reported_flaky_tests()), frozenset(expected_reported_flaky_tests))
self.assertEqual(commit_queue.did_run_clean_tests(), expect_clean_tests_to_run)
# The failure status only means anything if we actually failed.
if expected_analysis_result == PatchAnalysisResult.FAIL:
self.assertEqual(task.failure_status_id, expected_failure_status_id)
self.assertIsInstance(task.results_from_patch_test_run(patch), LayoutTestResults)
def _run_through_task(self, commit_queue, expected_logs, expected_exception=None, expect_retry=False):
self.maxDiff = None
tool = MockTool(log_executive=True)
patch = tool.bugs.fetch_attachment(10000)
task = CommitQueueTask(commit_queue, patch)
success = OutputCapture().assert_outputs(self, task.run, expected_logs=expected_logs, expected_exception=expected_exception)
if not expected_exception:
self.assertEqual(success, not expect_retry)
return task
def test_success_case(self):
commit_queue = MockCommitQueue([])
expected_logs = """run_webkit_patch: ['clean']
command_passed: success_message='Cleaned working directory' patch='10000'
run_webkit_patch: ['update']
command_passed: success_message='Updated working directory' patch='10000'
run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 10000]
command_passed: success_message='Applied patch' patch='10000'
run_webkit_patch: ['validate-changelog', '--check-oops', '--non-interactive', 10000]
command_passed: success_message='ChangeLog validated' patch='10000'
run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=release']
command_passed: success_message='Built patch' patch='10000'
run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive', '--build-style=release']
command_passed: success_message='Passed tests' patch='10000'
run_webkit_patch: ['land-attachment', '--force-clean', '--non-interactive', '--parent-command=commit-queue', 10000]
command_passed: success_message='Landed patch' patch='10000'
"""
self._run_through_task(commit_queue, expected_logs)
def test_fast_success_case(self):
commit_queue = MockCommitQueue([])
commit_queue.did_pass_testing_ews = lambda patch: True
expected_logs = """run_webkit_patch: ['clean']
command_passed: success_message='Cleaned working directory' patch='10000'
run_webkit_patch: ['update']
command_passed: success_message='Updated working directory' patch='10000'
run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 10000]
command_passed: success_message='Applied patch' patch='10000'
run_webkit_patch: ['validate-changelog', '--check-oops', '--non-interactive', 10000]
command_passed: success_message='ChangeLog validated' patch='10000'
run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=release']
command_passed: success_message='Built patch' patch='10000'
run_webkit_patch: ['land-attachment', '--force-clean', '--non-interactive', '--parent-command=commit-queue', 10000]
command_passed: success_message='Landed patch' patch='10000'
"""
self._run_through_task(commit_queue, expected_logs)
def test_clean_failure(self):
commit_queue = MockCommitQueue([
ScriptError("MOCK clean failure"),
])
expected_logs = """run_webkit_patch: ['clean']
command_failed: failure_message='Unable to clean working directory' script_error='MOCK clean failure' patch='10000'
"""
self._run_through_task(commit_queue, expected_logs, expect_retry=True)
def test_update_failure(self):
commit_queue = MockCommitQueue([
None,
ScriptError("MOCK update failure"),
])
expected_logs = """run_webkit_patch: ['clean']
command_passed: success_message='Cleaned working directory' patch='10000'
run_webkit_patch: ['update']
command_failed: failure_message='Unable to update working directory' script_error='MOCK update failure' patch='10000'
"""
self._run_through_task(commit_queue, expected_logs, expect_retry=True)
def test_apply_failure(self):
commit_queue = MockCommitQueue([
None,
None,
GoldenScriptError("MOCK apply failure"),
])
expected_logs = """run_webkit_patch: ['clean']
command_passed: success_message='Cleaned working directory' patch='10000'
run_webkit_patch: ['update']
command_passed: success_message='Updated working directory' patch='10000'
run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 10000]
command_failed: failure_message='Patch does not apply' script_error='MOCK apply failure' patch='10000'
"""
self._run_through_task(commit_queue, expected_logs, GoldenScriptError)
def test_validate_changelog_failure(self):
commit_queue = MockCommitQueue([
None,
None,
None,
GoldenScriptError("MOCK validate failure"),
])
expected_logs = """run_webkit_patch: ['clean']
command_passed: success_message='Cleaned working directory' patch='10000'
run_webkit_patch: ['update']
command_passed: success_message='Updated working directory' patch='10000'
run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 10000]
command_passed: success_message='Applied patch' patch='10000'
run_webkit_patch: ['validate-changelog', '--check-oops', '--non-interactive', 10000]
command_failed: failure_message='ChangeLog did not pass validation' script_error='MOCK validate failure' patch='10000'
"""
self._run_through_task(commit_queue, expected_logs, GoldenScriptError)
def test_build_failure(self):
commit_queue = MockCommitQueue([
None,
None,
None,
None,
GoldenScriptError("MOCK build failure"),
])
expected_logs = """run_webkit_patch: ['clean']
command_passed: success_message='Cleaned working directory' patch='10000'
run_webkit_patch: ['update']
command_passed: success_message='Updated working directory' patch='10000'
run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 10000]
command_passed: success_message='Applied patch' patch='10000'
run_webkit_patch: ['validate-changelog', '--check-oops', '--non-interactive', 10000]
command_passed: success_message='ChangeLog validated' patch='10000'
run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=release']
command_failed: failure_message='Patch does not build' script_error='MOCK build failure' patch='10000'
run_webkit_patch: ['build', '--force-clean', '--no-update', '--build-style=release']
command_passed: success_message='Able to build without patch' patch='10000'
"""
self._run_through_task(commit_queue, expected_logs, GoldenScriptError)
def test_red_build_failure(self):
commit_queue = MockCommitQueue([
None,
None,
None,
None,
ScriptError("MOCK build failure"),
ScriptError("MOCK clean build failure"),
])
expected_logs = """run_webkit_patch: ['clean']
command_passed: success_message='Cleaned working directory' patch='10000'
run_webkit_patch: ['update']
command_passed: success_message='Updated working directory' patch='10000'
run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 10000]
command_passed: success_message='Applied patch' patch='10000'
run_webkit_patch: ['validate-changelog', '--check-oops', '--non-interactive', 10000]
command_passed: success_message='ChangeLog validated' patch='10000'
run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=release']
command_failed: failure_message='Patch does not build' script_error='MOCK build failure' patch='10000'
run_webkit_patch: ['build', '--force-clean', '--no-update', '--build-style=release']
command_failed: failure_message='Unable to build without patch' script_error='MOCK clean build failure' patch='10000'
"""
self._run_through_task(commit_queue, expected_logs, expect_retry=True)
def test_land_failure(self):
commit_queue = MockCommitQueue([
None,
None,
None,
None,
None,
None,
GoldenScriptError("MOCK land failure"),
])
expected_logs = """run_webkit_patch: ['clean']
command_passed: success_message='Cleaned working directory' patch='10000'
run_webkit_patch: ['update']
command_passed: success_message='Updated working directory' patch='10000'
run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 10000]
command_passed: success_message='Applied patch' patch='10000'
run_webkit_patch: ['validate-changelog', '--check-oops', '--non-interactive', 10000]
command_passed: success_message='ChangeLog validated' patch='10000'
run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=release']
command_passed: success_message='Built patch' patch='10000'
run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive', '--build-style=release']
command_passed: success_message='Passed tests' patch='10000'
run_webkit_patch: ['land-attachment', '--force-clean', '--non-interactive', '--parent-command=commit-queue', 10000]
command_failed: failure_message='Unable to land patch' script_error='MOCK land failure' patch='10000'
"""
# FIXME: This should really be expect_retry=True for a better user experiance.
self._run_through_task(commit_queue, expected_logs, GoldenScriptError)
def test_failed_archive(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["Fail1"],
second_test_failures=[],
clean_test_failures=[])
# It's possible for the delegate to fail to archive layout tests,
# but we shouldn't try to report flaky tests when that happens.
commit_queue.archive_last_test_results = lambda patch: None
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.PASS)
def test_double_flaky_test_failure(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["Fail1"],
second_test_failures=["Fail2"],
clean_test_failures=["Fail1"])
# The (subtle) point of this test is that report_flaky_tests does not get
# called for this run.
# Note also that there is no attempt to run the tests w/o the patch.
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.DEFER, expected_reported_flaky_tests=["Fail1", "Fail2"])
def test_test_failure(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["Fail1"],
second_test_failures=["Fail1"],
clean_test_failures=[])
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.FAIL, expect_clean_tests_to_run=True, expected_failure_status_id=1)
def test_red_test_failure(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["Fail1"],
second_test_failures=["Fail1"],
clean_test_failures=["Fail1"])
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.PASS, expect_clean_tests_to_run=True)
def test_first_failure_limit(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=_lots_of_failing_tests,
second_test_failures=[],
clean_test_failures=[])
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.DEFER, expect_clean_tests_to_run=True, expected_failure_status_id=1)
def test_first_failure_limit_with_some_tree_redness(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=_lots_of_failing_tests,
second_test_failures=["Fail1", "Fail2", "Fail3"],
clean_test_failures=["Fail1", "Fail2", "Fail3"])
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.DEFER, expect_clean_tests_to_run=True, expected_failure_status_id=1)
def test_second_failure_limit(self):
# There need to be some failures in the first set of tests, or it won't even make it to the second test.
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["Fail1", "Fail2", "Fail3"],
second_test_failures=_lots_of_failing_tests,
clean_test_failures=["Fail1", "Fail2", "Fail3"])
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.DEFER, expect_clean_tests_to_run=True, expected_failure_status_id=2)
def test_tree_failure_limit_with_patch_that_potentially_fixes_some_redness(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["Fail1", "Fail2", "Fail3"],
second_test_failures=["Fail1", "Fail2", "Fail3"],
clean_test_failures=_lots_of_failing_tests)
# Unfortunately there are cases where the clean build will randomly fail enough tests to hit the failure limit.
# With that in mind, we can't actually know that this patch is good or bad until we see a clean run that doesn't
# exceed the failure limit.
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.DEFER, expect_clean_tests_to_run=True)
def test_first_and_second_failure_limit(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=_lots_of_failing_tests,
second_test_failures=_lots_of_failing_tests,
clean_test_failures=[])
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.FAIL, expect_clean_tests_to_run=True, expected_failure_status_id=1)
def test_first_and_clean_failure_limit(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=_lots_of_failing_tests,
second_test_failures=[],
clean_test_failures=_lots_of_failing_tests)
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.DEFER, expect_clean_tests_to_run=True)
def test_first_second_and_clean_failure_limit(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=_lots_of_failing_tests,
second_test_failures=_lots_of_failing_tests,
clean_test_failures=_lots_of_failing_tests)
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.DEFER, expect_clean_tests_to_run=True)
def test_red_tree_patch_rejection(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["Fail1", "Fail2"],
second_test_failures=["Fail1", "Fail2"],
clean_test_failures=["Fail1"])
# failure_status_id should be of the test with patch (1), not the test without patch (2).
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.FAIL, expect_clean_tests_to_run=True, expected_failure_status_id=1)
def test_two_flaky_tests(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["Fail1"],
second_test_failures=["Fail2"],
clean_test_failures=["Fail1", "Fail2"])
# FIXME: This should pass, but as of right now, it defers.
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.DEFER, expected_reported_flaky_tests=["Fail1", "Fail2"])
def test_one_flaky_test(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["Fail1"],
second_test_failures=[],
clean_test_failures=[])
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.PASS, expected_reported_flaky_tests=["Fail1"])
def test_very_flaky_patch(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["Fail1", "Fail2", "Fail3", "Fail4", "Fail5"],
second_test_failures=["Fail6", "Fail7", "Fail8", "Fail9", "Fail10"],
clean_test_failures=[])
# FIXME: This should actually fail, but right now it defers
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.DEFER, expected_reported_flaky_tests=["Fail1", "Fail2", "Fail3", "Fail4", "Fail5", "Fail6", "Fail7", "Fail8", "Fail9", "Fail10"])
def test_very_flaky_patch_with_some_tree_redness(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["PreExistingFail1", "PreExistingFail2", "Fail1", "Fail2", "Fail3", "Fail4", "Fail5"],
second_test_failures=["PreExistingFail1", "PreExistingFail2", "Fail6", "Fail7", "Fail8", "Fail9", "Fail10"],
clean_test_failures=["PreExistingFail1", "PreExistingFail2"])
# FIXME: This should actually fail, but right now it defers
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.DEFER, expect_clean_tests_to_run=True, expected_reported_flaky_tests=["Fail1", "Fail2", "Fail3", "Fail4", "Fail5", "Fail6", "Fail7", "Fail8", "Fail9", "Fail10"])
def test_different_test_failures(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["Fail1", "Fail2", "Fail3", "Fail4", "Fail5", "Fail6"],
second_test_failures=["Fail1", "Fail2", "Fail3", "Fail4", "Fail5"],
clean_test_failures=[])
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.FAIL, expect_clean_tests_to_run=True, expected_reported_flaky_tests=["Fail6"], expected_failure_status_id=1)
def test_different_test_failures_with_some_tree_redness(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["PreExistingFail1", "PreExistingFail2", "Fail1", "Fail2", "Fail3", "Fail4", "Fail5", "Fail6"],
second_test_failures=["PreExistingFail1", "PreExistingFail2", "Fail1", "Fail2", "Fail3", "Fail4", "Fail5"],
clean_test_failures=["PreExistingFail1", "PreExistingFail2"])
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.FAIL, expect_clean_tests_to_run=True, expected_reported_flaky_tests=["Fail6"], expected_failure_status_id=1)
def test_different_test_failures_with_some_tree_redness_and_some_fixes(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["PreExistingFail1", "Fail1", "Fail2", "Fail3", "Fail4", "Fail5", "Fail6"],
second_test_failures=["PreExistingFail1", "Fail1", "Fail2", "Fail3", "Fail4", "Fail5"],
clean_test_failures=["PreExistingFail1", "PreExistingFail2"])
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.FAIL, expect_clean_tests_to_run=True, expected_reported_flaky_tests=["Fail6"], expected_failure_status_id=1)
def test_mildly_flaky_patch(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["Fail1"],
second_test_failures=["Fail2"],
clean_test_failures=[])
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.DEFER, expect_clean_tests_to_run=False, expected_reported_flaky_tests=["Fail1", "Fail2"])
def test_mildly_flaky_patch_with_some_tree_redness(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["PreExistingFail1", "PreExistingFail2", "Fail1"],
second_test_failures=["PreExistingFail1", "PreExistingFail2", "Fail2"],
clean_test_failures=["PreExistingFail1", "PreExistingFail2"])
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.DEFER, expect_clean_tests_to_run=True, expected_reported_flaky_tests=["Fail1", "Fail2"])
def test_tree_more_red_than_patch(self):
commit_queue = MockSimpleTestPlanCommitQueue(
first_test_failures=["Fail1", "Fail2", "Fail3"],
second_test_failures=["Fail1", "Fail2", "Fail3"],
clean_test_failures=["Fail1", "Fail2", "Fail3", "Fail4"])
self._run_and_expect_patch_analysis_result(commit_queue, PatchAnalysisResult.PASS, expect_clean_tests_to_run=True)
def _expect_validate(self, patch, is_valid):
class MockDelegate(object):
def refetch_patch(self, patch):
return patch
task = CommitQueueTask(MockDelegate(), patch)
self.assertEqual(task.validate(), is_valid)
def _mock_patch(self, attachment_dict={}, bug_dict={'bug_status': 'NEW'}, committer="fake"):
bug = bugzilla.Bug(bug_dict, None)
patch = bugzilla.Attachment(attachment_dict, bug)
patch._committer = committer
return patch
def test_validate(self):
self._expect_validate(self._mock_patch(), True)
self._expect_validate(self._mock_patch({'is_obsolete': True}), False)
self._expect_validate(self._mock_patch(bug_dict={'bug_status': 'CLOSED'}), False)
self._expect_validate(self._mock_patch(committer=None), False)
self._expect_validate(self._mock_patch({'review': '-'}), False)