initial import
[vuplus_webkit] / Tools / Scripts / webkitpy / tool / servers / gardeningserver.py
1 # Copyright (C) 2011 Google Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
5 # met:
6 #
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.
12 #
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.
24
25 import BaseHTTPServer
26 import os
27
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
34
35
36 class BuildCoverageExtrapolator(object):
37     def __init__(self, test_configuration_converter):
38         self._test_configuration_converter = test_configuration_converter
39
40     @memoized
41     def _covered_test_configurations_for_builder_name(self):
42         coverage = {}
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))
45         return coverage
46
47     def extrapolate_test_configurations(self, builder_name):
48         return self._covered_test_configurations_for_builder_name()[builder_name]
49
50
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()
57         self._tool = tool
58
59     def close_bug(self, bug_id, reference_bug_id=None):
60         # FIXME: Implement this properly.
61         pass
62
63     def create_bug(self):
64         return "BUG_NEW"
65
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']
78             assert(test_name)
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))
83
84
85 class GardeningHTTPServer(BaseHTTPServer.HTTPServer):
86     def __init__(self, httpd_port, config):
87         server_name = ''
88         self.tool = config['tool']
89         BaseHTTPServer.HTTPServer.__init__(self, (server_name, httpd_port), GardeningHTTPRequestHandler)
90
91
92 class GardeningHTTPRequestHandler(ReflectionHandler):
93     STATIC_FILE_NAMES = frozenset([
94         "base.js",
95         "Bugzilla.js",
96         "builders.js",
97         "checkout.js",
98         "config.js",
99         "favicon-green.png",
100         "favicon-red.png",
101         "garden-o-matic.html",
102         "main.css",
103         "main.js",
104         "model.js",
105         "net.js",
106         "partytime.gif",
107         "results.js",
108         "Trac.js",
109         "ui.js",
110     ])
111
112     STATIC_FILE_DIRECTORY = os.path.join(
113         os.path.dirname(__file__),
114         "..",
115         "..",
116         "..",
117         "..",
118         "BuildSlaveSupport",
119         "build.webkit.org-config",
120         "public_html",
121         "TestFailures")
122
123     allow_cross_origin_requests = True
124
125     def _run_webkit_patch(self, args):
126         return self.server.tool.executive.run_command([self.server.tool.path()] + args, cwd=self.server.tool.scm().checkout_root)
127
128     @memoized
129     def _expectations_updater(self):
130         # FIXME: Should split failure_info_list into lists per port, then edit each expectations file separately.
131         # For now, assume Chromium port.
132         port = factory.get("chromium-win-win7")
133         return GardeningExpectationsUpdater(self.server.tool, port)
134
135     def rollout(self):
136         revision = self.query['revision'][0]
137         reason = self.query['reason'][0]
138         self._run_webkit_patch([
139             'rollout',
140             '--force-clean',
141             '--non-interactive',
142             revision,
143             reason,
144         ])
145         self._serve_text('success')
146
147     def ping(self):
148         self._serve_text('pong')
149
150     def updateexpectations(self):
151         self._expectations_updater().update_expectations(self._read_entity_body_as_json())
152         self._serve_text('success')
153
154     def rebaseline(self):
155         builder = self.query['builder'][0]
156         test = self.query['test'][0]
157         self._run_webkit_patch([
158             'rebaseline-test',
159             builder,
160             test,
161         ])
162         self._serve_text('success')
163
164     def optimizebaselines(self):
165         test = self.query['test'][0]
166         self._run_webkit_patch([
167             'optimize-baselines',
168             test,
169         ])
170         self._serve_text('success')