OLD | NEW |
| (Empty) |
1 # Copyright (C) 2010 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 # * Redistributions of source code must retain the above copyright | |
8 # notice, this list of conditions and the following disclaimer. | |
9 # * Redistributions in binary form must reproduce the above | |
10 # copyright notice, this list of conditions and the following disclaimer | |
11 # in the documentation and/or other materials provided with the | |
12 # distribution. | |
13 # * Neither the name of Google Inc. nor the names of its | |
14 # contributors may be used to endorse or promote products derived from | |
15 # this software without specific prior written permission. | |
16 # | |
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 | |
29 """Windows implementation of the Port interface.""" | |
30 | |
31 import errno | |
32 import os | |
33 import logging | |
34 | |
35 try: | |
36 import _winreg | |
37 except ImportError as e: | |
38 _winreg = None | |
39 WindowsError = Exception # this shuts up pylint. | |
40 | |
41 from webkitpy.layout_tests.breakpad.dump_reader_win import DumpReaderWin | |
42 from webkitpy.layout_tests.models import test_run_results | |
43 from webkitpy.layout_tests.port import base | |
44 from webkitpy.layout_tests.servers import crash_service | |
45 | |
46 | |
47 _log = logging.getLogger(__name__) | |
48 | |
49 | |
50 class WinPort(base.Port): | |
51 port_name = 'win' | |
52 | |
53 # FIXME: Figure out how to unify this with base.TestConfiguration.all_system
s()? | |
54 SUPPORTED_VERSIONS = ('xp', 'win7') | |
55 | |
56 FALLBACK_PATHS = { 'win7': [ 'win' ]} | |
57 FALLBACK_PATHS['xp'] = ['win-xp'] + FALLBACK_PATHS['win7'] | |
58 | |
59 DEFAULT_BUILD_DIRECTORIES = ('build', 'out') | |
60 | |
61 BUILD_REQUIREMENTS_URL = 'http://www.chromium.org/developers/how-tos/build-i
nstructions-windows' | |
62 | |
63 @classmethod | |
64 def determine_full_port_name(cls, host, options, port_name): | |
65 if port_name.endswith('win'): | |
66 assert host.platform.is_win() | |
67 # We don't maintain separate baselines for vista, so we pretend it i
s win7. | |
68 if host.platform.os_version in ('vista', '7sp0', '7sp1', 'future'): | |
69 version = 'win7' | |
70 else: | |
71 version = host.platform.os_version | |
72 port_name = port_name + '-' + version | |
73 return port_name | |
74 | |
75 def __init__(self, host, port_name, **kwargs): | |
76 super(WinPort, self).__init__(host, port_name, **kwargs) | |
77 self._version = port_name[port_name.index('win-') + len('win-'):] | |
78 assert self._version in self.SUPPORTED_VERSIONS, "%s is not in %s" % (se
lf._version, self.SUPPORTED_VERSIONS) | |
79 if not self.get_option('disable_breakpad'): | |
80 self._dump_reader = DumpReaderWin(host, self._build_path()) | |
81 self._crash_service = None | |
82 self._crash_service_available = None | |
83 | |
84 def additional_drt_flag(self): | |
85 flags = super(WinPort, self).additional_drt_flag() | |
86 flags += ['--enable-direct-write'] | |
87 if not self.get_option('disable_breakpad'): | |
88 flags += ['--enable-crash-reporter', '--crash-dumps-dir=%s' % self._
dump_reader.crash_dumps_directory()] | |
89 return flags | |
90 | |
91 def check_httpd(self): | |
92 res = super(WinPort, self).check_httpd() | |
93 if self.uses_apache(): | |
94 # In order to run CGI scripts on Win32 that use unix shebang lines,
we need to | |
95 # create entries in the registry that remap the extensions (.pl and
.cgi) to the | |
96 # appropriate Win32 paths. The command line arguments must match the
command | |
97 # line arguments in the shebang line exactly. | |
98 if _winreg: | |
99 res = self._check_reg(r'.cgi\Shell\ExecCGI\Command') and res | |
100 res = self._check_reg(r'.pl\Shell\ExecCGI\Command') and res | |
101 else: | |
102 _log.warning("Could not check the registry; http may not work co
rrectly.") | |
103 | |
104 return res | |
105 | |
106 def _check_reg(self, sub_key): | |
107 # see comments in check_httpd(), above, for why this routine exists and
what it's doing. | |
108 try: | |
109 # Note that we HKCR is a union of HKLM and HKCR (with the latter | |
110 # overridding the former), so reading from HKCR ensures that we get | |
111 # the value if it is set in either place. See als comments below. | |
112 hkey = _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, sub_key) | |
113 args = _winreg.QueryValue(hkey, '').split() | |
114 _winreg.CloseKey(hkey) | |
115 | |
116 # In order to keep multiple checkouts from stepping on each other, w
e simply check that an | |
117 # existing entry points to a valid path and has the right command li
ne. | |
118 if len(args) == 2 and self._filesystem.exists(args[0]) and args[0].e
ndswith('perl.exe') and args[1] == '-wT': | |
119 return True | |
120 except WindowsError, e: | |
121 if e.errno != errno.ENOENT: | |
122 raise e | |
123 # The key simply probably doesn't exist. | |
124 pass | |
125 | |
126 # Note that we write to HKCU so that we don't need privileged access | |
127 # to the registry, and that will get reflected in HKCR when it is read,
above. | |
128 cmdline = self.path_from_chromium_base('third_party', 'perl', 'perl', 'b
in', 'perl.exe') + ' -wT' | |
129 hkey = _winreg.CreateKeyEx(_winreg.HKEY_CURRENT_USER, 'Software\\Classes
\\' + sub_key, 0, _winreg.KEY_WRITE) | |
130 _winreg.SetValue(hkey, '', _winreg.REG_SZ, cmdline) | |
131 _winreg.CloseKey(hkey) | |
132 return True | |
133 | |
134 def setup_test_run(self): | |
135 super(WinPort, self).setup_test_run() | |
136 | |
137 if not self.get_option('disable_breakpad'): | |
138 assert not self._crash_service, 'Already running a crash service' | |
139 if self._crash_service_available == None: | |
140 self._crash_service_available = self._check_crash_service_availa
ble() | |
141 if not self._crash_service_available: | |
142 return | |
143 service = crash_service.CrashService(self, self._dump_reader.crash_d
umps_directory()) | |
144 service.start() | |
145 self._crash_service = service | |
146 | |
147 def clean_up_test_run(self): | |
148 super(WinPort, self).clean_up_test_run() | |
149 | |
150 if self._crash_service: | |
151 self._crash_service.stop() | |
152 self._crash_service = None | |
153 | |
154 def setup_environ_for_server(self, server_name=None): | |
155 env = super(WinPort, self).setup_environ_for_server(server_name) | |
156 | |
157 # FIXME: This is a temporary hack to get the cr-win bot online until | |
158 # someone from the cr-win port can take a look. | |
159 apache_envvars = ['SYSTEMDRIVE', 'SYSTEMROOT', 'TEMP', 'TMP'] | |
160 for key, value in os.environ.items(): | |
161 if key not in env and key in apache_envvars: | |
162 env[key] = value | |
163 | |
164 # Put the cygwin directory first in the path to find cygwin1.dll. | |
165 env["PATH"] = "%s;%s" % (self.path_from_chromium_base("third_party", "cy
gwin", "bin"), env["PATH"]) | |
166 # Configure the cygwin directory so that pywebsocket finds proper | |
167 # python executable to run cgi program. | |
168 env["CYGWIN_PATH"] = self.path_from_chromium_base("third_party", "cygwin
", "bin") | |
169 if self.get_option('register_cygwin'): | |
170 setup_mount = self.path_from_chromium_base("third_party", "cygwin",
"setup_mount.bat") | |
171 self._executive.run_command([setup_mount]) # Paths are all absolute
, so this does not require a cwd. | |
172 return env | |
173 | |
174 def _modules_to_search_for_symbols(self): | |
175 # FIXME: we should return the path to the ffmpeg equivalents to detect i
f we have the mp3 and aac codecs installed. | |
176 # See https://bugs.webkit.org/show_bug.cgi?id=89706. | |
177 return [] | |
178 | |
179 def check_build(self, needs_http, printer): | |
180 result = super(WinPort, self).check_build(needs_http, printer) | |
181 | |
182 self._crash_service_available = self._check_crash_service_available() | |
183 if not self._crash_service_available: | |
184 result = test_run_results.UNEXPECTED_ERROR_EXIT_STATUS | |
185 | |
186 if result: | |
187 _log.error('For complete Windows build requirements, please see:') | |
188 _log.error('') | |
189 _log.error(' http://dev.chromium.org/developers/how-tos/build-ins
tructions-windows') | |
190 return result | |
191 | |
192 def operating_system(self): | |
193 return 'win' | |
194 | |
195 def relative_test_filename(self, filename): | |
196 path = filename[len(self.layout_tests_dir()) + 1:] | |
197 return path.replace('\\', '/') | |
198 | |
199 def uses_apache(self): | |
200 val = self.get_option('use_apache') | |
201 if val is None: | |
202 return True | |
203 return val | |
204 | |
205 def path_to_apache(self): | |
206 return self.path_from_chromium_base('third_party', 'apache-win32', 'bin'
, 'httpd.exe') | |
207 | |
208 def path_to_apache_config_file(self): | |
209 return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', 'w
in-httpd.conf') | |
210 | |
211 # | |
212 # PROTECTED ROUTINES | |
213 # | |
214 | |
215 def _path_to_driver(self, configuration=None): | |
216 binary_name = '%s.exe' % self.driver_name() | |
217 return self._build_path_with_configuration(configuration, binary_name) | |
218 | |
219 def _path_to_crash_service(self): | |
220 binary_name = 'content_shell_crash_service.exe' | |
221 return self._build_path(binary_name) | |
222 | |
223 def _path_to_image_diff(self): | |
224 binary_name = 'image_diff.exe' | |
225 return self._build_path(binary_name) | |
226 | |
227 def _path_to_wdiff(self): | |
228 return self.path_from_chromium_base('third_party', 'cygwin', 'bin', 'wdi
ff.exe') | |
229 | |
230 def _check_crash_service_available(self): | |
231 """Checks whether the crash service binary is present.""" | |
232 result = self._check_file_exists(self._path_to_crash_service(), "content
_shell_crash_service.exe") | |
233 if not result: | |
234 _log.error(" Could not find crash service, unexpected crashes won
't be symbolized.") | |
235 _log.error(' Did you build the target blink_tests?') | |
236 _log.error('') | |
237 return result | |
238 | |
239 def look_for_new_crash_logs(self, crashed_processes, start_time): | |
240 if self.get_option('disable_breakpad'): | |
241 return None | |
242 return self._dump_reader.look_for_new_crash_logs(crashed_processes, star
t_time) | |
243 | |
244 def clobber_old_port_specific_results(self): | |
245 if not self.get_option('disable_breakpad'): | |
246 self._dump_reader.clobber_old_results() | |
OLD | NEW |