| 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 22 matching lines...) Expand all Loading... |
| 33 import difflib | 33 import difflib |
| 34 import errno | 34 import errno |
| 35 import itertools | 35 import itertools |
| 36 import json | 36 import json |
| 37 import logging | 37 import logging |
| 38 import os | 38 import os |
| 39 import operator | 39 import operator |
| 40 import optparse | 40 import optparse |
| 41 import re | 41 import re |
| 42 import sys | 42 import sys |
| 43 from functools import reduce |
| 43 | 44 |
| 44 try: | 45 try: |
| 45 from collections import OrderedDict | 46 from collections import OrderedDict |
| 46 except ImportError: | 47 except ImportError: |
| 47 # Needed for Python < 2.7 | 48 # Needed for Python < 2.7 |
| 48 from webkitpy.thirdparty.ordered_dict import OrderedDict | 49 from webkitpy.thirdparty.ordered_dict import OrderedDict |
| 49 | 50 |
| 50 | 51 |
| 51 from webkitpy.common import find_files | 52 from webkitpy.common import find_files |
| 52 from webkitpy.common import read_checksum_from_png | 53 from webkitpy.common import read_checksum_from_png |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 if not hasattr(options, 'configuration') or not options.configuration: | 209 if not hasattr(options, 'configuration') or not options.configuration: |
| 209 self.set_option_default('configuration', self.default_configuration(
)) | 210 self.set_option_default('configuration', self.default_configuration(
)) |
| 210 if not hasattr(options, 'target') or not options.target: | 211 if not hasattr(options, 'target') or not options.target: |
| 211 self.set_option_default('target', self._options.configuration) | 212 self.set_option_default('target', self._options.configuration) |
| 212 self._test_configuration = None | 213 self._test_configuration = None |
| 213 self._reftest_list = {} | 214 self._reftest_list = {} |
| 214 self._results_directory = None | 215 self._results_directory = None |
| 215 self._virtual_test_suites = None | 216 self._virtual_test_suites = None |
| 216 | 217 |
| 217 def __str__(self): | 218 def __str__(self): |
| 218 return "Port{name=%s, version=%s, architecture=%s, test_configuration=%s
}" % (self._name, self._version, self._architecture, self._test_configuration) | 219 return "Port{name=%s, version=%s, architecture=%s, test_configuration=%s
}" % ( |
| 220 self._name, self._version, self._architecture, self._test_configurat
ion) |
| 219 | 221 |
| 220 def buildbot_archives_baselines(self): | 222 def buildbot_archives_baselines(self): |
| 221 return True | 223 return True |
| 222 | 224 |
| 223 def additional_driver_flag(self): | 225 def additional_driver_flag(self): |
| 224 if self.driver_name() == self.CONTENT_SHELL_NAME: | 226 if self.driver_name() == self.CONTENT_SHELL_NAME: |
| 225 return ['--run-layout-test'] | 227 return ['--run-layout-test'] |
| 226 return [] | 228 return [] |
| 227 | 229 |
| 228 def supports_per_test_timeout(self): | 230 def supports_per_test_timeout(self): |
| (...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 412 image_diff_path = self._path_to_image_diff() | 414 image_diff_path = self._path_to_image_diff() |
| 413 if not self._filesystem.exists(image_diff_path): | 415 if not self._filesystem.exists(image_diff_path): |
| 414 _log.error("image_diff was not found at %s" % image_diff_path) | 416 _log.error("image_diff was not found at %s" % image_diff_path) |
| 415 return False | 417 return False |
| 416 return True | 418 return True |
| 417 | 419 |
| 418 def check_pretty_patch(self, logging=True): | 420 def check_pretty_patch(self, logging=True): |
| 419 """Checks whether we can use the PrettyPatch ruby script.""" | 421 """Checks whether we can use the PrettyPatch ruby script.""" |
| 420 try: | 422 try: |
| 421 _ = self._executive.run_command(['ruby', '--version']) | 423 _ = self._executive.run_command(['ruby', '--version']) |
| 422 except OSError, e: | 424 except OSError as e: |
| 423 if e.errno in [errno.ENOENT, errno.EACCES, errno.ECHILD]: | 425 if e.errno in [errno.ENOENT, errno.EACCES, errno.ECHILD]: |
| 424 if logging: | 426 if logging: |
| 425 _log.warning("Ruby is not installed; can't generate pretty p
atches.") | 427 _log.warning("Ruby is not installed; can't generate pretty p
atches.") |
| 426 _log.warning('') | 428 _log.warning('') |
| 427 return False | 429 return False |
| 428 | 430 |
| 429 if not self._filesystem.exists(self._pretty_patch_path): | 431 if not self._filesystem.exists(self._pretty_patch_path): |
| 430 if logging: | 432 if logging: |
| 431 _log.warning("Unable to find %s; can't generate pretty patches."
% self._pretty_patch_path) | 433 _log.warning("Unable to find %s; can't generate pretty patches."
% self._pretty_patch_path) |
| 432 _log.warning('') | 434 _log.warning('') |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 err_str = None | 514 err_str = None |
| 513 try: | 515 try: |
| 514 exit_code = self._executive.run_command(command, return_exit_code=Tr
ue) | 516 exit_code = self._executive.run_command(command, return_exit_code=Tr
ue) |
| 515 if exit_code == 0: | 517 if exit_code == 0: |
| 516 # The images are the same. | 518 # The images are the same. |
| 517 result = None | 519 result = None |
| 518 elif exit_code == 1: | 520 elif exit_code == 1: |
| 519 result = self._filesystem.read_binary_file(native_diff_filename) | 521 result = self._filesystem.read_binary_file(native_diff_filename) |
| 520 else: | 522 else: |
| 521 err_str = "Image diff returned an exit code of %s. See http://cr
bug.com/278596" % exit_code | 523 err_str = "Image diff returned an exit code of %s. See http://cr
bug.com/278596" % exit_code |
| 522 except OSError, e: | 524 except OSError as e: |
| 523 err_str = 'error running image diff: %s' % str(e) | 525 err_str = 'error running image diff: %s' % str(e) |
| 524 finally: | 526 finally: |
| 525 self._filesystem.rmtree(str(tempdir)) | 527 self._filesystem.rmtree(str(tempdir)) |
| 526 | 528 |
| 527 return (result, err_str or None) | 529 return (result, err_str or None) |
| 528 | 530 |
| 529 def diff_text(self, expected_text, actual_text, expected_filename, actual_fi
lename): | 531 def diff_text(self, expected_text, actual_text, expected_filename, actual_fi
lename): |
| 530 """Returns a string containing the diff of the two text strings | 532 """Returns a string containing the diff of the two text strings |
| 531 in 'unified diff' format.""" | 533 in 'unified diff' format.""" |
| 532 | 534 |
| (...skipping 244 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 777 return False | 779 return False |
| 778 | 780 |
| 779 @staticmethod | 781 @staticmethod |
| 780 def _has_supported_extension(filesystem, filename): | 782 def _has_supported_extension(filesystem, filename): |
| 781 """Return true if filename is one of the file extensions we want to run
a test on.""" | 783 """Return true if filename is one of the file extensions we want to run
a test on.""" |
| 782 extension = filesystem.splitext(filename)[1] | 784 extension = filesystem.splitext(filename)[1] |
| 783 return extension in Port._supported_file_extensions | 785 return extension in Port._supported_file_extensions |
| 784 | 786 |
| 785 @staticmethod | 787 @staticmethod |
| 786 def is_test_file(filesystem, dirname, filename): | 788 def is_test_file(filesystem, dirname, filename): |
| 787 return Port._has_supported_extension(filesystem, filename) and not Port.
is_reference_html_file(filesystem, dirname, filename) | 789 return Port._has_supported_extension( |
| 790 filesystem, filename) and not Port.is_reference_html_file(filesystem
, dirname, filename) |
| 788 | 791 |
| 789 ALL_TEST_TYPES = ['audio', 'harness', 'pixel', 'ref', 'text', 'unknown'] | 792 ALL_TEST_TYPES = ['audio', 'harness', 'pixel', 'ref', 'text', 'unknown'] |
| 790 | 793 |
| 791 def test_type(self, test_name): | 794 def test_type(self, test_name): |
| 792 fs = self._filesystem | 795 fs = self._filesystem |
| 793 if fs.exists(self.expected_filename(test_name, '.png')): | 796 if fs.exists(self.expected_filename(test_name, '.png')): |
| 794 return 'pixel' | 797 return 'pixel' |
| 795 if fs.exists(self.expected_filename(test_name, '.wav')): | 798 if fs.exists(self.expected_filename(test_name, '.wav')): |
| 796 return 'audio' | 799 return 'audio' |
| 797 if self.reference_files(test_name): | 800 if self.reference_files(test_name): |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1196 def stop_helper(self): | 1199 def stop_helper(self): |
| 1197 """Shut down the test helper if it is running. Do nothing if | 1200 """Shut down the test helper if it is running. Do nothing if |
| 1198 it isn't, or it isn't available. If a port overrides start_helper() | 1201 it isn't, or it isn't available. If a port overrides start_helper() |
| 1199 it must override this routine as well.""" | 1202 it must override this routine as well.""" |
| 1200 if self._helper: | 1203 if self._helper: |
| 1201 _log.debug("Stopping layout test helper") | 1204 _log.debug("Stopping layout test helper") |
| 1202 try: | 1205 try: |
| 1203 self._helper.stdin.write("x\n") | 1206 self._helper.stdin.write("x\n") |
| 1204 self._helper.stdin.close() | 1207 self._helper.stdin.close() |
| 1205 self._helper.wait() | 1208 self._helper.wait() |
| 1206 except IOError, e: | 1209 except IOError as e: |
| 1207 pass | 1210 pass |
| 1208 finally: | 1211 finally: |
| 1209 self._helper = None | 1212 self._helper = None |
| 1210 | 1213 |
| 1211 def stop_http_server(self): | 1214 def stop_http_server(self): |
| 1212 """Shut down the http server if it is running. Do nothing if it isn't.""
" | 1215 """Shut down the http server if it is running. Do nothing if it isn't.""
" |
| 1213 if self._http_server: | 1216 if self._http_server: |
| 1214 self._http_server.stop() | 1217 self._http_server.stop() |
| 1215 self._http_server = None | 1218 self._http_server = None |
| 1216 | 1219 |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1399 if self._pretty_patch_available is None: | 1402 if self._pretty_patch_available is None: |
| 1400 self._pretty_patch_available = self.check_pretty_patch(logging=False
) | 1403 self._pretty_patch_available = self.check_pretty_patch(logging=False
) |
| 1401 if not self._pretty_patch_available: | 1404 if not self._pretty_patch_available: |
| 1402 return self._pretty_patch_error_html | 1405 return self._pretty_patch_error_html |
| 1403 command = ("ruby", "-I", self._filesystem.dirname(self._pretty_patch_pat
h), | 1406 command = ("ruby", "-I", self._filesystem.dirname(self._pretty_patch_pat
h), |
| 1404 self._pretty_patch_path, diff_path) | 1407 self._pretty_patch_path, diff_path) |
| 1405 try: | 1408 try: |
| 1406 # Diffs are treated as binary (we pass decode_output=False) as they | 1409 # Diffs are treated as binary (we pass decode_output=False) as they |
| 1407 # may contain multiple files of conflicting encodings. | 1410 # may contain multiple files of conflicting encodings. |
| 1408 return self._executive.run_command(command, decode_output=False) | 1411 return self._executive.run_command(command, decode_output=False) |
| 1409 except OSError, e: | 1412 except OSError as e: |
| 1410 # If the system is missing ruby log the error and stop trying. | 1413 # If the system is missing ruby log the error and stop trying. |
| 1411 self._pretty_patch_available = False | 1414 self._pretty_patch_available = False |
| 1412 _log.error("Failed to run PrettyPatch (%s): %s" % (command, e)) | 1415 _log.error("Failed to run PrettyPatch (%s): %s" % (command, e)) |
| 1413 return self._pretty_patch_error_html | 1416 return self._pretty_patch_error_html |
| 1414 except ScriptError, e: | 1417 except ScriptError as e: |
| 1415 # If ruby failed to run for some reason, log the command | 1418 # If ruby failed to run for some reason, log the command |
| 1416 # output and stop trying. | 1419 # output and stop trying. |
| 1417 self._pretty_patch_available = False | 1420 self._pretty_patch_available = False |
| 1418 _log.error("Failed to run PrettyPatch (%s):\n%s" % (command, e.messa
ge_with_output())) | 1421 _log.error("Failed to run PrettyPatch (%s):\n%s" % (command, e.messa
ge_with_output())) |
| 1419 return self._pretty_patch_error_html | 1422 return self._pretty_patch_error_html |
| 1420 | 1423 |
| 1421 def default_configuration(self): | 1424 def default_configuration(self): |
| 1422 return 'Release' | 1425 return 'Release' |
| 1423 | 1426 |
| 1424 def clobber_old_port_specific_results(self): | 1427 def clobber_old_port_specific_results(self): |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1662 path = self._path_to_webcore_library() | 1665 path = self._path_to_webcore_library() |
| 1663 if path: | 1666 if path: |
| 1664 return [path] | 1667 return [path] |
| 1665 return [] | 1668 return [] |
| 1666 | 1669 |
| 1667 def _symbols_string(self): | 1670 def _symbols_string(self): |
| 1668 symbols = '' | 1671 symbols = '' |
| 1669 for path_to_module in self._modules_to_search_for_symbols(): | 1672 for path_to_module in self._modules_to_search_for_symbols(): |
| 1670 try: | 1673 try: |
| 1671 symbols += self._executive.run_command(['nm', path_to_module], e
rror_handler=self._executive.ignore_error) | 1674 symbols += self._executive.run_command(['nm', path_to_module], e
rror_handler=self._executive.ignore_error) |
| 1672 except OSError, e: | 1675 except OSError as e: |
| 1673 _log.warn("Failed to run nm: %s. Can't determine supported feat
ures correctly." % e) | 1676 _log.warn("Failed to run nm: %s. Can't determine supported feat
ures correctly." % e) |
| 1674 return symbols | 1677 return symbols |
| 1675 | 1678 |
| 1676 # Ports which use compile-time feature detection should define this method a
nd return | 1679 # Ports which use compile-time feature detection should define this method a
nd return |
| 1677 # a dictionary mapping from symbol substrings to possibly disabled test dire
ctories. | 1680 # a dictionary mapping from symbol substrings to possibly disabled test dire
ctories. |
| 1678 # When the symbol substrings are not matched, the directories will be skippe
d. | 1681 # When the symbol substrings are not matched, the directories will be skippe
d. |
| 1679 # If ports don't ever enable certain features, then those directories can ju
st be | 1682 # If ports don't ever enable certain features, then those directories can ju
st be |
| 1680 # in the Skipped list instead of compile-time-checked here. | 1683 # in the Skipped list instead of compile-time-checked here. |
| 1681 def _missing_symbol_to_skipped_tests(self): | 1684 def _missing_symbol_to_skipped_tests(self): |
| 1682 if self.PORT_HAS_AUDIO_CODECS_BUILT_IN: | 1685 if self.PORT_HAS_AUDIO_CODECS_BUILT_IN: |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1698 return False | 1701 return False |
| 1699 | 1702 |
| 1700 def _skipped_tests_for_unsupported_features(self, test_list): | 1703 def _skipped_tests_for_unsupported_features(self, test_list): |
| 1701 # Only check the symbols of there are tests in the test_list that might
get skipped. | 1704 # Only check the symbols of there are tests in the test_list that might
get skipped. |
| 1702 # This is a performance optimization to avoid the calling nm. | 1705 # This is a performance optimization to avoid the calling nm. |
| 1703 # Runtime feature detection not supported, fallback to static detection: | 1706 # Runtime feature detection not supported, fallback to static detection: |
| 1704 # Disable any tests for symbols missing from the executable or libraries
. | 1707 # Disable any tests for symbols missing from the executable or libraries
. |
| 1705 if self._has_test_in_directories(self._missing_symbol_to_skipped_tests()
.values(), test_list): | 1708 if self._has_test_in_directories(self._missing_symbol_to_skipped_tests()
.values(), test_list): |
| 1706 symbols_string = self._symbols_string() | 1709 symbols_string = self._symbols_string() |
| 1707 if symbols_string is not None: | 1710 if symbols_string is not None: |
| 1708 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], []) | 1711 return reduce(operator.add, [directories for symbol_substring, d
irectories in self._missing_symbol_to_skipped_tests( |
| 1712 ).items() if symbol_substring not in symbols_string], []) |
| 1709 return [] | 1713 return [] |
| 1710 | 1714 |
| 1711 def _convert_path(self, path): | 1715 def _convert_path(self, path): |
| 1712 """Handles filename conversion for subprocess command line args.""" | 1716 """Handles filename conversion for subprocess command line args.""" |
| 1713 # See note above in diff_image() for why we need this. | 1717 # See note above in diff_image() for why we need this. |
| 1714 if sys.platform == 'cygwin': | 1718 if sys.platform == 'cygwin': |
| 1715 return cygpath(path) | 1719 return cygpath(path) |
| 1716 return path | 1720 return path |
| 1717 | 1721 |
| 1718 def _build_path(self, *comps): | 1722 def _build_path(self, *comps): |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1780 | 1784 |
| 1781 def __init__(self, base, args, reference_args=None): | 1785 def __init__(self, base, args, reference_args=None): |
| 1782 self.name = base | 1786 self.name = base |
| 1783 self.base = base | 1787 self.base = base |
| 1784 self.args = args | 1788 self.args = args |
| 1785 self.reference_args = args if reference_args is None else reference_args | 1789 self.reference_args = args if reference_args is None else reference_args |
| 1786 self.tests = set() | 1790 self.tests = set() |
| 1787 | 1791 |
| 1788 def __repr__(self): | 1792 def __repr__(self): |
| 1789 return "PhysicalTestSuite('%s', '%s', %s, %s)" % (self.name, self.base,
self.args, self.reference_args) | 1793 return "PhysicalTestSuite('%s', '%s', %s, %s)" % (self.name, self.base,
self.args, self.reference_args) |
| OLD | NEW |