OLD | NEW |
1 # Copyright (C) 2010 Google Inc. All rights reserved. | 1 # Copyright (C) 2010 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 21 matching lines...) Expand all Loading... |
32 import cgi | 32 import cgi |
33 import difflib | 33 import difflib |
34 import errno | 34 import errno |
35 import itertools | 35 import itertools |
36 import logging | 36 import logging |
37 import os | 37 import os |
38 import operator | 38 import operator |
39 import optparse | 39 import optparse |
40 import re | 40 import re |
41 import sys | 41 import sys |
| 42 from functools import reduce |
42 | 43 |
43 try: | 44 try: |
44 from collections import OrderedDict | 45 from collections import OrderedDict |
45 except ImportError: | 46 except ImportError: |
46 # Needed for Python < 2.7 | 47 # Needed for Python < 2.7 |
47 from webkitpy.thirdparty.ordered_dict import OrderedDict | 48 from webkitpy.thirdparty.ordered_dict import OrderedDict |
48 | 49 |
49 | 50 |
50 from webkitpy.common import find_files | 51 from webkitpy.common import find_files |
51 from webkitpy.common import read_checksum_from_png | 52 from webkitpy.common import read_checksum_from_png |
(...skipping 11 matching lines...) Expand all Loading... |
63 from webkitpy.layout_tests.port import server_process | 64 from webkitpy.layout_tests.port import server_process |
64 from webkitpy.layout_tests.port.factory import PortFactory | 65 from webkitpy.layout_tests.port.factory import PortFactory |
65 from webkitpy.layout_tests.servers import apache_http | 66 from webkitpy.layout_tests.servers import apache_http |
66 from webkitpy.layout_tests.servers import pywebsocket | 67 from webkitpy.layout_tests.servers import pywebsocket |
67 | 68 |
68 _log = logging.getLogger(__name__) | 69 _log = logging.getLogger(__name__) |
69 | 70 |
70 | 71 |
71 # FIXME: This class should merge with WebKitPort now that Chromium behaves mostl
y like other webkit ports. | 72 # FIXME: This class should merge with WebKitPort now that Chromium behaves mostl
y like other webkit ports. |
72 class Port(object): | 73 class Port(object): |
| 74 |
73 """Abstract class for Port-specific hooks for the layout_test package.""" | 75 """Abstract class for Port-specific hooks for the layout_test package.""" |
74 | 76 |
75 # Subclasses override this. This should indicate the basic implementation | 77 # Subclasses override this. This should indicate the basic implementation |
76 # part of the port name, e.g., 'mac', 'win', 'gtk'; there is probably (?) | 78 # part of the port name, e.g., 'mac', 'win', 'gtk'; there is probably (?) |
77 # one unique value per class. | 79 # one unique value per class. |
78 | 80 |
79 # FIXME: We should probably rename this to something like 'implementation_na
me'. | 81 # FIXME: We should probably rename this to something like 'implementation_na
me'. |
80 port_name = None | 82 port_name = None |
81 | 83 |
82 # Test names resemble unix relative paths, and use '/' as a directory separa
tor. | 84 # Test names resemble unix relative paths, and use '/' as a directory separa
tor. |
(...skipping 17 matching lines...) Expand all Loading... |
100 | 102 |
101 ('mountainlion', 'x86'), | 103 ('mountainlion', 'x86'), |
102 ('mavericks', 'x86'), | 104 ('mavericks', 'x86'), |
103 ('xp', 'x86'), | 105 ('xp', 'x86'), |
104 ('win7', 'x86'), | 106 ('win7', 'x86'), |
105 ('lucid', 'x86'), | 107 ('lucid', 'x86'), |
106 ('lucid', 'x86_64'), | 108 ('lucid', 'x86_64'), |
107 # FIXME: Technically this should be 'arm', but adding a third architectu
re type breaks TestConfigurationConverter. | 109 # FIXME: Technically this should be 'arm', but adding a third architectu
re type breaks TestConfigurationConverter. |
108 # If we need this to be 'arm' in the future, then we first have to fix T
estConfigurationConverter. | 110 # If we need this to be 'arm' in the future, then we first have to fix T
estConfigurationConverter. |
109 ('icecreamsandwich', 'x86'), | 111 ('icecreamsandwich', 'x86'), |
110 ) | 112 ) |
111 | 113 |
112 ALL_BASELINE_VARIANTS = [ | 114 ALL_BASELINE_VARIANTS = [ |
113 'mac-mavericks', 'mac-mountainlion', 'mac-retina', 'mac-lion', 'mac-snow
leopard', | 115 'mac-mavericks', 'mac-mountainlion', 'mac-retina', 'mac-lion', 'mac-snow
leopard', |
114 'win-win7', 'win-xp', | 116 'win-win7', 'win-xp', |
115 'linux-x86_64', 'linux-x86', | 117 'linux-x86_64', 'linux-x86', |
116 ] | 118 ] |
117 | 119 |
118 CONFIGURATION_SPECIFIER_MACROS = { | 120 CONFIGURATION_SPECIFIER_MACROS = { |
119 'mac': ['snowleopard', 'lion', 'retina', 'mountainlion', 'mavericks'], | 121 'mac': ['snowleopard', 'lion', 'retina', 'mountainlion', 'mavericks'], |
120 'win': ['xp', 'win7'], | 122 'win': ['xp', 'win7'], |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
200 # wdiff, assume it's not available. This will leak one | 202 # wdiff, assume it's not available. This will leak one |
201 # file descriptor but that's better than leaking each time | 203 # file descriptor but that's better than leaking each time |
202 # wdiff would be run. | 204 # wdiff would be run. |
203 # | 205 # |
204 # http://mail.python.org/pipermail/python-list/ | 206 # http://mail.python.org/pipermail/python-list/ |
205 # 2008-August/505753.html | 207 # 2008-August/505753.html |
206 # http://bugs.python.org/issue3210 | 208 # http://bugs.python.org/issue3210 |
207 self._wdiff_available = None | 209 self._wdiff_available = None |
208 | 210 |
209 # FIXME: prettypatch.py knows this path, why is it copied here? | 211 # FIXME: prettypatch.py knows this path, why is it copied here? |
210 self._pretty_patch_path = self.path_from_webkit_base("Tools", "Scripts",
"webkitruby", "PrettyPatch", "prettify.rb") | 212 self._pretty_patch_path = self.path_from_webkit_base('Tools', 'Scripts',
'webkitruby', 'PrettyPatch', 'prettify.rb') |
211 self._pretty_patch_available = None | 213 self._pretty_patch_available = None |
212 | 214 |
213 if not hasattr(options, 'configuration') or not options.configuration: | 215 if not hasattr(options, 'configuration') or not options.configuration: |
214 self.set_option_default('configuration', self.default_configuration(
)) | 216 self.set_option_default('configuration', self.default_configuration(
)) |
215 self._test_configuration = None | 217 self._test_configuration = None |
216 self._reftest_list = {} | 218 self._reftest_list = {} |
217 self._results_directory = None | 219 self._results_directory = None |
218 | 220 |
219 def buildbot_archives_baselines(self): | 221 def buildbot_archives_baselines(self): |
220 return True | 222 return True |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 result = self._dump_reader.check_is_functional() and result | 353 result = self._dump_reader.check_is_functional() and result |
352 | 354 |
353 if needs_http: | 355 if needs_http: |
354 result = self.check_httpd() and result | 356 result = self.check_httpd() and result |
355 | 357 |
356 return test_run_results.OK_EXIT_STATUS if result else test_run_results.U
NEXPECTED_ERROR_EXIT_STATUS | 358 return test_run_results.OK_EXIT_STATUS if result else test_run_results.U
NEXPECTED_ERROR_EXIT_STATUS |
357 | 359 |
358 def _check_driver(self): | 360 def _check_driver(self): |
359 driver_path = self._path_to_driver() | 361 driver_path = self._path_to_driver() |
360 if not self._filesystem.exists(driver_path): | 362 if not self._filesystem.exists(driver_path): |
361 _log.error("%s was not found at %s" % (self.driver_name(), driver_pa
th)) | 363 _log.error('%s was not found at %s' % (self.driver_name(), driver_pa
th)) |
362 return False | 364 return False |
363 return True | 365 return True |
364 | 366 |
365 def _check_port_build(self): | 367 def _check_port_build(self): |
366 # Ports can override this method to do additional checks. | 368 # Ports can override this method to do additional checks. |
367 return True | 369 return True |
368 | 370 |
369 def check_sys_deps(self, needs_http): | 371 def check_sys_deps(self, needs_http): |
370 """If the port needs to do some runtime checks to ensure that the | 372 """If the port needs to do some runtime checks to ensure that the |
371 tests can be run successfully, it should override this routine. | 373 tests can be run successfully, it should override this routine. |
(...skipping 17 matching lines...) Expand all Loading... |
389 _log.error('') | 391 _log.error('') |
390 _log.error('For complete build requirements, please see:') | 392 _log.error('For complete build requirements, please see:') |
391 _log.error(self.BUILD_REQUIREMENTS_URL) | 393 _log.error(self.BUILD_REQUIREMENTS_URL) |
392 return test_run_results.SYS_DEPS_EXIT_STATUS | 394 return test_run_results.SYS_DEPS_EXIT_STATUS |
393 return test_run_results.OK_EXIT_STATUS | 395 return test_run_results.OK_EXIT_STATUS |
394 | 396 |
395 def check_image_diff(self, override_step=None, logging=True): | 397 def check_image_diff(self, override_step=None, logging=True): |
396 """This routine is used to check whether image_diff binary exists.""" | 398 """This routine is used to check whether image_diff binary exists.""" |
397 image_diff_path = self._path_to_image_diff() | 399 image_diff_path = self._path_to_image_diff() |
398 if not self._filesystem.exists(image_diff_path): | 400 if not self._filesystem.exists(image_diff_path): |
399 _log.error("image_diff was not found at %s" % image_diff_path) | 401 _log.error('image_diff was not found at %s' % image_diff_path) |
400 return False | 402 return False |
401 return True | 403 return True |
402 | 404 |
403 def check_pretty_patch(self, logging=True): | 405 def check_pretty_patch(self, logging=True): |
404 """Checks whether we can use the PrettyPatch ruby script.""" | 406 """Checks whether we can use the PrettyPatch ruby script.""" |
405 try: | 407 try: |
406 _ = self._executive.run_command(['ruby', '--version']) | 408 _ = self._executive.run_command(['ruby', '--version']) |
407 except OSError, e: | 409 except OSError as e: |
408 if e.errno in [errno.ENOENT, errno.EACCES, errno.ECHILD]: | 410 if e.errno in [errno.ENOENT, errno.EACCES, errno.ECHILD]: |
409 if logging: | 411 if logging: |
410 _log.warning("Ruby is not installed; can't generate pretty p
atches.") | 412 _log.warning("Ruby is not installed; can't generate pretty p
atches.") |
411 _log.warning('') | 413 _log.warning('') |
412 return False | 414 return False |
413 | 415 |
414 if not self._filesystem.exists(self._pretty_patch_path): | 416 if not self._filesystem.exists(self._pretty_patch_path): |
415 if logging: | 417 if logging: |
416 _log.warning("Unable to find %s; can't generate pretty patches."
% self._pretty_patch_path) | 418 _log.warning("Unable to find %s; can't generate pretty patches."
% self._pretty_patch_path) |
417 _log.warning('') | 419 _log.warning('') |
(...skipping 20 matching lines...) Expand all Loading... |
438 return True | 440 return True |
439 | 441 |
440 def _wdiff_missing_message(self): | 442 def _wdiff_missing_message(self): |
441 return 'wdiff is not installed; please install it to generate word-by-wo
rd diffs.' | 443 return 'wdiff is not installed; please install it to generate word-by-wo
rd diffs.' |
442 | 444 |
443 def check_httpd(self): | 445 def check_httpd(self): |
444 httpd_path = self.path_to_apache() | 446 httpd_path = self.path_to_apache() |
445 try: | 447 try: |
446 server_name = self._filesystem.basename(httpd_path) | 448 server_name = self._filesystem.basename(httpd_path) |
447 env = self.setup_environ_for_server(server_name) | 449 env = self.setup_environ_for_server(server_name) |
448 if self._executive.run_command([httpd_path, "-v"], env=env, return_e
xit_code=True) != 0: | 450 if self._executive.run_command([httpd_path, '-v'], env=env, return_e
xit_code=True) != 0: |
449 _log.error("httpd seems broken. Cannot run http tests.") | 451 _log.error('httpd seems broken. Cannot run http tests.') |
450 return False | 452 return False |
451 return True | 453 return True |
452 except OSError: | 454 except OSError: |
453 _log.error("No httpd found. Cannot run http tests.") | 455 _log.error('No httpd found. Cannot run http tests.') |
454 return False | 456 return False |
455 | 457 |
456 def do_text_results_differ(self, expected_text, actual_text): | 458 def do_text_results_differ(self, expected_text, actual_text): |
457 return expected_text != actual_text | 459 return expected_text != actual_text |
458 | 460 |
459 def do_audio_results_differ(self, expected_audio, actual_audio): | 461 def do_audio_results_differ(self, expected_audio, actual_audio): |
460 return expected_audio != actual_audio | 462 return expected_audio != actual_audio |
461 | 463 |
462 def diff_image(self, expected_contents, actual_contents): | 464 def diff_image(self, expected_contents, actual_contents): |
463 """Compare two images and return a tuple of an image diff, and an error
string. | 465 """Compare two images and return a tuple of an image diff, and an error
string. |
464 | 466 |
465 If an error occurs (like image_diff isn't found, or crashes, we log an e
rror and return True (for a diff). | 467 If an error occurs (like image_diff isn't found, or crashes, we log an e
rror and return True (for a diff). |
466 """ | 468 """ |
467 # If only one of them exists, return that one. | 469 # If only one of them exists, return that one. |
468 if not actual_contents and not expected_contents: | 470 if not actual_contents and not expected_contents: |
469 return (None, None) | 471 return (None, None) |
470 if not actual_contents: | 472 if not actual_contents: |
471 return (expected_contents, None) | 473 return (expected_contents, None) |
472 if not expected_contents: | 474 if not expected_contents: |
473 return (actual_contents, None) | 475 return (actual_contents, None) |
474 | 476 |
475 tempdir = self._filesystem.mkdtemp() | 477 tempdir = self._filesystem.mkdtemp() |
476 | 478 |
477 expected_filename = self._filesystem.join(str(tempdir), "expected.png") | 479 expected_filename = self._filesystem.join(str(tempdir), 'expected.png') |
478 self._filesystem.write_binary_file(expected_filename, expected_contents) | 480 self._filesystem.write_binary_file(expected_filename, expected_contents) |
479 | 481 |
480 actual_filename = self._filesystem.join(str(tempdir), "actual.png") | 482 actual_filename = self._filesystem.join(str(tempdir), 'actual.png') |
481 self._filesystem.write_binary_file(actual_filename, actual_contents) | 483 self._filesystem.write_binary_file(actual_filename, actual_contents) |
482 | 484 |
483 diff_filename = self._filesystem.join(str(tempdir), "diff.png") | 485 diff_filename = self._filesystem.join(str(tempdir), 'diff.png') |
484 | 486 |
485 # image_diff needs native win paths as arguments, so we need to convert
them if running under cygwin. | 487 # image_diff needs native win paths as arguments, so we need to convert
them if running under cygwin. |
486 native_expected_filename = self._convert_path(expected_filename) | 488 native_expected_filename = self._convert_path(expected_filename) |
487 native_actual_filename = self._convert_path(actual_filename) | 489 native_actual_filename = self._convert_path(actual_filename) |
488 native_diff_filename = self._convert_path(diff_filename) | 490 native_diff_filename = self._convert_path(diff_filename) |
489 | 491 |
490 executable = self._path_to_image_diff() | 492 executable = self._path_to_image_diff() |
491 # Note that although we are handed 'old', 'new', image_diff wants 'new',
'old'. | 493 # Note that although we are handed 'old', 'new', image_diff wants 'new',
'old'. |
492 comand = [executable, '--diff', native_actual_filename, native_expected_
filename, native_diff_filename] | 494 comand = [executable, '--diff', native_actual_filename, native_expected_
filename, native_diff_filename] |
493 | 495 |
494 result = None | 496 result = None |
495 err_str = None | 497 err_str = None |
496 try: | 498 try: |
497 exit_code = self._executive.run_command(comand, return_exit_code=Tru
e) | 499 exit_code = self._executive.run_command(comand, return_exit_code=Tru
e) |
498 if exit_code == 0: | 500 if exit_code == 0: |
499 # The images are the same. | 501 # The images are the same. |
500 result = None | 502 result = None |
501 elif exit_code == 1: | 503 elif exit_code == 1: |
502 result = self._filesystem.read_binary_file(native_diff_filename) | 504 result = self._filesystem.read_binary_file(native_diff_filename) |
503 else: | 505 else: |
504 err_str = "Image diff returned an exit code of %s. See http://cr
bug.com/278596" % exit_code | 506 err_str = 'Image diff returned an exit code of %s. See http://cr
bug.com/278596' % exit_code |
505 except OSError, e: | 507 except OSError as e: |
506 err_str = 'error running image diff: %s' % str(e) | 508 err_str = 'error running image diff: %s' % str(e) |
507 finally: | 509 finally: |
508 self._filesystem.rmtree(str(tempdir)) | 510 self._filesystem.rmtree(str(tempdir)) |
509 | 511 |
510 return (result, err_str or None) | 512 return (result, err_str or None) |
511 | 513 |
512 def diff_text(self, expected_text, actual_text, expected_filename, actual_fi
lename): | 514 def diff_text(self, expected_text, actual_text, expected_filename, actual_fi
lename): |
513 """Returns a string containing the diff of the two text strings | 515 """Returns a string containing the diff of the two text strings |
514 in 'unified diff' format.""" | 516 in 'unified diff' format.""" |
515 | 517 |
(...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
674 """Returns the text output we expect the test to produce, or None | 676 """Returns the text output we expect the test to produce, or None |
675 if we don't expect there to be any text output. | 677 if we don't expect there to be any text output. |
676 End-of-line characters are normalized to '\n'.""" | 678 End-of-line characters are normalized to '\n'.""" |
677 # FIXME: DRT output is actually utf-8, but since we don't decode the | 679 # FIXME: DRT output is actually utf-8, but since we don't decode the |
678 # output from DRT (instead treating it as a binary string), we read the | 680 # output from DRT (instead treating it as a binary string), we read the |
679 # baselines as a binary string, too. | 681 # baselines as a binary string, too. |
680 baseline_path = self.expected_filename(test_name, '.txt') | 682 baseline_path = self.expected_filename(test_name, '.txt') |
681 if not self._filesystem.exists(baseline_path): | 683 if not self._filesystem.exists(baseline_path): |
682 return None | 684 return None |
683 text = self._filesystem.read_binary_file(baseline_path) | 685 text = self._filesystem.read_binary_file(baseline_path) |
684 return text.replace("\r\n", "\n") | 686 return text.replace('\r\n', '\n') |
685 | 687 |
686 def _get_reftest_list(self, test_name): | 688 def _get_reftest_list(self, test_name): |
687 dirname = self._filesystem.join(self.layout_tests_dir(), self._filesyste
m.dirname(test_name)) | 689 dirname = self._filesystem.join(self.layout_tests_dir(), self._filesyste
m.dirname(test_name)) |
688 if dirname not in self._reftest_list: | 690 if dirname not in self._reftest_list: |
689 self._reftest_list[dirname] = Port._parse_reftest_list(self._filesys
tem, dirname) | 691 self._reftest_list[dirname] = Port._parse_reftest_list(self._filesys
tem, dirname) |
690 return self._reftest_list[dirname] | 692 return self._reftest_list[dirname] |
691 | 693 |
692 @staticmethod | 694 @staticmethod |
693 def _parse_reftest_list(filesystem, test_dirpath): | 695 def _parse_reftest_list(filesystem, test_dirpath): |
694 reftest_list_path = filesystem.join(test_dirpath, 'reftest.list') | 696 reftest_list_path = filesystem.join(test_dirpath, 'reftest.list') |
695 if not filesystem.isfile(reftest_list_path): | 697 if not filesystem.isfile(reftest_list_path): |
696 return None | 698 return None |
697 reftest_list_file = filesystem.read_text_file(reftest_list_path) | 699 reftest_list_file = filesystem.read_text_file(reftest_list_path) |
698 | 700 |
699 parsed_list = {} | 701 parsed_list = {} |
700 for line in reftest_list_file.split('\n'): | 702 for line in reftest_list_file.split('\n'): |
701 line = re.sub('#.+$', '', line) | 703 line = re.sub('#.+$', '', line) |
702 split_line = line.split() | 704 split_line = line.split() |
703 if len(split_line) == 4: | 705 if len(split_line) == 4: |
704 # FIXME: Probably one of mozilla's extensions in the reftest.lis
t format. Do we need to support this? | 706 # FIXME: Probably one of mozilla's extensions in the reftest.lis
t format. Do we need to support this? |
705 _log.warning("unsupported reftest.list line '%s' in %s" % (line,
reftest_list_path)) | 707 _log.warning("unsupported reftest.list line '%s' in %s" % (line,
reftest_list_path)) |
706 continue | 708 continue |
707 if len(split_line) < 3: | 709 if len(split_line) < 3: |
708 continue | 710 continue |
709 expectation_type, test_file, ref_file = split_line | 711 expectation_type, test_file, ref_file = split_line |
710 parsed_list.setdefault(filesystem.join(test_dirpath, test_file), [])
.append((expectation_type, filesystem.join(test_dirpath, ref_file))) | 712 parsed_list.setdefault( |
| 713 filesystem.join( |
| 714 test_dirpath, |
| 715 test_file), |
| 716 []).append( |
| 717 (expectation_type, |
| 718 filesystem.join( |
| 719 test_dirpath, |
| 720 ref_file))) |
711 return parsed_list | 721 return parsed_list |
712 | 722 |
713 def reference_files(self, test_name): | 723 def reference_files(self, test_name): |
714 """Return a list of expectation (== or !=) and filename pairs""" | 724 """Return a list of expectation (== or !=) and filename pairs""" |
715 | 725 |
716 reftest_list = self._get_reftest_list(test_name) | 726 reftest_list = self._get_reftest_list(test_name) |
717 if not reftest_list: | 727 if not reftest_list: |
718 reftest_list = [] | 728 reftest_list = [] |
719 for expectation, prefix in (('==', ''), ('!=', '-mismatch')): | 729 for expectation, prefix in (('==', ''), ('!=', '-mismatch')): |
720 for extention in Port._supported_file_extensions: | 730 for extention in Port._supported_file_extensions: |
721 path = self.expected_filename(test_name, prefix + extention) | 731 path = self.expected_filename(test_name, prefix + extention) |
722 if self._filesystem.exists(path): | 732 if self._filesystem.exists(path): |
723 reftest_list.append((expectation, path)) | 733 reftest_list.append((expectation, path)) |
724 return reftest_list | 734 return reftest_list |
725 | 735 |
726 return reftest_list.get(self._filesystem.join(self.layout_tests_dir(), t
est_name), []) # pylint: disable=E1103 | 736 return reftest_list.get(self._filesystem.join(self.layout_tests_dir(), t
est_name), []) # pylint: disable=E1103 |
727 | 737 |
728 def tests(self, paths): | 738 def tests(self, paths): |
729 """Return the list of tests found matching paths.""" | 739 """Return the list of tests found matching paths.""" |
730 tests = self._real_tests(paths) | 740 tests = self._real_tests(paths) |
731 tests.extend(self._virtual_tests(paths, self.populated_virtual_test_suit
es())) | 741 tests.extend(self._virtual_tests(paths, self.populated_virtual_test_suit
es())) |
732 return tests | 742 return tests |
733 | 743 |
734 def _real_tests(self, paths): | 744 def _real_tests(self, paths): |
735 # When collecting test cases, skip these directories | 745 # When collecting test cases, skip these directories |
736 skipped_directories = set(['.svn', '_svn', 'platform', 'resources', 'sup
port', 'script-tests', 'reference', 'reftest']) | 746 skipped_directories = set(['.svn', '_svn', 'platform', 'resources', 'sup
port', 'script-tests', 'reference', 'reftest']) |
737 files = find_files.find(self._filesystem, self.layout_tests_dir(), paths
, skipped_directories, Port.is_test_file, self.test_key) | 747 files = find_files.find( |
| 748 self._filesystem, |
| 749 self.layout_tests_dir(), |
| 750 paths, |
| 751 skipped_directories, |
| 752 Port.is_test_file, |
| 753 self.test_key) |
738 return [self.relative_test_filename(f) for f in files] | 754 return [self.relative_test_filename(f) for f in files] |
739 | 755 |
740 # When collecting test cases, we include any file with these extensions. | 756 # When collecting test cases, we include any file with these extensions. |
741 _supported_file_extensions = set(['.html', '.xml', '.xhtml', '.xht', '.pl', | 757 _supported_file_extensions = set(['.html', '.xml', '.xhtml', '.xht', '.pl', |
742 '.htm', '.php', '.svg', '.mht', '.pdf']) | 758 '.htm', '.php', '.svg', '.mht', '.pdf']) |
743 | 759 |
744 @staticmethod | 760 @staticmethod |
745 # If any changes are made here be sure to update the isUsedInReftest method
in old-run-webkit-tests as well. | 761 # If any changes are made here be sure to update the isUsedInReftest method
in old-run-webkit-tests as well. |
746 def is_reference_html_file(filesystem, dirname, filename): | 762 def is_reference_html_file(filesystem, dirname, filename): |
747 if filename.startswith('ref-') or filename.startswith('notref-'): | 763 if filename.startswith('ref-') or filename.startswith('notref-'): |
748 return True | 764 return True |
749 filename_wihout_ext, unused = filesystem.splitext(filename) | 765 filename_wihout_ext, unused = filesystem.splitext(filename) |
750 for suffix in ['-expected', '-expected-mismatch', '-ref', '-notref']: | 766 for suffix in ['-expected', '-expected-mismatch', '-ref', '-notref']: |
751 if filename_wihout_ext.endswith(suffix): | 767 if filename_wihout_ext.endswith(suffix): |
752 return True | 768 return True |
753 return False | 769 return False |
754 | 770 |
755 @staticmethod | 771 @staticmethod |
756 def _has_supported_extension(filesystem, filename): | 772 def _has_supported_extension(filesystem, filename): |
757 """Return true if filename is one of the file extensions we want to run
a test on.""" | 773 """Return true if filename is one of the file extensions we want to run
a test on.""" |
758 extension = filesystem.splitext(filename)[1] | 774 extension = filesystem.splitext(filename)[1] |
759 return extension in Port._supported_file_extensions | 775 return extension in Port._supported_file_extensions |
760 | 776 |
761 @staticmethod | 777 @staticmethod |
762 def is_test_file(filesystem, dirname, filename): | 778 def is_test_file(filesystem, dirname, filename): |
763 return Port._has_supported_extension(filesystem, filename) and not Port.
is_reference_html_file(filesystem, dirname, filename) | 779 return Port._has_supported_extension( |
| 780 filesystem, filename) and not Port.is_reference_html_file(filesystem
, dirname, filename) |
764 | 781 |
765 ALL_TEST_TYPES = ['audio', 'harness', 'pixel', 'ref', 'text', 'unknown'] | 782 ALL_TEST_TYPES = ['audio', 'harness', 'pixel', 'ref', 'text', 'unknown'] |
766 | 783 |
767 def test_type(self, test_name): | 784 def test_type(self, test_name): |
768 fs = self._filesystem | 785 fs = self._filesystem |
769 if fs.exists(self.expected_filename(test_name, '.png')): | 786 if fs.exists(self.expected_filename(test_name, '.png')): |
770 return 'pixel' | 787 return 'pixel' |
771 if fs.exists(self.expected_filename(test_name, '.wav')): | 788 if fs.exists(self.expected_filename(test_name, '.wav')): |
772 return 'audio' | 789 return 'audio' |
773 if self.reference_files(test_name): | 790 if self.reference_files(test_name): |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
898 line = line.strip() | 915 line = line.strip() |
899 line = line.rstrip('/') # Best to normalize directory names to not
include the trailing slash. | 916 line = line.rstrip('/') # Best to normalize directory names to not
include the trailing slash. |
900 if line.startswith('#') or not len(line): | 917 if line.startswith('#') or not len(line): |
901 continue | 918 continue |
902 tests_to_skip.append(line) | 919 tests_to_skip.append(line) |
903 return tests_to_skip | 920 return tests_to_skip |
904 | 921 |
905 def _expectations_from_skipped_files(self, skipped_file_paths): | 922 def _expectations_from_skipped_files(self, skipped_file_paths): |
906 tests_to_skip = [] | 923 tests_to_skip = [] |
907 for search_path in skipped_file_paths: | 924 for search_path in skipped_file_paths: |
908 filename = self._filesystem.join(self._webkit_baseline_path(search_p
ath), "Skipped") | 925 filename = self._filesystem.join(self._webkit_baseline_path(search_p
ath), 'Skipped') |
909 if not self._filesystem.exists(filename): | 926 if not self._filesystem.exists(filename): |
910 _log.debug("Skipped does not exist: %s" % filename) | 927 _log.debug('Skipped does not exist: %s' % filename) |
911 continue | 928 continue |
912 _log.debug("Using Skipped file: %s" % filename) | 929 _log.debug('Using Skipped file: %s' % filename) |
913 skipped_file_contents = self._filesystem.read_text_file(filename) | 930 skipped_file_contents = self._filesystem.read_text_file(filename) |
914 tests_to_skip.extend(self._tests_from_skipped_file_contents(skipped_
file_contents)) | 931 tests_to_skip.extend(self._tests_from_skipped_file_contents(skipped_
file_contents)) |
915 return tests_to_skip | 932 return tests_to_skip |
916 | 933 |
917 @memoized | 934 @memoized |
918 def skipped_perf_tests(self): | 935 def skipped_perf_tests(self): |
919 return self._expectations_from_skipped_files([self.perf_tests_dir()]) | 936 return self._expectations_from_skipped_files([self.perf_tests_dir()]) |
920 | 937 |
921 def skips_perf_test(self, test_name): | 938 def skips_perf_test(self, test_name): |
922 for test_or_category in self.skipped_perf_tests(): | 939 for test_or_category in self.skipped_perf_tests(): |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
992 try: | 1009 try: |
993 return self.path_from_chromium_base('webkit', self.get_option('confi
guration'), 'layout-test-results') | 1010 return self.path_from_chromium_base('webkit', self.get_option('confi
guration'), 'layout-test-results') |
994 except AssertionError: | 1011 except AssertionError: |
995 return self._build_path('layout-test-results') | 1012 return self._build_path('layout-test-results') |
996 | 1013 |
997 def setup_test_run(self): | 1014 def setup_test_run(self): |
998 """Perform port-specific work at the beginning of a test run.""" | 1015 """Perform port-specific work at the beginning of a test run.""" |
999 # Delete the disk cache if any to ensure a clean test run. | 1016 # Delete the disk cache if any to ensure a clean test run. |
1000 dump_render_tree_binary_path = self._path_to_driver() | 1017 dump_render_tree_binary_path = self._path_to_driver() |
1001 cachedir = self._filesystem.dirname(dump_render_tree_binary_path) | 1018 cachedir = self._filesystem.dirname(dump_render_tree_binary_path) |
1002 cachedir = self._filesystem.join(cachedir, "cache") | 1019 cachedir = self._filesystem.join(cachedir, 'cache') |
1003 if self._filesystem.exists(cachedir): | 1020 if self._filesystem.exists(cachedir): |
1004 self._filesystem.rmtree(cachedir) | 1021 self._filesystem.rmtree(cachedir) |
1005 | 1022 |
1006 if self._dump_reader: | 1023 if self._dump_reader: |
1007 self._filesystem.maybe_make_directory(self._dump_reader.crash_dumps_
directory()) | 1024 self._filesystem.maybe_make_directory(self._dump_reader.crash_dumps_
directory()) |
1008 | 1025 |
1009 def num_workers(self, requested_num_workers): | 1026 def num_workers(self, requested_num_workers): |
1010 """Returns the number of available workers (possibly less than the numbe
r requested).""" | 1027 """Returns the number of available workers (possibly less than the numbe
r requested).""" |
1011 return requested_num_workers | 1028 return requested_num_workers |
1012 | 1029 |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1086 def create_driver(self, worker_number, no_timeout=False): | 1103 def create_driver(self, worker_number, no_timeout=False): |
1087 """Return a newly created Driver subclass for starting/stopping the test
driver.""" | 1104 """Return a newly created Driver subclass for starting/stopping the test
driver.""" |
1088 return self._driver_class()(self, worker_number, pixel_tests=self.get_op
tion('pixel_tests'), no_timeout=no_timeout) | 1105 return self._driver_class()(self, worker_number, pixel_tests=self.get_op
tion('pixel_tests'), no_timeout=no_timeout) |
1089 | 1106 |
1090 def start_helper(self): | 1107 def start_helper(self): |
1091 """If a port needs to reconfigure graphics settings or do other | 1108 """If a port needs to reconfigure graphics settings or do other |
1092 things to ensure a known test configuration, it should override this | 1109 things to ensure a known test configuration, it should override this |
1093 method.""" | 1110 method.""" |
1094 helper_path = self._path_to_helper() | 1111 helper_path = self._path_to_helper() |
1095 if helper_path: | 1112 if helper_path: |
1096 _log.debug("Starting layout helper %s" % helper_path) | 1113 _log.debug('Starting layout helper %s' % helper_path) |
1097 # Note: Not thread safe: http://bugs.python.org/issue2320 | 1114 # Note: Not thread safe: http://bugs.python.org/issue2320 |
1098 self._helper = self._executive.popen([helper_path], | 1115 self._helper = self._executive.popen([helper_path], |
1099 stdin=self._executive.PIPE, stdout=self._executive.PIPE, stderr=
None) | 1116 stdin=self._executive.PIPE, std
out=self._executive.PIPE, stderr=None) |
1100 is_ready = self._helper.stdout.readline() | 1117 is_ready = self._helper.stdout.readline() |
1101 if not is_ready.startswith('ready'): | 1118 if not is_ready.startswith('ready'): |
1102 _log.error("layout_test_helper failed to be ready") | 1119 _log.error('layout_test_helper failed to be ready') |
1103 | 1120 |
1104 def requires_http_server(self): | 1121 def requires_http_server(self): |
1105 """Does the port require an HTTP server for running tests? This could | 1122 """Does the port require an HTTP server for running tests? This could |
1106 be the case when the tests aren't run on the host platform.""" | 1123 be the case when the tests aren't run on the host platform.""" |
1107 return False | 1124 return False |
1108 | 1125 |
1109 def start_http_server(self, additional_dirs, number_of_drivers): | 1126 def start_http_server(self, additional_dirs, number_of_drivers): |
1110 """Start a web server. Raise an error if it can't start or is already ru
nning. | 1127 """Start a web server. Raise an error if it can't start or is already ru
nning. |
1111 | 1128 |
1112 Ports can stub this out if they don't need a web server to be running.""
" | 1129 Ports can stub this out if they don't need a web server to be running.""
" |
(...skipping 19 matching lines...) Expand all Loading... |
1132 # Apache < 2.4 on win32 does not support IPv6, nor does cygwin apache. | 1149 # Apache < 2.4 on win32 does not support IPv6, nor does cygwin apache. |
1133 if self.host.platform.is_cygwin() or self.host.platform.is_win(): | 1150 if self.host.platform.is_cygwin() or self.host.platform.is_win(): |
1134 return False | 1151 return False |
1135 return True | 1152 return True |
1136 | 1153 |
1137 def stop_helper(self): | 1154 def stop_helper(self): |
1138 """Shut down the test helper if it is running. Do nothing if | 1155 """Shut down the test helper if it is running. Do nothing if |
1139 it isn't, or it isn't available. If a port overrides start_helper() | 1156 it isn't, or it isn't available. If a port overrides start_helper() |
1140 it must override this routine as well.""" | 1157 it must override this routine as well.""" |
1141 if self._helper: | 1158 if self._helper: |
1142 _log.debug("Stopping layout test helper") | 1159 _log.debug('Stopping layout test helper') |
1143 try: | 1160 try: |
1144 self._helper.stdin.write("x\n") | 1161 self._helper.stdin.write('x\n') |
1145 self._helper.stdin.close() | 1162 self._helper.stdin.close() |
1146 self._helper.wait() | 1163 self._helper.wait() |
1147 except IOError, e: | 1164 except IOError as e: |
1148 pass | 1165 pass |
1149 finally: | 1166 finally: |
1150 self._helper = None | 1167 self._helper = None |
1151 | 1168 |
1152 def stop_http_server(self): | 1169 def stop_http_server(self): |
1153 """Shut down the http server if it is running. Do nothing if it isn't.""
" | 1170 """Shut down the http server if it is running. Do nothing if it isn't.""
" |
1154 if self._http_server: | 1171 if self._http_server: |
1155 self._http_server.stop() | 1172 self._http_server.stop() |
1156 self._http_server = None | 1173 self._http_server = None |
1157 | 1174 |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1287 """Returns a list of (repository_name, repository_path) tuples of its de
pending code base.""" | 1304 """Returns a list of (repository_name, repository_path) tuples of its de
pending code base.""" |
1288 return [('blink', self.layout_tests_dir()), | 1305 return [('blink', self.layout_tests_dir()), |
1289 ('chromium', self.path_from_chromium_base('build'))] | 1306 ('chromium', self.path_from_chromium_base('build'))] |
1290 | 1307 |
1291 _WDIFF_DEL = '##WDIFF_DEL##' | 1308 _WDIFF_DEL = '##WDIFF_DEL##' |
1292 _WDIFF_ADD = '##WDIFF_ADD##' | 1309 _WDIFF_ADD = '##WDIFF_ADD##' |
1293 _WDIFF_END = '##WDIFF_END##' | 1310 _WDIFF_END = '##WDIFF_END##' |
1294 | 1311 |
1295 def _format_wdiff_output_as_html(self, wdiff): | 1312 def _format_wdiff_output_as_html(self, wdiff): |
1296 wdiff = cgi.escape(wdiff) | 1313 wdiff = cgi.escape(wdiff) |
1297 wdiff = wdiff.replace(self._WDIFF_DEL, "<span class=del>") | 1314 wdiff = wdiff.replace(self._WDIFF_DEL, '<span class=del>') |
1298 wdiff = wdiff.replace(self._WDIFF_ADD, "<span class=add>") | 1315 wdiff = wdiff.replace(self._WDIFF_ADD, '<span class=add>') |
1299 wdiff = wdiff.replace(self._WDIFF_END, "</span>") | 1316 wdiff = wdiff.replace(self._WDIFF_END, '</span>') |
1300 html = "<head><style>.del { background: #faa; } " | 1317 html = '<head><style>.del { background: #faa; } ' |
1301 html += ".add { background: #afa; }</style></head>" | 1318 html += '.add { background: #afa; }</style></head>' |
1302 html += "<pre>%s</pre>" % wdiff | 1319 html += '<pre>%s</pre>' % wdiff |
1303 return html | 1320 return html |
1304 | 1321 |
1305 def _wdiff_command(self, actual_filename, expected_filename): | 1322 def _wdiff_command(self, actual_filename, expected_filename): |
1306 executable = self._path_to_wdiff() | 1323 executable = self._path_to_wdiff() |
1307 return [executable, | 1324 return [executable, |
1308 "--start-delete=%s" % self._WDIFF_DEL, | 1325 '--start-delete=%s' % self._WDIFF_DEL, |
1309 "--end-delete=%s" % self._WDIFF_END, | 1326 '--end-delete=%s' % self._WDIFF_END, |
1310 "--start-insert=%s" % self._WDIFF_ADD, | 1327 '--start-insert=%s' % self._WDIFF_ADD, |
1311 "--end-insert=%s" % self._WDIFF_END, | 1328 '--end-insert=%s' % self._WDIFF_END, |
1312 actual_filename, | 1329 actual_filename, |
1313 expected_filename] | 1330 expected_filename] |
1314 | 1331 |
1315 @staticmethod | 1332 @staticmethod |
1316 def _handle_wdiff_error(script_error): | 1333 def _handle_wdiff_error(script_error): |
1317 # Exit 1 means the files differed, any other exit code is an error. | 1334 # Exit 1 means the files differed, any other exit code is an error. |
1318 if script_error.exit_code != 1: | 1335 if script_error.exit_code != 1: |
1319 raise script_error | 1336 raise script_error |
1320 | 1337 |
1321 def _run_wdiff(self, actual_filename, expected_filename): | 1338 def _run_wdiff(self, actual_filename, expected_filename): |
1322 """Runs wdiff and may throw exceptions. | 1339 """Runs wdiff and may throw exceptions. |
1323 This is mostly a hook for unit testing.""" | 1340 This is mostly a hook for unit testing.""" |
1324 # Diffs are treated as binary as they may include multiple files | 1341 # Diffs are treated as binary as they may include multiple files |
1325 # with conflicting encodings. Thus we do not decode the output. | 1342 # with conflicting encodings. Thus we do not decode the output. |
1326 command = self._wdiff_command(actual_filename, expected_filename) | 1343 command = self._wdiff_command(actual_filename, expected_filename) |
1327 wdiff = self._executive.run_command(command, decode_output=False, | 1344 wdiff = self._executive.run_command(command, decode_output=False, |
1328 error_handler=self._handle_wdiff_error) | 1345 error_handler=self._handle_wdiff_err
or) |
1329 return self._format_wdiff_output_as_html(wdiff) | 1346 return self._format_wdiff_output_as_html(wdiff) |
1330 | 1347 |
1331 _wdiff_error_html = "Failed to run wdiff, see error log." | 1348 _wdiff_error_html = 'Failed to run wdiff, see error log.' |
1332 | 1349 |
1333 def wdiff_text(self, actual_filename, expected_filename): | 1350 def wdiff_text(self, actual_filename, expected_filename): |
1334 """Returns a string of HTML indicating the word-level diff of the | 1351 """Returns a string of HTML indicating the word-level diff of the |
1335 contents of the two filenames. Returns an empty string if word-level | 1352 contents of the two filenames. Returns an empty string if word-level |
1336 diffing isn't available.""" | 1353 diffing isn't available.""" |
1337 if not self.wdiff_available(): | 1354 if not self.wdiff_available(): |
1338 return "" | 1355 return '' |
1339 try: | 1356 try: |
1340 # It's possible to raise a ScriptError we pass wdiff invalid paths. | 1357 # It's possible to raise a ScriptError we pass wdiff invalid paths. |
1341 return self._run_wdiff(actual_filename, expected_filename) | 1358 return self._run_wdiff(actual_filename, expected_filename) |
1342 except OSError as e: | 1359 except OSError as e: |
1343 if e.errno in [errno.ENOENT, errno.EACCES, errno.ECHILD]: | 1360 if e.errno in [errno.ENOENT, errno.EACCES, errno.ECHILD]: |
1344 # Silently ignore cases where wdiff is missing. | 1361 # Silently ignore cases where wdiff is missing. |
1345 self._wdiff_available = False | 1362 self._wdiff_available = False |
1346 return "" | 1363 return '' |
1347 raise | 1364 raise |
1348 except ScriptError as e: | 1365 except ScriptError as e: |
1349 _log.error("Failed to run wdiff: %s" % e) | 1366 _log.error('Failed to run wdiff: %s' % e) |
1350 self._wdiff_available = False | 1367 self._wdiff_available = False |
1351 return self._wdiff_error_html | 1368 return self._wdiff_error_html |
1352 | 1369 |
1353 # This is a class variable so we can test error output easily. | 1370 # This is a class variable so we can test error output easily. |
1354 _pretty_patch_error_html = "Failed to run PrettyPatch, see error log." | 1371 _pretty_patch_error_html = 'Failed to run PrettyPatch, see error log.' |
1355 | 1372 |
1356 def pretty_patch_text(self, diff_path): | 1373 def pretty_patch_text(self, diff_path): |
1357 if self._pretty_patch_available is None: | 1374 if self._pretty_patch_available is None: |
1358 self._pretty_patch_available = self.check_pretty_patch(logging=False
) | 1375 self._pretty_patch_available = self.check_pretty_patch(logging=False
) |
1359 if not self._pretty_patch_available: | 1376 if not self._pretty_patch_available: |
1360 return self._pretty_patch_error_html | 1377 return self._pretty_patch_error_html |
1361 command = ("ruby", "-I", self._filesystem.dirname(self._pretty_patch_pat
h), | 1378 command = ('ruby', '-I', self._filesystem.dirname(self._pretty_patch_pat
h), |
1362 self._pretty_patch_path, diff_path) | 1379 self._pretty_patch_path, diff_path) |
1363 try: | 1380 try: |
1364 # Diffs are treated as binary (we pass decode_output=False) as they | 1381 # Diffs are treated as binary (we pass decode_output=False) as they |
1365 # may contain multiple files of conflicting encodings. | 1382 # may contain multiple files of conflicting encodings. |
1366 return self._executive.run_command(command, decode_output=False) | 1383 return self._executive.run_command(command, decode_output=False) |
1367 except OSError, e: | 1384 except OSError as e: |
1368 # If the system is missing ruby log the error and stop trying. | 1385 # If the system is missing ruby log the error and stop trying. |
1369 self._pretty_patch_available = False | 1386 self._pretty_patch_available = False |
1370 _log.error("Failed to run PrettyPatch (%s): %s" % (command, e)) | 1387 _log.error('Failed to run PrettyPatch (%s): %s' % (command, e)) |
1371 return self._pretty_patch_error_html | 1388 return self._pretty_patch_error_html |
1372 except ScriptError, e: | 1389 except ScriptError as e: |
1373 # If ruby failed to run for some reason, log the command | 1390 # If ruby failed to run for some reason, log the command |
1374 # output and stop trying. | 1391 # output and stop trying. |
1375 self._pretty_patch_available = False | 1392 self._pretty_patch_available = False |
1376 _log.error("Failed to run PrettyPatch (%s):\n%s" % (command, e.messa
ge_with_output())) | 1393 _log.error('Failed to run PrettyPatch (%s):\n%s' % (command, e.messa
ge_with_output())) |
1377 return self._pretty_patch_error_html | 1394 return self._pretty_patch_error_html |
1378 | 1395 |
1379 def default_configuration(self): | 1396 def default_configuration(self): |
1380 return self._config.default_configuration() | 1397 return self._config.default_configuration() |
1381 | 1398 |
1382 def clobber_old_port_specific_results(self): | 1399 def clobber_old_port_specific_results(self): |
1383 pass | 1400 pass |
1384 | 1401 |
1385 # FIXME: This does not belong on the port object. | 1402 # FIXME: This does not belong on the port object. |
1386 @memoized | 1403 @memoized |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1427 # We pass sys_platform into this method to make it easy to unit test. | 1444 # We pass sys_platform into this method to make it easy to unit test. |
1428 def _apache_config_file_name_for_platform(self, sys_platform): | 1445 def _apache_config_file_name_for_platform(self, sys_platform): |
1429 if sys_platform == 'cygwin': | 1446 if sys_platform == 'cygwin': |
1430 return 'cygwin-httpd.conf' # CYGWIN is the only platform to still u
se Apache 1.3. | 1447 return 'cygwin-httpd.conf' # CYGWIN is the only platform to still u
se Apache 1.3. |
1431 if sys_platform.startswith('linux'): | 1448 if sys_platform.startswith('linux'): |
1432 if self._is_redhat_based(): | 1449 if self._is_redhat_based(): |
1433 return 'fedora-httpd-' + self._apache_version() + '.conf' | 1450 return 'fedora-httpd-' + self._apache_version() + '.conf' |
1434 if self._is_debian_based(): | 1451 if self._is_debian_based(): |
1435 return 'debian-httpd-' + self._apache_version() + '.conf' | 1452 return 'debian-httpd-' + self._apache_version() + '.conf' |
1436 # All platforms use apache2 except for CYGWIN (and Mac OS X Tiger and pr
ior, which we no longer support). | 1453 # All platforms use apache2 except for CYGWIN (and Mac OS X Tiger and pr
ior, which we no longer support). |
1437 return "apache2-httpd.conf" | 1454 return 'apache2-httpd.conf' |
1438 | 1455 |
1439 def _path_to_driver(self, configuration=None): | 1456 def _path_to_driver(self, configuration=None): |
1440 """Returns the full path to the test driver.""" | 1457 """Returns the full path to the test driver.""" |
1441 return self._build_path(self.driver_name()) | 1458 return self._build_path(self.driver_name()) |
1442 | 1459 |
1443 def _path_to_webcore_library(self): | 1460 def _path_to_webcore_library(self): |
1444 """Returns the full path to a built copy of WebCore.""" | 1461 """Returns the full path to a built copy of WebCore.""" |
1445 return None | 1462 return None |
1446 | 1463 |
1447 def _path_to_helper(self): | 1464 def _path_to_helper(self): |
1448 """Returns the full path to the layout_test_helper binary, which | 1465 """Returns the full path to the layout_test_helper binary, which |
1449 is used to help configure the system for the test run, or None | 1466 is used to help configure the system for the test run, or None |
1450 if no helper is needed. | 1467 if no helper is needed. |
1451 | 1468 |
1452 This is likely only used by start/stop_helper().""" | 1469 This is likely only used by start/stop_helper().""" |
1453 return None | 1470 return None |
1454 | 1471 |
1455 def _path_to_image_diff(self): | 1472 def _path_to_image_diff(self): |
1456 """Returns the full path to the image_diff binary, or None if it is not
available. | 1473 """Returns the full path to the image_diff binary, or None if it is not
available. |
1457 | 1474 |
1458 This is likely used only by diff_image()""" | 1475 This is likely used only by diff_image()""" |
1459 return self._build_path('image_diff') | 1476 return self._build_path('image_diff') |
1460 | 1477 |
1461 @memoized | 1478 @memoized |
1462 def _path_to_wdiff(self): | 1479 def _path_to_wdiff(self): |
1463 """Returns the full path to the wdiff binary, or None if it is not avail
able. | 1480 """Returns the full path to the wdiff binary, or None if it is not avail
able. |
1464 | 1481 |
1465 This is likely used only by wdiff_text()""" | 1482 This is likely used only by wdiff_text()""" |
1466 for path in ("/usr/bin/wdiff", "/usr/bin/dwdiff"): | 1483 for path in ('/usr/bin/wdiff', '/usr/bin/dwdiff'): |
1467 if self._filesystem.exists(path): | 1484 if self._filesystem.exists(path): |
1468 return path | 1485 return path |
1469 return None | 1486 return None |
1470 | 1487 |
1471 def _webkit_baseline_path(self, platform): | 1488 def _webkit_baseline_path(self, platform): |
1472 """Return the full path to the top of the baseline tree for a | 1489 """Return the full path to the top of the baseline tree for a |
1473 given platform.""" | 1490 given platform.""" |
1474 return self._filesystem.join(self.layout_tests_dir(), 'platform', platfo
rm) | 1491 return self._filesystem.join(self.layout_tests_dir(), 'platform', platfo
rm) |
1475 | 1492 |
1476 def _driver_class(self): | 1493 def _driver_class(self): |
(...skipping 11 matching lines...) Expand all Loading... |
1488 | 1505 |
1489 def _get_crash_log(self, name, pid, stdout, stderr, newer_than): | 1506 def _get_crash_log(self, name, pid, stdout, stderr, newer_than): |
1490 if self._output_contains_sanitizer_messages(stderr): | 1507 if self._output_contains_sanitizer_messages(stderr): |
1491 # Running the symbolizer script can take a lot of memory, so we need
to | 1508 # Running the symbolizer script can take a lot of memory, so we need
to |
1492 # serialize access to it across all the concurrently running drivers
. | 1509 # serialize access to it across all the concurrently running drivers
. |
1493 | 1510 |
1494 # FIXME: investigate using LLVM_SYMBOLIZER_PATH here to reduce the o
verhead. | 1511 # FIXME: investigate using LLVM_SYMBOLIZER_PATH here to reduce the o
verhead. |
1495 sanitizer_filter_path = self.path_from_chromium_base('tools', 'valgr
ind', 'asan', 'asan_symbolize.py') | 1512 sanitizer_filter_path = self.path_from_chromium_base('tools', 'valgr
ind', 'asan', 'asan_symbolize.py') |
1496 sanitizer_strip_path_prefix = 'Release/../../' | 1513 sanitizer_strip_path_prefix = 'Release/../../' |
1497 if self._filesystem.exists(sanitizer_filter_path): | 1514 if self._filesystem.exists(sanitizer_filter_path): |
1498 stderr = self._executive.run_command(['flock', sys.executable, s
anitizer_filter_path, sanitizer_strip_path_prefix], input=stderr, decode_output=
False) | 1515 stderr = self._executive.run_command(['flock', |
| 1516 sys.executable, |
| 1517 sanitizer_filter_path, |
| 1518 sanitizer_strip_path_prefi
x], |
| 1519 input=stderr, |
| 1520 decode_output=False) |
1499 | 1521 |
1500 name_str = name or '<unknown process name>' | 1522 name_str = name or '<unknown process name>' |
1501 pid_str = str(pid or '<unknown>') | 1523 pid_str = str(pid or '<unknown>') |
1502 stdout_lines = (stdout or '<empty>').decode('utf8', 'replace').splitline
s() | 1524 stdout_lines = (stdout or '<empty>').decode('utf8', 'replace').splitline
s() |
1503 stderr_lines = (stderr or '<empty>').decode('utf8', 'replace').splitline
s() | 1525 stderr_lines = (stderr or '<empty>').decode('utf8', 'replace').splitline
s() |
1504 return (stderr, 'crash log for %s (pid %s):\n%s\n%s\n' % (name_str, pid_
str, | 1526 return (stderr, 'crash log for %s (pid %s):\n%s\n%s\n' % (name_str, pid_
str, |
1505 '\n'.join(('STDOUT: ' + l) for l in stdout_lines), | 1527 '\n'.join(('ST
DOUT: ' + l) for l in stdout_lines), |
1506 '\n'.join(('STDERR: ' + l) for l in stderr_lines))) | 1528 '\n'.join(('ST
DERR: ' + l) for l in stderr_lines))) |
1507 | 1529 |
1508 def look_for_new_crash_logs(self, crashed_processes, start_time): | 1530 def look_for_new_crash_logs(self, crashed_processes, start_time): |
1509 pass | 1531 pass |
1510 | 1532 |
1511 def look_for_new_samples(self, unresponsive_processes, start_time): | 1533 def look_for_new_samples(self, unresponsive_processes, start_time): |
1512 pass | 1534 pass |
1513 | 1535 |
1514 def sample_process(self, name, pid): | 1536 def sample_process(self, name, pid): |
1515 pass | 1537 pass |
1516 | 1538 |
1517 def physical_test_suites(self): | 1539 def physical_test_suites(self): |
1518 return [ | 1540 return [ |
1519 # For example, to turn on force-compositing-mode in the svg/ directo
ry: | 1541 # For example, to turn on force-compositing-mode in the svg/ directo
ry: |
1520 # PhysicalTestSuite('svg', | 1542 # PhysicalTestSuite('svg', |
1521 # ['--force-compositing-mode']), | 1543 # ['--force-compositing-mode']), |
1522 ] | 1544 ] |
1523 | 1545 |
1524 def virtual_test_suites(self): | 1546 def virtual_test_suites(self): |
1525 return [ | 1547 return [ |
1526 VirtualTestSuite('gpu', | 1548 VirtualTestSuite('gpu', |
1527 'fast/canvas', | 1549 'fast/canvas', |
1528 ['--enable-accelerated-2d-canvas']), | 1550 ['--enable-accelerated-2d-canvas']), |
1529 VirtualTestSuite('gpu', | 1551 VirtualTestSuite('gpu', |
1530 'canvas/philip', | 1552 'canvas/philip', |
1531 ['--enable-accelerated-2d-canvas']), | 1553 ['--enable-accelerated-2d-canvas']), |
1532 VirtualTestSuite('threaded', | 1554 VirtualTestSuite('threaded', |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1673 path = self._path_to_webcore_library() | 1695 path = self._path_to_webcore_library() |
1674 if path: | 1696 if path: |
1675 return [path] | 1697 return [path] |
1676 return [] | 1698 return [] |
1677 | 1699 |
1678 def _symbols_string(self): | 1700 def _symbols_string(self): |
1679 symbols = '' | 1701 symbols = '' |
1680 for path_to_module in self._modules_to_search_for_symbols(): | 1702 for path_to_module in self._modules_to_search_for_symbols(): |
1681 try: | 1703 try: |
1682 symbols += self._executive.run_command(['nm', path_to_module], e
rror_handler=self._executive.ignore_error) | 1704 symbols += self._executive.run_command(['nm', path_to_module], e
rror_handler=self._executive.ignore_error) |
1683 except OSError, e: | 1705 except OSError as e: |
1684 _log.warn("Failed to run nm: %s. Can't determine supported feat
ures correctly." % e) | 1706 _log.warn("Failed to run nm: %s. Can't determine supported feat
ures correctly." % e) |
1685 return symbols | 1707 return symbols |
1686 | 1708 |
1687 # Ports which use compile-time feature detection should define this method a
nd return | 1709 # Ports which use compile-time feature detection should define this method a
nd return |
1688 # a dictionary mapping from symbol substrings to possibly disabled test dire
ctories. | 1710 # a dictionary mapping from symbol substrings to possibly disabled test dire
ctories. |
1689 # When the symbol substrings are not matched, the directories will be skippe
d. | 1711 # When the symbol substrings are not matched, the directories will be skippe
d. |
1690 # If ports don't ever enable certain features, then those directories can ju
st be | 1712 # If ports don't ever enable certain features, then those directories can ju
st be |
1691 # in the Skipped list instead of compile-time-checked here. | 1713 # in the Skipped list instead of compile-time-checked here. |
1692 def _missing_symbol_to_skipped_tests(self): | 1714 def _missing_symbol_to_skipped_tests(self): |
1693 if self.PORT_HAS_AUDIO_CODECS_BUILT_IN: | 1715 if self.PORT_HAS_AUDIO_CODECS_BUILT_IN: |
1694 return {} | 1716 return {} |
1695 else: | 1717 else: |
1696 return { | 1718 return { |
1697 "ff_mp3_decoder": ["webaudio/codec-tests/mp3"], | 1719 'ff_mp3_decoder': ['webaudio/codec-tests/mp3'], |
1698 "ff_aac_decoder": ["webaudio/codec-tests/aac"], | 1720 'ff_aac_decoder': ['webaudio/codec-tests/aac'], |
1699 } | 1721 } |
1700 | 1722 |
1701 def _has_test_in_directories(self, directory_lists, test_list): | 1723 def _has_test_in_directories(self, directory_lists, test_list): |
1702 if not test_list: | 1724 if not test_list: |
1703 return False | 1725 return False |
1704 | 1726 |
1705 directories = itertools.chain.from_iterable(directory_lists) | 1727 directories = itertools.chain.from_iterable(directory_lists) |
1706 for directory, test in itertools.product(directories, test_list): | 1728 for directory, test in itertools.product(directories, test_list): |
1707 if test.startswith(directory): | 1729 if test.startswith(directory): |
1708 return True | 1730 return True |
1709 return False | 1731 return False |
1710 | 1732 |
1711 def _skipped_tests_for_unsupported_features(self, test_list): | 1733 def _skipped_tests_for_unsupported_features(self, test_list): |
1712 # Only check the symbols of there are tests in the test_list that might
get skipped. | 1734 # Only check the symbols of there are tests in the test_list that might
get skipped. |
1713 # This is a performance optimization to avoid the calling nm. | 1735 # This is a performance optimization to avoid the calling nm. |
1714 # Runtime feature detection not supported, fallback to static detection: | 1736 # Runtime feature detection not supported, fallback to static detection: |
1715 # Disable any tests for symbols missing from the executable or libraries
. | 1737 # Disable any tests for symbols missing from the executable or libraries
. |
1716 if self._has_test_in_directories(self._missing_symbol_to_skipped_tests()
.values(), test_list): | 1738 if self._has_test_in_directories(self._missing_symbol_to_skipped_tests()
.values(), test_list): |
1717 symbols_string = self._symbols_string() | 1739 symbols_string = self._symbols_string() |
1718 if symbols_string is not None: | 1740 if symbols_string is not None: |
1719 return reduce(operator.add, [directories for symbol_substring, d
irectories in self._missing_symbol_to_skipped_tests().items() if symbol_substrin
g not in symbols_string], []) | 1741 return reduce(operator.add, [directories for symbol_substring, d
irectories in self._missing_symbol_to_skipped_tests( |
| 1742 ).items() if symbol_substring not in symbols_string], []) |
1720 return [] | 1743 return [] |
1721 | 1744 |
1722 def _convert_path(self, path): | 1745 def _convert_path(self, path): |
1723 """Handles filename conversion for subprocess command line args.""" | 1746 """Handles filename conversion for subprocess command line args.""" |
1724 # See note above in diff_image() for why we need this. | 1747 # See note above in diff_image() for why we need this. |
1725 if sys.platform == 'cygwin': | 1748 if sys.platform == 'cygwin': |
1726 return cygpath(path) | 1749 return cygpath(path) |
1727 return path | 1750 return path |
1728 | 1751 |
1729 def _build_path(self, *comps): | 1752 def _build_path(self, *comps): |
1730 return self._build_path_with_configuration(None, *comps) | 1753 return self._build_path_with_configuration(None, *comps) |
1731 | 1754 |
1732 def _build_path_with_configuration(self, configuration, *comps): | 1755 def _build_path_with_configuration(self, configuration, *comps): |
1733 # Note that we don't do the option caching that the | 1756 # Note that we don't do the option caching that the |
1734 # base class does, because finding the right directory is relatively | 1757 # base class does, because finding the right directory is relatively |
1735 # fast. | 1758 # fast. |
1736 configuration = configuration or self.get_option('configuration') | 1759 configuration = configuration or self.get_option('configuration') |
1737 return self._static_build_path(self._filesystem, self.get_option('build_
directory'), | 1760 return self._static_build_path(self._filesystem, self.get_option('build_
directory'), |
1738 self.path_from_chromium_base(), configuration, comps) | 1761 self.path_from_chromium_base(), configura
tion, comps) |
1739 | 1762 |
1740 def _check_driver_build_up_to_date(self, configuration): | 1763 def _check_driver_build_up_to_date(self, configuration): |
1741 if configuration in ('Debug', 'Release'): | 1764 if configuration in ('Debug', 'Release'): |
1742 try: | 1765 try: |
1743 debug_path = self._path_to_driver('Debug') | 1766 debug_path = self._path_to_driver('Debug') |
1744 release_path = self._path_to_driver('Release') | 1767 release_path = self._path_to_driver('Release') |
1745 | 1768 |
1746 debug_mtime = self._filesystem.mtime(debug_path) | 1769 debug_mtime = self._filesystem.mtime(debug_path) |
1747 release_mtime = self._filesystem.mtime(release_path) | 1770 release_mtime = self._filesystem.mtime(release_path) |
1748 | 1771 |
1749 if (debug_mtime > release_mtime and configuration == 'Release' o
r | 1772 if (debug_mtime > release_mtime and configuration == 'Release' o
r |
1750 release_mtime > debug_mtime and configuration == 'Debug'): | 1773 release_mtime > debug_mtime and configuration == 'Debug'
): |
1751 most_recent_binary = 'Release' if configuration == 'Debug' e
lse 'Debug' | 1774 most_recent_binary = 'Release' if configuration == 'Debug' e
lse 'Debug' |
1752 _log.warning('You are running the %s binary. However the %s
binary appears to be more recent. ' | 1775 _log.warning('You are running the %s binary. However the %s
binary appears to be more recent. ' |
1753 'Please pass --%s.', configuration, most_recent
_binary, most_recent_binary.lower()) | 1776 'Please pass --%s.', configuration, most_recent
_binary, most_recent_binary.lower()) |
1754 _log.warning('') | 1777 _log.warning('') |
1755 # This will fail if we don't have both a debug and release binary. | 1778 # This will fail if we don't have both a debug and release binary. |
1756 # That's fine because, in this case, we must already be running the | 1779 # That's fine because, in this case, we must already be running the |
1757 # most up-to-date one. | 1780 # most up-to-date one. |
1758 except OSError: | 1781 except OSError: |
1759 pass | 1782 pass |
1760 return True | 1783 return True |
1761 | 1784 |
1762 def _chromium_baseline_path(self, platform): | 1785 def _chromium_baseline_path(self, platform): |
1763 if platform is None: | 1786 if platform is None: |
1764 platform = self.name() | 1787 platform = self.name() |
1765 return self.path_from_webkit_base('LayoutTests', 'platform', platform) | 1788 return self.path_from_webkit_base('LayoutTests', 'platform', platform) |
1766 | 1789 |
| 1790 |
1767 class VirtualTestSuite(object): | 1791 class VirtualTestSuite(object): |
| 1792 |
1768 def __init__(self, name, base, args, use_legacy_naming=False, tests=None): | 1793 def __init__(self, name, base, args, use_legacy_naming=False, tests=None): |
1769 if use_legacy_naming: | 1794 if use_legacy_naming: |
1770 self.name = 'virtual/' + name | 1795 self.name = 'virtual/' + name |
1771 else: | 1796 else: |
1772 if name.find('/') != -1: | 1797 if name.find('/') != -1: |
1773 _log.error("Virtual test suites names cannot contain /'s: %s" %
name) | 1798 _log.error("Virtual test suites names cannot contain /'s: %s" %
name) |
1774 return | 1799 return |
1775 self.name = 'virtual/' + name + '/' + base | 1800 self.name = 'virtual/' + name + '/' + base |
1776 self.base = base | 1801 self.base = base |
1777 self.args = args | 1802 self.args = args |
1778 self.tests = tests or set() | 1803 self.tests = tests or set() |
1779 | 1804 |
1780 def __repr__(self): | 1805 def __repr__(self): |
1781 return "VirtualTestSuite('%s', '%s', %s)" % (self.name, self.base, self.
args) | 1806 return "VirtualTestSuite('%s', '%s', %s)" % (self.name, self.base, self.
args) |
1782 | 1807 |
1783 | 1808 |
1784 class PhysicalTestSuite(object): | 1809 class PhysicalTestSuite(object): |
| 1810 |
1785 def __init__(self, base, args): | 1811 def __init__(self, base, args): |
1786 self.name = base | 1812 self.name = base |
1787 self.base = base | 1813 self.base = base |
1788 self.args = args | 1814 self.args = args |
1789 self.tests = set() | 1815 self.tests = set() |
1790 | 1816 |
1791 def __repr__(self): | 1817 def __repr__(self): |
1792 return "PhysicalTestSuite('%s', '%s', %s)" % (self.name, self.base, self
.args) | 1818 return "PhysicalTestSuite('%s', '%s', %s)" % (self.name, self.base, self
.args) |
OLD | NEW |