1 # Copyright (C) 2011 Google Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
7 # 1. Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 # 2. Redistributions in binary form must reproduce the above copyright
10 # notice, this list of conditions and the following disclaimer in the
11 # documentation and/or other materials provided with the distribution.
13 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
14 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
15 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
16 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
17 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
19 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 from webkitpy.common.memoized import memoized
29 from webkitpy.tool.servers.reflectionhandler import ReflectionHandler
30 from webkitpy.layout_tests.models.test_expectations import BugManager, TestExpectationParser, TestExpectations, TestExpectationsEditor, TestExpectationSerializer
31 from webkitpy.layout_tests.models.test_configuration import TestConfigurationConverter
32 from webkitpy.layout_tests.port import factory
33 from webkitpy.layout_tests.port import builders
36 class BuildCoverageExtrapolator(object):
37 def __init__(self, test_configuration_converter):
38 self._test_configuration_converter = test_configuration_converter
41 def _covered_test_configurations_for_builder_name(self):
43 for builder_name in builders.all_builder_names():
44 coverage[builder_name] = self._test_configuration_converter.to_config_set(builders.coverage_specifiers_for_builder_name(builder_name))
47 def extrapolate_test_configurations(self, builder_name):
48 return self._covered_test_configurations_for_builder_name()[builder_name]
51 class GardeningExpectationsUpdater(BugManager):
52 def __init__(self, tool, port):
53 self._converter = TestConfigurationConverter(port.all_test_configurations(), port.configuration_specifier_macros())
54 self._extrapolator = BuildCoverageExtrapolator(self._converter)
55 self._parser = TestExpectationParser(port, [], allow_rebaseline_modifier=False)
56 self._path_to_test_expectations_file = port.path_to_test_expectations_file()
59 def close_bug(self, bug_id, reference_bug_id=None):
60 # FIXME: Implement this properly.
66 def update_expectations(self, failure_info_list):
67 expectation_lines = TestExpectationParser.tokenize_list(self._tool.filesystem.read_text_file(self._path_to_test_expectations_file))
68 for expectation_line in expectation_lines:
69 self._parser.parse(expectation_line)
70 editor = TestExpectationsEditor(expectation_lines, self)
71 updated_expectation_lines = []
72 # FIXME: Group failures by testName+failureTypeList.
73 for failure_info in failure_info_list:
74 expectation_set = set(filter(lambda expectation: expectation is not None,
75 map(TestExpectations.expectation_from_string, failure_info['failureTypeList'])))
76 assert(expectation_set)
77 test_name = failure_info['testName']
79 builder_name = failure_info['builderName']
80 affected_test_configuration_set = self._extrapolator.extrapolate_test_configurations(builder_name)
81 updated_expectation_lines.extend(editor.update_expectation(test_name, affected_test_configuration_set, expectation_set))
82 self._tool.filesystem.write_text_file(self._path_to_test_expectations_file, TestExpectationSerializer.list_to_string(expectation_lines, self._converter, reconstitute_only_these=updated_expectation_lines))
85 class GardeningHTTPServer(BaseHTTPServer.HTTPServer):
86 def __init__(self, httpd_port, config):
88 self.tool = config['tool']
89 BaseHTTPServer.HTTPServer.__init__(self, (server_name, httpd_port), GardeningHTTPRequestHandler)
92 return 'file://' + os.path.join(GardeningHTTPRequestHandler.STATIC_FILE_DIRECTORY, 'garden-o-matic.html')
95 class GardeningHTTPRequestHandler(ReflectionHandler):
96 STATIC_FILE_NAMES = frozenset()
98 STATIC_FILE_DIRECTORY = os.path.join(
99 os.path.dirname(__file__),
105 'build.webkit.org-config',
109 allow_cross_origin_requests = True
111 def _run_webkit_patch(self, args):
112 return self.server.tool.executive.run_command([self.server.tool.path()] + args, cwd=self.server.tool.scm().checkout_root)
115 def _expectations_updater(self):
116 # FIXME: Should split failure_info_list into lists per port, then edit each expectations file separately.
117 # For now, assume Chromium port.
118 port = factory.get("chromium-win-win7")
119 return GardeningExpectationsUpdater(self.server.tool, port)
122 revision = self.query['revision'][0]
123 reason = self.query['reason'][0]
124 self._run_webkit_patch([
131 self._serve_text('success')
134 self._serve_text('pong')
136 def updateexpectations(self):
137 self._expectations_updater().update_expectations(self._read_entity_body_as_json())
138 self._serve_text('success')
140 def rebaseline(self):
141 builder = self.query['builder'][0]
142 test = self.query['test'][0]
143 self._run_webkit_patch([
148 self._serve_text('success')
150 def optimizebaselines(self):
151 test = self.query['test'][0]
152 self._run_webkit_patch([
153 'optimize-baselines',
156 self._serve_text('success')