Changeset 84658 in webkit


Ignore:
Timestamp:
Apr 22, 2011 12:25:34 PM (13 years ago)
Author:
abarth@webkit.org
Message:

2011-04-22 Adam Barth <abarth@webkit.org>

Reviewed by Eric Seidel.

Factor PatchAnalysis task out of CommitQueueTask
https://bugs.webkit.org/show_bug.cgi?id=59220

This is a first step towards teaching the EWS to run tests.

  • Scripts/webkitpy/tool/bot/commitqueuetask.py:
  • Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py:
  • Scripts/webkitpy/tool/bot/patchanalysistask.py: Added.
Location:
trunk/Tools
Files:
1 added
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Tools/ChangeLog

    r84637 r84658  
     12011-04-22  Adam Barth  <abarth@webkit.org>
     2
     3        Reviewed by Eric Seidel.
     4
     5        Factor PatchAnalysis task out of CommitQueueTask
     6        https://bugs.webkit.org/show_bug.cgi?id=59220
     7
     8        This is a first step towards teaching the EWS to run tests.
     9
     10        * Scripts/webkitpy/tool/bot/commitqueuetask.py:
     11        * Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py:
     12        * Scripts/webkitpy/tool/bot/patchanalysistask.py: Added.
     13
    1142011-04-22  Philippe Normand  <pnormand@igalia.com>
    215
  • trunk/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py

    r83797 r84658  
    2727# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2828
    29 from webkitpy.common.system.executive import ScriptError
    30 from webkitpy.common.net.layouttestresults import LayoutTestResults
    31 from webkitpy.tool.bot.expectedfailures import ExpectedFailures
     29from webkitpy.tool.bot.patchanalysistask import PatchAnalysisTask, PatchAnalysisTaskDelegate
    3230
    3331
    34 class CommitQueueTaskDelegate(object):
    35     def run_command(self, command):
    36         raise NotImplementedError("subclasses must implement")
    37 
    38     def command_passed(self, message, patch):
    39         raise NotImplementedError("subclasses must implement")
    40 
    41     def command_failed(self, message, script_error, patch):
    42         raise NotImplementedError("subclasses must implement")
    43 
    44     def refetch_patch(self, patch):
    45         raise NotImplementedError("subclasses must implement")
    46 
    47     def layout_test_results(self):
    48         raise NotImplementedError("subclasses must implement")
    49 
    50     def archive_last_layout_test_results(self, patch):
    51         raise NotImplementedError("subclasses must implement")
    52 
    53     # We could make results_archive optional, but for now it's required.
    54     def report_flaky_tests(self, patch, flaky_tests, results_archive):
    55         raise NotImplementedError("subclasses must implement")
     32class CommitQueueTaskDelegate(PatchAnalysisTaskDelegate):
     33    def parent_command(self):
     34        return "commit-queue"
    5635
    5736
    58 class CommitQueueTask(object):
    59     def __init__(self, delegate, patch):
    60         self._delegate = delegate
    61         self._patch = patch
    62         self._script_error = None
    63         self._results_archive_from_patch_test_run = None
    64         self._expected_failures = ExpectedFailures()
    65 
    66     def _validate(self):
     37class CommitQueueTask(PatchAnalysisTask):
     38    def validate(self):
    6739        # Bugs might get closed, or patches might be obsoleted or r-'d while the
    6840        # commit-queue is processing.
     
    8052        return True
    8153
    82     def _run_command(self, command, success_message, failure_message):
    83         try:
    84             self._delegate.run_command(command)
    85             self._delegate.command_passed(success_message, patch=self._patch)
    86             return True
    87         except ScriptError, e:
    88             self._script_error = e
    89             self.failure_status_id = self._delegate.command_failed(failure_message, script_error=self._script_error, patch=self._patch)
    90             return False
    91 
    92     def _clean(self):
    93         return self._run_command([
    94             "clean",
    95         ],
    96         "Cleaned working directory",
    97         "Unable to clean working directory")
    98 
    99     def _update(self):
    100         # FIXME: Ideally the status server log message should include which revision we updated to.
    101         return self._run_command([
    102             "update",
    103         ],
    104         "Updated working directory",
    105         "Unable to update working directory")
    106 
    107     def _apply(self):
    108         return self._run_command([
    109             "apply-attachment",
    110             "--no-update",
    111             "--non-interactive",
    112             self._patch.id(),
    113         ],
    114         "Applied patch",
    115         "Patch does not apply")
    116 
    117     def _build(self):
    118         return self._run_command([
    119             "build",
    120             "--no-clean",
    121             "--no-update",
    122             "--build-style=both",
    123         ],
    124         "Built patch",
    125         "Patch does not build")
    126 
    127     def _build_without_patch(self):
    128         return self._run_command([
    129             "build",
    130             "--force-clean",
    131             "--no-update",
    132             "--build-style=both",
    133         ],
    134         "Able to build without patch",
    135         "Unable to build without patch")
    136 
    137     def _test(self):
    138         success = self._run_command([
    139             "build-and-test",
    140             "--no-clean",
    141             "--no-update",
    142             # Notice that we don't pass --build, which means we won't build!
    143             "--test",
    144             "--non-interactive",
    145         ],
    146         "Passed tests",
    147         "Patch does not pass tests")
    148 
    149         self._expected_failures.shrink_expected_failures(self._delegate.layout_test_results(), success)
    150         return success
    151 
    152     def _build_and_test_without_patch(self):
    153         success = self._run_command([
    154             "build-and-test",
    155             "--force-clean",
    156             "--no-update",
    157             "--build",
    158             "--test",
    159             "--non-interactive",
    160         ],
    161         "Able to pass tests without patch",
    162         "Unable to pass tests without patch (tree is red?)")
    163 
    164         self._expected_failures.shrink_expected_failures(self._delegate.layout_test_results(), success)
    165         return success
    166 
    167     def _land(self):
    168         # Unclear if this should pass --quiet or not.  If --parent-command always does the reporting, then it should.
    169         return self._run_command([
    170             "land-attachment",
    171             "--force-clean",
    172             "--ignore-builders",
    173             "--non-interactive",
    174             "--parent-command=commit-queue",
    175             self._patch.id(),
    176         ],
    177         "Landed patch",
    178         "Unable to land patch")
    179 
    180     def _report_flaky_tests(self, flaky_test_results, results_archive):
    181         self._delegate.report_flaky_tests(self._patch, flaky_test_results, results_archive)
    182 
    183     def _results_failed_different_tests(self, first, second):
    184         first_failing_tests = [] if not first else first.failing_tests()
    185         second_failing_tests = [] if not second else second.failing_tests()
    186         return first_failing_tests != second_failing_tests
    187 
    188     def _test_patch(self):
    189         if self._test():
    190             return True
    191 
    192         # Note: archive_last_layout_test_results deletes the results directory, making these calls order-sensitve.
    193         # We could remove this dependency by building the layout_test_results from the archive.
    194         first_results = self._delegate.layout_test_results()
    195         first_results_archive = self._delegate.archive_last_layout_test_results(self._patch)
    196 
    197         if self._expected_failures.failures_were_expected(first_results):
    198             return True
    199 
    200         if self._test():
    201             # Only report flaky tests if we were successful at parsing results.html and archiving results.
    202             if first_results and first_results_archive:
    203                 self._report_flaky_tests(first_results.failing_test_results(), first_results_archive)
    204             return True
    205 
    206         second_results = self._delegate.layout_test_results()
    207         if self._results_failed_different_tests(first_results, second_results):
    208             # We could report flaky tests here, but we would need to be careful
    209             # to use similar checks to ExpectedFailures._can_trust_results
    210             # to make sure we don't report constant failures as flakes when
    211             # we happen to hit the --exit-after-N-failures limit.
    212             # See https://bugs.webkit.org/show_bug.cgi?id=51272
    213             return False
    214 
    215         # Archive (and remove) second results so layout_test_results() after
    216         # build_and_test_without_patch won't use second results instead of the clean-tree results.
    217         second_results_archive = self._delegate.archive_last_layout_test_results(self._patch)
    218 
    219         if self._build_and_test_without_patch():
    220             # The error from the previous ._test() run is real, report it.
    221             return self.report_failure(first_results_archive)
    222 
    223         clean_tree_results = self._delegate.layout_test_results()
    224         self._expected_failures.grow_expected_failures(clean_tree_results)
    225 
    226         return False  # Tree must be redder than we expected, just retry later.
    227 
    228     def results_archive_from_patch_test_run(self, patch):
    229         assert(self._patch.id() == patch.id())  # CommitQueueTask is not currently re-useable.
    230         return self._results_archive_from_patch_test_run
    231 
    232     def report_failure(self, results_archive=None):
    233         if not self._validate():
    234             return False
    235         self._results_archive_from_patch_test_run = results_archive
    236         raise self._script_error
    237 
    23854    def run(self):
    239         if not self._validate():
     55        if not self.validate():
    24056            return False
    24157        if not self._clean():
     
    25470        # Make sure the patch is still valid before landing (e.g., make sure
    25571        # no one has set commit-queue- since we started working on the patch.)
    256         if not self._validate():
     72        if not self.validate():
    25773            return False
    25874        # FIXME: We should understand why the land failure occured and retry if possible.
  • trunk/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py

    r83795 r84658  
    3333from webkitpy.common.net.layouttestresults import LayoutTestResults
    3434from webkitpy.common.system.deprecated_logging import error, log
     35from webkitpy.common.system.executive import ScriptError
    3536from webkitpy.common.system.outputcapture import OutputCapture
    3637from webkitpy.layout_tests.layout_package import test_results
     
    377378
    378379        task = CommitQueueTask(MockDelegate(), patch)
    379         self.assertEquals(task._validate(), is_valid)
     380        self.assertEquals(task.validate(), is_valid)
    380381
    381382    def _mock_patch(self, attachment_dict={}, bug_dict={'bug_status': 'NEW'}, committer="fake"):
Note: See TracChangeset for help on using the changeset viewer.