Changeset 72249 in webkit


Ignore:
Timestamp:
Nov 17, 2010 3:02:39 PM (13 years ago)
Author:
hayato@chromium.org
Message:

2010-11-17 Hayato Ito <hayato@chromium.org>

Refactor TestTypeBase.compare_output().

Introduce a TestOutput class and update compare_output() of each test
types so that they can take both actual and expected TestOutput objects.

https://bugs.webkit.org/show_bug.cgi?id=49431

  • Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
  • Scripts/webkitpy/layout_tests/layout_package/test_output.py: Added.
  • Scripts/webkitpy/layout_tests/port/base.py:
  • Scripts/webkitpy/layout_tests/port/chromium.py:
  • Scripts/webkitpy/layout_tests/port/dryrun.py:
  • Scripts/webkitpy/layout_tests/port/test.py:
  • Scripts/webkitpy/layout_tests/port/webkit.py:
  • Scripts/webkitpy/layout_tests/run_webkit_tests.py:
  • Scripts/webkitpy/layout_tests/test_types/image_diff.py:
  • Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
  • Scripts/webkitpy/layout_tests/test_types/text_diff.py:
Location:
trunk/WebKitTools
Files:
1 added
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebKitTools/ChangeLog

    r72245 r72249  
     12010-11-17  Hayato Ito  <hayato@chromium.org>
     2
     3        Refactor TestTypeBase.compare_output().
     4
     5        Introduce a TestOutput class and update compare_output() of each test
     6        types so that they can take both actual and expected TestOutput objects.
     7
     8        https://bugs.webkit.org/show_bug.cgi?id=49431
     9
     10        * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
     11        * Scripts/webkitpy/layout_tests/layout_package/test_output.py: Added.
     12        * Scripts/webkitpy/layout_tests/port/base.py:
     13        * Scripts/webkitpy/layout_tests/port/chromium.py:
     14        * Scripts/webkitpy/layout_tests/port/dryrun.py:
     15        * Scripts/webkitpy/layout_tests/port/test.py:
     16        * Scripts/webkitpy/layout_tests/port/webkit.py:
     17        * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
     18        * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
     19        * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
     20        * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
     21
    1222010-11-17  Adam Roben  <aroben@apple.com>
    223
  • trunk/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py

    r72149 r72249  
    5252
    5353import test_failures
     54import test_output
    5455import test_results
    5556
     
    7576
    7677
     78def _expected_test_output(port, filename):
     79    """Returns an expected TestOutput object."""
     80    return test_output.TestOutput(port.expected_text(filename),
     81                                  port.expected_image(filename),
     82                                  port.expected_checksum(filename))
     83
    7784def _process_output(port, options, test_input, test_types, test_args,
    78                     crash, timeout, test_run_time, actual_checksum,
    79                     output, error):
     85                    test_output):
    8086    """Receives the output from a DumpRenderTree process, subjects it to a
    8187    number of tests, and returns a list of failure types the test produced.
     
    8894      test_types: list of test types to subject the output to
    8995      test_args: arguments to be passed to each test
     96      test_output: a TestOutput object containing the output of the test
    9097
    9198    Returns: a TestResult object
     
    93100    failures = []
    94101
    95     # Some test args, such as the image hash, may be added or changed on a
    96     # test-by-test basis.
    97     local_test_args = copy.copy(test_args)
    98 
    99     local_test_args.hash = actual_checksum
    100 
    101     if crash:
     102    if test_output.crash:
    102103        failures.append(test_failures.FailureCrash())
    103     if timeout:
     104    if test_output.timeout:
    104105        failures.append(test_failures.FailureTimeout())
    105106
    106     if crash:
    107         _log.debug("Stacktrace for %s:\n%s" % (test_input.filename, error))
     107    if test_output.crash:
     108        _log.debug("Stacktrace for %s:\n%s" % (test_input.filename,
     109                                               test_output.error))
    108110        # Strip off "file://" since RelativeTestFilename expects
    109111        # filesystem paths.
     
    114116        port.maybe_make_directory(os.path.split(filename)[0])
    115117        with codecs.open(filename, "wb", "utf-8") as file:
    116             file.write(error)
    117     elif error:
    118         _log.debug("Previous test output stderr lines:\n%s" % error)
     118            file.write(test_output.error)
     119    elif test_output.error:
     120        _log.debug("Previous test output stderr lines:\n%s" % test_output.error)
     121
     122    expected_test_output = _expected_test_output(port, test_input.filename)
    119123
    120124    # Check the output and save the results.
     
    124128        start_diff_time = time.time()
    125129        new_failures = test_type.compare_output(port, test_input.filename,
    126                                                 output, local_test_args,
    127                                                 options.configuration)
     130                                                test_args, test_output,
     131                                                expected_test_output)
    128132        # Don't add any more failures if we already have a crash, so we don't
    129133        # double-report those tests. We do double-report for timeouts since
    130134        # we still want to see the text and image output.
    131         if not crash:
     135        if not test_output.crash:
    132136            failures.extend(new_failures)
    133137        time_for_diffs[test_type.__class__.__name__] = (
     
    135139
    136140    total_time_for_all_diffs = time.time() - start_diff_time
    137     return test_results.TestResult(test_input.filename, failures, test_run_time,
     141    return test_results.TestResult(test_input.filename, failures, test_output.test_time,
    138142                                   total_time_for_all_diffs, time_for_diffs)
    139143
     
    156160def _should_fetch_expected_checksum(options):
    157161    return options.pixel_tests and not (options.new_baseline or options.reset_results)
     162
     163
     164def _run_single_test(port, options, test_input, test_types, test_args, driver):
     165    # FIXME: Pull this into TestShellThread._run().
     166
     167    # The image hash is used to avoid doing an image dump if the
     168    # checksums match, so it should be set to a blank value if we
     169    # are generating a new baseline.  (Otherwise, an image from a
     170    # previous run will be copied into the baseline."""
     171    if _should_fetch_expected_checksum(options):
     172        image_hash_to_driver = port.expected_checksum(test_input.filename)
     173    else:
     174        image_hash_to_driver = None
     175    test_input.uri = port.filename_to_uri(test_input.filename).strip()
     176    test_output = driver.run_test(test_input.uri, test_input.timeout, image_hash_to_driver)
     177    return _process_output(port, options, test_input, test_types, test_args,
     178                           test_output)
    158179
    159180
     
    186207        # FIXME: this is a separate routine to work around a bug
    187208        # in coverage: see http://bitbucket.org/ned/coveragepy/issue/85.
    188 
    189         # FIXME: Pull this into TestShellThread._run().
    190         test_input = self._test_input
    191         test_input.uri = self._port.filename_to_uri(test_input.filename)
    192         if _should_fetch_expected_checksum(self._options):
    193             test_input.image_checksum = self._port.expected_checksum(test_input.filename)
    194 
    195         start = time.time()
    196209        self._driver = self._port.create_driver(self._test_args.png_path,
    197210                                                self._options)
    198211        self._driver.start()
    199         crash, timeout, actual_checksum, output, error = \
    200             self._driver.run_test(test_input.uri, test_input.timeout,
    201                                   test_input.image_checksum)
    202         end = time.time()
    203         self._test_result = _process_output(self._port, self._options,
    204             test_input, self._test_types, self._test_args,
    205             crash, timeout, end - start,
    206             actual_checksum, output, error)
     212        self._test_result = _run_single_test(self._port, self._options,
     213                                             self._test_input, self._test_types,
     214                                             self._test_args, self._driver)
    207215        self._driver.stop()
    208216
     
    502510        """
    503511        self._ensure_dump_render_tree_is_running()
    504         # The pixel_hash is used to avoid doing an image dump if the
    505         # checksums match, so it should be set to a blank value if we
    506         # are generating a new baseline.  (Otherwise, an image from a
    507         # previous run will be copied into the baseline.)
    508 
    509         # FIXME: Pull this into TestShellThread._run().
    510         test_input.uri = self._port.filename_to_uri(test_input.filename)
    511         if _should_fetch_expected_checksum(self._options):
    512             test_input.image_checksum = self._port.expected_checksum(test_input.filename)
    513         start = time.time()
    514 
    515512        thread_timeout = _milliseconds_to_seconds(
    516513             _pad_timeout(int(test_input.timeout)))
    517         self._next_timeout = start + thread_timeout
    518 
    519         crash, timeout, actual_checksum, output, error = \
    520            self._driver.run_test(test_input.uri, test_input.timeout, test_input.image_checksum)
    521         end = time.time()
    522 
    523         result = _process_output(self._port, self._options,
    524                                  test_input, self._test_types,
    525                                  self._test_args, crash,
    526                                  timeout, end - start, actual_checksum,
    527                                  output, error)
    528         self._test_results.append(result)
    529         return result
     514        self._next_timeout = time.time() + thread_timeout
     515        test_result = _run_single_test(self._port, self._options, test_input,
     516                                       self._test_types, self._test_args,
     517                                       self._driver)
     518        self._test_results.append(test_result)
     519        return test_result
    530520
    531521    def _ensure_dump_render_tree_is_running(self):
  • trunk/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py

    r71580 r72249  
    833833            test
    834834
    835         Returns a tuple of the following:
    836             crash - a boolean indicating whether the driver crashed on the test
    837             timeout - a boolean indicating whehter the test timed out
    838             checksum - a string containing the checksum of the image, if
    839                 present
    840             output - any text output
    841             error - any unexpected or additional (or error) text output
    842 
    843         Note that the image itself should be written to the path that was
    844         specified in the __init__() call."""
     835        Returns a TestOutput object.
     836        """
    845837        raise NotImplementedError('Driver.run_test')
    846838
  • trunk/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py

    r70789 r72249  
    4747from webkitpy.common.system.path import cygpath
    4848from webkitpy.layout_tests.layout_package import test_expectations
     49from webkitpy.layout_tests.layout_package import test_output
    4950
    5051import base
    5152import http_server
    52 
    53 from webkitpy.common.system.executive import Executive
    54 from webkitpy.layout_tests.layout_package import test_expectations
    5553
    5654# Chromium DRT on OSX uses WebKitDriver.
     
    448446        return cmd
    449447
     448    def _output_image(self):
     449        """Returns the image output which driver generated."""
     450        png_path = self._image_path
     451        if png_path and os.path.isfile(png_path):
     452            with open(png_path, 'rb') as image_file:
     453                return image_file.read()
     454        else:
     455            return None
     456
    450457    def run_test(self, uri, timeoutms, checksum):
    451458        output = []
     
    499506            (line, crash) = self._write_command_and_read_line(input=None)
    500507
    501         return (crash, timeout, actual_checksum, ''.join(output),
    502                 ''.join(error))
     508        return test_output.TestOutput(
     509            ''.join(output), self._output_image(), actual_checksum,
     510            crash, time.time() - start_time, timeout, ''.join(error))
    503511
    504512    def stop(self):
  • trunk/WebKitTools/Scripts/webkitpy/layout_tests/port/dryrun.py

    r70013 r72249  
    4949import os
    5050import sys
     51import time
     52
     53from webkitpy.layout_tests.layout_package import test_output
    5154
    5255import base
     
    110113
    111114    def run_test(self, uri, timeoutms, image_hash):
     115        start_time = time.time()
    112116        test_name = self._port.uri_to_test_name(uri)
    113117        path = os.path.join(self._port.layout_tests_dir(), test_name)
     
    116120        if image_hash is not None:
    117121            image = self._port.expected_image(path)
    118             if image and self._image_path:
    119                 with open(self._image_path, 'w') as f:
    120                     f.write(image)
    121122            hash = self._port.expected_checksum(path)
    122123        else:
     124            image = None
    123125            hash = None
    124         return (False, False, hash, text_output, None)
     126        return test_output.TestOutput(text_output, image, hash, False,
     127                                      time.time() - start_time, False, None)
    125128
    126129    def start(self):
  • trunk/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py

    r70277 r72249  
    3636import sys
    3737import time
     38
     39from webkitpy.layout_tests.layout_package import test_output
    3840
    3941import base
     
    290292
    291293    def run_test(self, uri, timeoutms, image_hash):
     294        start_time = time.time()
    292295        test_name = self._port.uri_to_test_name(uri)
    293296        test = self._port._tests[test_name]
     
    298301        if test.hang:
    299302            time.sleep((float(timeoutms) * 4) / 1000.0)
    300 
    301         if self._port.get_option('pixel_tests') and test.actual_image:
    302             with open(self._image_path, 'w') as file:
    303                 file.write(test.actual_image)
    304 
    305         return (test.crash, test.timeout, test.actual_checksum,
    306                 test.actual_text, test.error)
     303        return test_output.TestOutput(test.actual_text, test.actual_image,
     304                                      test.actual_checksum, test.crash,
     305                                      time.time() - start_time, test.timeout,
     306                                      test.error)
    307307
    308308    def start(self):
  • trunk/WebKitTools/Scripts/webkitpy/layout_tests/port/webkit.py

    r71580 r72249  
    5050
    5151import webkitpy.common.system.ospath as ospath
     52import webkitpy.layout_tests.layout_package.test_output as test_output
    5253import webkitpy.layout_tests.port.base as base
    5354import webkitpy.layout_tests.port.server_process as server_process
     
    443444        command += "\n"
    444445
     446        start_time = time.time()
    445447        self._server_process.write(command)
    446448
     
    487489            line = self._server_process.read_line(timeout)
    488490
    489         if self._image_path and len(self._image_path):
    490             with open(self._image_path, "wb") as image_file:
    491                 image_file.write(image)
    492 
    493491        error_lines = self._server_process.error.splitlines()
    494492        # FIXME: This is a hack.  It is unclear why sometimes
     
    501499        # this reset in.
    502500        self._server_process.error = ""
    503         return (self._server_process.crashed,
    504                 self._server_process.timed_out,
    505                 actual_image_hash,
    506                 output,
    507                 error)
     501        return test_output.TestOutput(output, image, actual_image_hash,
     502                                      self._server_process.crashed,
     503                                      time.time() - start_time,
     504                                      self._server_process.timed_out,
     505                                      error)
    508506
    509507    def stop(self):
  • trunk/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py

    r72149 r72249  
    102102        # FIXME: filename should really be test_name as a relative path.
    103103        self.filename = filename
    104         # The image checksum is passed to the driver so that the driver can optionally not have
    105         # to output the image if the checksums match.
    106         self.image_checksum = None
    107104        self.timeout = timeout
    108105
  • trunk/WebKitTools/Scripts/webkitpy/layout_tests/test_types/image_diff.py

    r69153 r72249  
    5555class ImageDiff(test_type_base.TestTypeBase):
    5656
    57     def _copy_output_png(self, test_filename, source_image, extension):
    58         """Copies result files into the output directory with appropriate
    59         names.
    60 
    61         Args:
    62           test_filename: the test filename
    63           source_file: path to the image file (either actual or expected)
    64           extension: extension to indicate -actual.png or -expected.png
    65         """
    66         self._make_output_directory(test_filename)
    67         dest_image = self.output_filename(test_filename, extension)
    68 
    69         if os.path.exists(source_image):
    70             shutil.copyfile(source_image, dest_image)
    71 
    72     def _save_baseline_files(self, filename, png_path, checksum,
     57    def _save_baseline_files(self, filename, image, image_hash,
    7358                             generate_new_baseline):
    7459        """Saves new baselines for the PNG and checksum.
     
    7661        Args:
    7762          filename: test filename
    78           png_path: path to the actual PNG result file
    79           checksum: value of the actual checksum result
     63          image: a image output
     64          image_hash: a checksum of the image
    8065          generate_new_baseline: whether to generate a new, platform-specific
    8166            baseline, or update the existing one
    8267        """
    83         with open(png_path, "rb") as png_file:
    84             png_data = png_file.read()
    85         self._save_baseline_data(filename, png_data, ".png", encoding=None,
     68        self._save_baseline_data(filename, image, ".png", encoding=None,
    8669                                 generate_new_baseline=generate_new_baseline)
    87         self._save_baseline_data(filename, checksum, ".checksum",
     70        self._save_baseline_data(filename, image_hash, ".checksum",
    8871                                 encoding="ascii",
    8972                                 generate_new_baseline=generate_new_baseline)
    9073
    91     def _create_image_diff(self, port, filename, configuration):
     74    def _copy_image(self, filename, actual_image, expected_image):
     75        self.write_output_files(filename, '.png',
     76                                output=actual_image, expected=expected_image,
     77                                encoding=None, print_text_diffs=False)
     78
     79    def _copy_image_hash(self, filename, actual_image_hash, expected_image_hash):
     80        self.write_output_files(filename, '.checksum',
     81                                actual_image_hash, expected_image_hash,
     82                                encoding="ascii", print_text_diffs=False)
     83
     84    def _create_diff_image(self, port, filename, actual_image, expected_image):
    9285        """Creates the visual diff of the expected/actual PNGs.
    9386
    94         Args:
    95           filename: the name of the test
    96           configuration: Debug or Release
    97         Returns True if the files are different, False if they match
     87        Returns True if the images are different.
    9888        """
    9989        diff_filename = self.output_filename(filename,
    100           self.FILENAME_SUFFIX_COMPARE)
    101         actual_filename = self.output_filename(filename,
    102           self.FILENAME_SUFFIX_ACTUAL + '.png')
    103         expected_filename = self.output_filename(filename,
    104           self.FILENAME_SUFFIX_EXPECTED + '.png')
     90                                             self.FILENAME_SUFFIX_COMPARE)
     91        return port.diff_image(actual_image, expected_image, diff_filename)
    10592
    106         expected_image = port.expected_image(filename)
    107         with codecs.open(actual_filename, 'r+b', None) as file:
    108             actual_image = file.read()
    109 
    110         result = port.diff_image(expected_image, actual_image,
    111                                  diff_filename)
    112         return result
    113 
    114     def compare_output(self, port, filename, output, test_args, configuration):
     93    def compare_output(self, port, filename, test_args, actual_test_output,
     94                       expected_test_output):
    11595        """Implementation of CompareOutput that checks the output image and
    11696        checksum against the expected files from the LayoutTest directory.
     
    11999
    120100        # If we didn't produce a hash file, this test must be text-only.
    121         if test_args.hash is None:
     101        if actual_test_output.image_hash is None:
    122102            return failures
    123103
    124104        # If we're generating a new baseline, we pass.
    125105        if test_args.new_baseline or test_args.reset_results:
    126             self._save_baseline_files(filename, test_args.png_path,
    127                                       test_args.hash, test_args.new_baseline)
     106            self._save_baseline_files(filename, actual_test_output.image_hash,
     107                                      actual_test_output.image,
     108                                      test_args.new_baseline)
    128109            return failures
    129110
    130         # Compare hashes.
    131         expected_hash = self._port.expected_checksum(filename)
    132         expected_png = self._port.expected_image(filename)
    133 
    134         if not expected_png:
     111        if not expected_test_output.image:
    135112            # Report a missing expected PNG file.
    136             self.write_output_files(filename, '.checksum',
    137                                     test_args.hash, expected_hash,
    138                                     encoding="ascii",
    139                                     print_text_diffs=False)
    140             self._copy_output_png(filename, test_args.png_path, '-actual.png')
     113            self._copy_image(filename, actual_test_output.image, expected_image=None)
     114            self._copy_image_hash(filename, actual_test_output.image_hash,
     115                                  expected_test_output.image_hash)
    141116            failures.append(test_failures.FailureMissingImage())
    142117            return failures
    143         elif test_args.hash == expected_hash:
     118        if not expected_test_output.image_hash:
     119            # Report a missing expected checksum file.
     120            self._copy_image(filename, actual_test_output.image,
     121                             expected_test_output.image)
     122            self._copy_image_hash(filename, actual_test_output.image_hash,
     123                                  expected_image_hash=None)
     124            failures.append(test_failures.FailureMissingImageHash())
     125            return failures
     126
     127        if actual_test_output.image_hash == expected_test_output.image_hash:
    144128            # Hash matched (no diff needed, okay to return).
    145129            return failures
    146130
    147         self.write_output_files(filename, '.checksum',
    148                                 test_args.hash, expected_hash,
    149                                 encoding="ascii",
    150                                 print_text_diffs=False)
    151 
    152         # FIXME: combine next two lines
    153         self._copy_output_png(filename, test_args.png_path, '-actual.png')
    154         self.write_output_files(filename, '.png', output=None,
    155                                 expected=expected_png,
    156                                 encoding=None, print_text_diffs=False)
     131        self._copy_image(filename, actual_test_output.image,
     132                         expected_test_output.image)
     133        self._copy_image_hash(filename, actual_test_output.image_hash,
     134                              expected_test_output.image_hash)
    157135
    158136        # Even though we only use the result in one codepath below but we
    159137        # still need to call CreateImageDiff for other codepaths.
    160         images_are_different = self._create_image_diff(port, filename, configuration)
    161         if not expected_hash:
    162             failures.append(test_failures.FailureMissingImageHash())
    163         elif test_args.hash != expected_hash:
    164             if images_are_different:
    165                 failures.append(test_failures.FailureImageHashMismatch())
    166             else:
    167                 failures.append(test_failures.FailureImageHashIncorrect())
     138        images_are_different = self._create_diff_image(port, filename,
     139                                                       actual_test_output.image,
     140                                                       expected_test_output.image)
     141        if not images_are_different:
     142            failures.append(test_failures.FailureImageHashIncorrect())
     143        else:
     144            failures.append(test_failures.FailureImageHashMismatch())
    168145
    169146        return failures
  • trunk/WebKitTools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py

    r69171 r72249  
    141141        return os.path.splitext(output_filename)[0] + modifier
    142142
    143     def compare_output(self, port, filename, output, test_args, configuration):
     143    def compare_output(self, port, filename, test_args, actual_test_output,
     144                        expected_test_output):
    144145        """Method that compares the output from the test with the
    145146        expected value.
     
    148149
    149150        Args:
     151          port: object implementing port-specific information and methods
    150152          filename: absolute filename to test file
    151           output: a string containing the output of the test
    152153          test_args: a TestArguments object holding optional additional
    153154              arguments
    154           configuration: Debug or Release
     155          actual_test_output: a TestOutput object which represents actual test
     156              output
     157          expected_test_output: a TestOutput object which represents a expected
     158              test output
    155159
    156160        Return:
  • trunk/WebKitTools/Scripts/webkitpy/layout_tests/test_types/text_diff.py

    r70943 r72249  
    5656        return norm + "\n"
    5757
    58     def _get_normalized_expected_text(self, filename):
    59         """Given the filename of the test, read the expected output from a file
    60         and normalize the text.  Returns a string with the expected text, or ''
    61         if the expected output file was not found."""
    62         return self._port.expected_text(filename)
    63 
    64     def compare_output(self, port, filename, output, test_args, configuration):
     58    def compare_output(self, port, filename, test_args, actual_test_output,
     59                        expected_test_output):
    6560        """Implementation of CompareOutput that checks the output text against
    6661        the expected text from the LayoutTest directory."""
     
    7772
    7873        # Normalize text to diff
    79         output = self._get_normalized_output_text(output)
    80         expected = self._get_normalized_expected_text(filename)
     74        actual_text = self._get_normalized_output_text(actual_test_output.text)
     75        # Assuming expected_text is already normalized.
     76        expected_text = expected_test_output.text
    8177
    8278        # Write output files for new tests, too.
    83         if port.compare_text(output, expected):
     79        if port.compare_text(actual_text, expected_text):
    8480            # Text doesn't match, write output files.
    85             self.write_output_files(filename, ".txt", output,
    86                                     expected, encoding=None,
     81            self.write_output_files(filename, ".txt", actual_text,
     82                                    expected_text, encoding=None,
    8783                                    print_text_diffs=True)
    8884
    89             if expected == '':
     85            if expected_text == '':
    9086                failures.append(test_failures.FailureMissingResult())
    9187            else:
Note: See TracChangeset for help on using the changeset viewer.