OLD | NEW |
1 # Copyright (C) 2011 Google Inc. All rights reserved. | 1 # Copyright (C) 2011 Google Inc. All rights reserved. |
2 # | 2 # |
3 # Redistribution and use in source and binary forms, with or without | 3 # Redistribution and use in source and binary forms, with or without |
4 # modification, are permitted provided that the following conditions are | 4 # modification, are permitted provided that the following conditions are |
5 # met: | 5 # met: |
6 # | 6 # |
7 # * Redistributions of source code must retain the above copyright | 7 # * Redistributions of source code must retain the above copyright |
8 # notice, this list of conditions and the following disclaimer. | 8 # notice, this list of conditions and the following disclaimer. |
9 # * Redistributions in binary form must reproduce the above | 9 # * Redistributions in binary form must reproduce the above |
10 # copyright notice, this list of conditions and the following disclaimer | 10 # copyright notice, this list of conditions and the following disclaimer |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 # We call stop() even if we crashed or timed out in order to get any
remaining stdout/stderr output. | 171 # We call stop() even if we crashed or timed out in order to get any
remaining stdout/stderr output. |
172 # In the timeout case, we kill the hung process as well. | 172 # In the timeout case, we kill the hung process as well. |
173 out, err = self._server_process.stop(self._port.driver_stop_timeout(
) if stop_when_done else 0.0) | 173 out, err = self._server_process.stop(self._port.driver_stop_timeout(
) if stop_when_done else 0.0) |
174 if out: | 174 if out: |
175 text += out | 175 text += out |
176 if err: | 176 if err: |
177 self.error_from_test += err | 177 self.error_from_test += err |
178 self._server_process = None | 178 self._server_process = None |
179 | 179 |
180 crash_log = None | 180 crash_log = None |
181 leak_log = None | |
182 if crashed: | 181 if crashed: |
183 self.error_from_test, crash_log = self._get_crash_log(text, self.err
or_from_test, newer_than=start_time) | 182 self.error_from_test, crash_log = self._get_crash_log(text, self.err
or_from_test, newer_than=start_time) |
184 | 183 |
185 # If we don't find a crash log use a placeholder error message inste
ad. | 184 # If we don't find a crash log use a placeholder error message inste
ad. |
186 if not crash_log: | 185 if not crash_log: |
187 pid_str = str(self._crashed_pid) if self._crashed_pid else "unkn
own pid" | 186 pid_str = str(self._crashed_pid) if self._crashed_pid else "unkn
own pid" |
188 crash_log = 'No crash log found for %s:%s.\n' % (self._crashed_p
rocess_name, pid_str) | 187 crash_log = 'No crash log found for %s:%s.\n' % (self._crashed_p
rocess_name, pid_str) |
189 # If we were unresponsive append a message informing there may n
ot have been a crash. | 188 # If we were unresponsive append a message informing there may n
ot have been a crash. |
190 if self._subprocess_was_unresponsive: | 189 if self._subprocess_was_unresponsive: |
191 crash_log += 'Process failed to become responsive before tim
ing out.\n' | 190 crash_log += 'Process failed to become responsive before tim
ing out.\n' |
192 | 191 |
193 # Print stdout and stderr to the placeholder crash log; we want
as much context as possible. | 192 # Print stdout and stderr to the placeholder crash log; we want
as much context as possible. |
194 if self.error_from_test: | 193 if self.error_from_test: |
195 crash_log += '\nstdout:\n%s\nstderr:\n%s\n' % (text, self.er
ror_from_test) | 194 crash_log += '\nstdout:\n%s\nstderr:\n%s\n' % (text, self.er
ror_from_test) |
196 elif leaked: | |
197 self.error_from_test, leak_log = self._get_leak_log(text, self.error
_from_test, newer_than=start_time) | |
198 | 195 |
199 return DriverOutput(text, image, actual_image_hash, audio, | 196 return DriverOutput(text, image, actual_image_hash, audio, |
200 crash=crashed, test_time=time.time() - test_begin_time, measurements
=self._measurements, | 197 crash=crashed, test_time=time.time() - test_begin_time, measurements
=self._measurements, |
201 timeout=timed_out, error=self.error_from_test, | 198 timeout=timed_out, error=self.error_from_test, |
202 crashed_process_name=self._crashed_process_name, | 199 crashed_process_name=self._crashed_process_name, |
203 crashed_pid=self._crashed_pid, crash_log=crash_log, | 200 crashed_pid=self._crashed_pid, crash_log=crash_log, |
204 leak=leaked, leak_log=leak_log, | 201 leak=leaked, leak_log=self._leak_log, |
205 pid=pid) | 202 pid=pid) |
206 | 203 |
207 def _get_crash_log(self, stdout, stderr, newer_than): | 204 def _get_crash_log(self, stdout, stderr, newer_than): |
208 return self._port._get_crash_log(self._crashed_process_name, self._crash
ed_pid, stdout, stderr, newer_than) | 205 return self._port._get_crash_log(self._crashed_process_name, self._crash
ed_pid, stdout, stderr, newer_than) |
209 | 206 |
210 def _get_leak_log(self, stdout, stderr, newer_than): | |
211 return self._port._get_leak_log(self._crashed_process_name, self._crashe
d_pid, stdout, stderr, newer_than) | |
212 | |
213 # FIXME: Seems this could just be inlined into callers. | 207 # FIXME: Seems this could just be inlined into callers. |
214 @classmethod | 208 @classmethod |
215 def _command_wrapper(cls, wrapper_option): | 209 def _command_wrapper(cls, wrapper_option): |
216 # Hook for injecting valgrind or other runtime instrumentation, | 210 # Hook for injecting valgrind or other runtime instrumentation, |
217 # used by e.g. tools/valgrind/valgrind_tests.py. | 211 # used by e.g. tools/valgrind/valgrind_tests.py. |
218 return shlex.split(wrapper_option) if wrapper_option else [] | 212 return shlex.split(wrapper_option) if wrapper_option else [] |
219 | 213 |
220 HTTP_DIR = "http/tests/" | 214 HTTP_DIR = "http/tests/" |
221 HTTP_LOCAL_DIR = "http/tests/local/" | 215 HTTP_LOCAL_DIR = "http/tests/local/" |
222 | 216 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
278 | 272 |
279 def _start(self, pixel_tests, per_test_args, wait_for_ready=True): | 273 def _start(self, pixel_tests, per_test_args, wait_for_ready=True): |
280 self.stop() | 274 self.stop() |
281 self._driver_tempdir = self._port._filesystem.mkdtemp(prefix='%s-' % sel
f._port.driver_name()) | 275 self._driver_tempdir = self._port._filesystem.mkdtemp(prefix='%s-' % sel
f._port.driver_name()) |
282 server_name = self._port.driver_name() | 276 server_name = self._port.driver_name() |
283 environment = self._port.setup_environ_for_server(server_name) | 277 environment = self._port.setup_environ_for_server(server_name) |
284 environment = self._setup_environ_for_driver(environment) | 278 environment = self._setup_environ_for_driver(environment) |
285 self._crashed_process_name = None | 279 self._crashed_process_name = None |
286 self._crashed_pid = None | 280 self._crashed_pid = None |
287 self._leaked = False | 281 self._leaked = False |
| 282 self._leak_log = None |
288 cmd_line = self.cmd_line(pixel_tests, per_test_args) | 283 cmd_line = self.cmd_line(pixel_tests, per_test_args) |
289 self._server_process = self._port._server_process_constructor(self._port
, server_name, cmd_line, environment, logging=self._port.get_option("driver_logg
ing")) | 284 self._server_process = self._port._server_process_constructor(self._port
, server_name, cmd_line, environment, logging=self._port.get_option("driver_logg
ing")) |
290 self._server_process.start() | 285 self._server_process.start() |
291 self._current_cmd_line = cmd_line | 286 self._current_cmd_line = cmd_line |
292 | 287 |
293 if wait_for_ready: | 288 if wait_for_ready: |
294 deadline = time.time() + DRIVER_START_TIMEOUT_SECS | 289 deadline = time.time() + DRIVER_START_TIMEOUT_SECS |
295 if not self._wait_for_server_process_output(self._server_process, de
adline, '#READY'): | 290 if not self._wait_for_server_process_output(self._server_process, de
adline, '#READY'): |
296 _log.error("content_shell took too long to startup.") | 291 _log.error("content_shell took too long to startup.") |
297 | 292 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
363 self._subprocess_was_unresponsive = True | 358 self._subprocess_was_unresponsive = True |
364 self._port.sample_process(self._crashed_process_name, self._cras
hed_pid) | 359 self._port.sample_process(self._crashed_process_name, self._cras
hed_pid) |
365 # We want to show this since it's not a regular crash and probab
ly we don't have a crash log. | 360 # We want to show this since it's not a regular crash and probab
ly we don't have a crash log. |
366 self.error_from_test += error_line | 361 self.error_from_test += error_line |
367 return True | 362 return True |
368 return self.has_crashed() | 363 return self.has_crashed() |
369 | 364 |
370 def _check_for_leak(self, error_line): | 365 def _check_for_leak(self, error_line): |
371 if error_line.startswith("#LEAK - "): | 366 if error_line.startswith("#LEAK - "): |
372 self._leaked = True | 367 self._leaked = True |
| 368 match = re.match('#LEAK - (\S+) pid (\d+) (.+)\n', error_line) |
| 369 self._leak_log = match.group(3) |
373 return self._leaked | 370 return self._leaked |
374 | 371 |
375 def _command_from_driver_input(self, driver_input): | 372 def _command_from_driver_input(self, driver_input): |
376 # FIXME: performance tests pass in full URLs instead of test names. | 373 # FIXME: performance tests pass in full URLs instead of test names. |
377 if driver_input.test_name.startswith('http://') or driver_input.test_nam
e.startswith('https://') or driver_input.test_name == ('about:blank'): | 374 if driver_input.test_name.startswith('http://') or driver_input.test_nam
e.startswith('https://') or driver_input.test_name == ('about:blank'): |
378 command = driver_input.test_name | 375 command = driver_input.test_name |
379 elif self.is_http_test(driver_input.test_name): | 376 elif self.is_http_test(driver_input.test_name): |
380 command = self.test_to_uri(driver_input.test_name) | 377 command = self.test_to_uri(driver_input.test_name) |
381 else: | 378 else: |
382 command = self._port.abspath_for_test(driver_input.test_name) | 379 command = self._port.abspath_for_test(driver_input.test_name) |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 if content_length_before_header_check != block._content_length: | 475 if content_length_before_header_check != block._content_length: |
479 if block._content_length > 0: | 476 if block._content_length > 0: |
480 block.content = self._server_process.read_stdout(deadlin
e, block._content_length) | 477 block.content = self._server_process.read_stdout(deadlin
e, block._content_length) |
481 else: | 478 else: |
482 _log.error("Received content of type %s with Content-Len
gth of 0! This indicates a bug in %s.", | 479 _log.error("Received content of type %s with Content-Len
gth of 0! This indicates a bug in %s.", |
483 block.content_type, self._server_process.name
()) | 480 block.content_type, self._server_process.name
()) |
484 | 481 |
485 if err_line: | 482 if err_line: |
486 if self._check_for_driver_crash(err_line): | 483 if self._check_for_driver_crash(err_line): |
487 break | 484 break |
488 self._check_for_leak(err_line) | 485 if self._check_for_leak(err_line): |
| 486 break |
489 self.error_from_test += err_line | 487 self.error_from_test += err_line |
490 | 488 |
491 block.decode_content() | 489 block.decode_content() |
492 return block | 490 return block |
493 | 491 |
494 | 492 |
495 class ContentBlock(object): | 493 class ContentBlock(object): |
496 def __init__(self): | 494 def __init__(self): |
497 self.content_type = None | 495 self.content_type = None |
498 self.encoding = None | 496 self.encoding = None |
499 self.content_hash = None | 497 self.content_hash = None |
500 self._content_length = None | 498 self._content_length = None |
501 # Content is treated as binary data even though the text output is usual
ly UTF-8. | 499 # Content is treated as binary data even though the text output is usual
ly UTF-8. |
502 self.content = str() # FIXME: Should be bytearray() once we require Pyt
hon 2.6. | 500 self.content = str() # FIXME: Should be bytearray() once we require Pyt
hon 2.6. |
503 self.decoded_content = None | 501 self.decoded_content = None |
504 self.malloc = None | 502 self.malloc = None |
505 self.js_heap = None | 503 self.js_heap = None |
506 | 504 |
507 def decode_content(self): | 505 def decode_content(self): |
508 if self.encoding == 'base64' and self.content is not None: | 506 if self.encoding == 'base64' and self.content is not None: |
509 self.decoded_content = base64.b64decode(self.content) | 507 self.decoded_content = base64.b64decode(self.content) |
510 else: | 508 else: |
511 self.decoded_content = self.content | 509 self.decoded_content = self.content |
OLD | NEW |