Title: [124958] trunk/Tools
Revision
124958
Author
dpra...@chromium.org
Date
2012-08-07 18:08:48 -0700 (Tue, 07 Aug 2012)

Log Message

nrwt: handle errors from image diff better
https://bugs.webkit.org/show_bug.cgi?id=92934

Reviewed by Ojan Vafai.

Re-land the change in r124801 with a fix ... in the case where
the ImageDiff is passed a tolerance and passes the fuzzy check,
we were returning the wrong value (missing an empty error
string) and crashing; this patch fixes that and adds a test for
that case (TestImageDiffer.test_image_diff_passed).

* Scripts/webkitpy/layout_tests/controllers/single_test_runner.py:
(SingleTestRunner._compare_image):
(SingleTestRunner._compare_output_with_reference):
* Scripts/webkitpy/layout_tests/controllers/test_result_writer.py:
(write_test_result):
* Scripts/webkitpy/layout_tests/controllers/test_result_writer_unittest.py:
(TestResultWriterTest.test_reftest_diff_image.ImageDiffTestPort.diff_image):
(TestResultWriterTest):
* Scripts/webkitpy/layout_tests/port/base.py:
(Port.diff_image):
* Scripts/webkitpy/layout_tests/port/chromium.py:
(ChromiumPort.diff_image):
* Scripts/webkitpy/layout_tests/port/chromium_port_testcase.py:
(ChromiumPortTestCase.test_diff_image_crashed):
* Scripts/webkitpy/layout_tests/port/image_diff.py:
(ImageDiffer.diff_image):
(ImageDiffer._read):
* Scripts/webkitpy/layout_tests/port/image_diff_unittest.py:
(TestImageDiffer.test_diff_image):
* Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py:
(MockDRTPortTest.test_diff_image_crashed):
* Scripts/webkitpy/layout_tests/port/port_testcase.py:
(PortTestCase.test_diff_image):
(PortTestCase.test_diff_image_crashed):
(PortTestCase.test_diff_image_crashed.make_proc):
* Scripts/webkitpy/layout_tests/port/server_process_mock.py:
(MockServerProcess.__init__):
* Scripts/webkitpy/layout_tests/port/test.py:
(TestPort.diff_image):
* Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py:
(MainTest.test_tolerance.ImageDiffTestPort.diff_image):

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (124957 => 124958)


--- trunk/Tools/ChangeLog	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/ChangeLog	2012-08-08 01:08:48 UTC (rev 124958)
@@ -1,5 +1,50 @@
 2012-08-07  Dirk Pranke  <dpra...@chromium.org>
 
+        nrwt: handle errors from image diff better
+        https://bugs.webkit.org/show_bug.cgi?id=92934
+
+        Reviewed by Ojan Vafai.
+
+        Re-land the change in r124801 with a fix ... in the case where
+        the ImageDiff is passed a tolerance and passes the fuzzy check,
+        we were returning the wrong value (missing an empty error
+        string) and crashing; this patch fixes that and adds a test for
+        that case (TestImageDiffer.test_image_diff_passed).
+
+        * Scripts/webkitpy/layout_tests/controllers/single_test_runner.py:
+        (SingleTestRunner._compare_image):
+        (SingleTestRunner._compare_output_with_reference):
+        * Scripts/webkitpy/layout_tests/controllers/test_result_writer.py:
+        (write_test_result):
+        * Scripts/webkitpy/layout_tests/controllers/test_result_writer_unittest.py:
+        (TestResultWriterTest.test_reftest_diff_image.ImageDiffTestPort.diff_image):
+        (TestResultWriterTest):
+        * Scripts/webkitpy/layout_tests/port/base.py:
+        (Port.diff_image):
+        * Scripts/webkitpy/layout_tests/port/chromium.py:
+        (ChromiumPort.diff_image):
+        * Scripts/webkitpy/layout_tests/port/chromium_port_testcase.py:
+        (ChromiumPortTestCase.test_diff_image_crashed):
+        * Scripts/webkitpy/layout_tests/port/image_diff.py:
+        (ImageDiffer.diff_image):
+        (ImageDiffer._read):
+        * Scripts/webkitpy/layout_tests/port/image_diff_unittest.py:
+        (TestImageDiffer.test_diff_image):
+        * Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py:
+        (MockDRTPortTest.test_diff_image_crashed):
+        * Scripts/webkitpy/layout_tests/port/port_testcase.py:
+        (PortTestCase.test_diff_image):
+        (PortTestCase.test_diff_image_crashed):
+        (PortTestCase.test_diff_image_crashed.make_proc):
+        * Scripts/webkitpy/layout_tests/port/server_process_mock.py:
+        (MockServerProcess.__init__):
+        * Scripts/webkitpy/layout_tests/port/test.py:
+        (TestPort.diff_image):
+        * Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py:
+        (MainTest.test_tolerance.ImageDiffTestPort.diff_image):
+
+2012-08-07  Dirk Pranke  <dpra...@chromium.org>
+
         nrwt: --no-build isn't working
         https://bugs.webkit.org/show_bug.cgi?id=93415
 

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py (124957 => 124958)


--- trunk/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py	2012-08-08 01:08:48 UTC (rev 124958)
@@ -264,12 +264,18 @@
             failures.append(test_failures.FailureMissingImageHash())
         elif driver_output.image_hash != expected_driver_output.image_hash:
             diff_result = self._port.diff_image(driver_output.image, expected_driver_output.image)
-            driver_output.image_diff = diff_result[0]
-            if driver_output.image_diff:
-                failures.append(test_failures.FailureImageHashMismatch(diff_result[1]))
+            err_str = diff_result[2]
+            if err_str:
+                _log.warning('  %s : %s' % (self._test_name, err_str))
+                failures.append(test_failures.FailureImageHashMismatch())
+                driver_output.error = (driver_output.error or '') + err_str
             else:
-                # See https://bugs.webkit.org/show_bug.cgi?id=69444 for why this isn't a full failure.
-                _log.warning('  %s -> pixel hash failed (but pixel test still passes)' % self._test_name)
+                driver_output.image_diff = diff_result[0]
+                if driver_output.image_diff:
+                    failures.append(test_failures.FailureImageHashMismatch(diff_result[1]))
+                else:
+                    # See https://bugs.webkit.org/show_bug.cgi?id=69444 for why this isn't a full failure.
+                    _log.warning('  %s -> pixel hash failed (but pixel test still passes)' % self._test_name)
         return failures
 
     def _run_reftest(self):
@@ -317,4 +323,8 @@
                 failures.append(test_failures.FailureReftestMismatchDidNotOccur(reference_filename))
         elif driver_output1.image_hash != driver_output2.image_hash:
             failures.append(test_failures.FailureReftestMismatch(reference_filename))
+
+        # recompute in case we added to stderr during diff_image
+        has_stderr = driver_output1.has_stderr() or driver_output2.has_stderr()
+
         return TestResult(self._test_name, failures, total_test_time, has_stderr)

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/controllers/test_result_writer.py (124957 => 124958)


--- trunk/Tools/Scripts/webkitpy/layout_tests/controllers/test_result_writer.py	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/controllers/test_result_writer.py	2012-08-08 01:08:48 UTC (rev 124958)
@@ -69,7 +69,7 @@
             # FIXME: This work should be done earlier in the pipeline (e.g., when we compare images for non-ref tests).
             # FIXME: We should always have 2 images here.
             if driver_output.image and expected_driver_output.image:
-                diff_image, diff_percent = port.diff_image(driver_output.image, expected_driver_output.image, tolerance=0)
+                diff_image, diff_percent, err_str = port.diff_image(driver_output.image, expected_driver_output.image, tolerance=0)
                 if diff_image:
                     writer.write_image_diff_files(diff_image)
                     failure.diff_percent = diff_percent

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/controllers/test_result_writer_unittest.py (124957 => 124958)


--- trunk/Tools/Scripts/webkitpy/layout_tests/controllers/test_result_writer_unittest.py	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/controllers/test_result_writer_unittest.py	2012-08-08 01:08:48 UTC (rev 124958)
@@ -42,7 +42,7 @@
         class ImageDiffTestPort(TestPort):
             def diff_image(self, expected_contents, actual_contents, tolerance=None):
                 used_tolerance_values.append(tolerance)
-                return (True, 1)
+                return (True, 1, None)
 
         host = MockHost()
         port = ImageDiffTestPort(host)

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/port/base.py (124957 => 124958)


--- trunk/Tools/Scripts/webkitpy/layout_tests/port/base.py	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/port/base.py	2012-08-08 01:08:48 UTC (rev 124958)
@@ -319,7 +319,7 @@
         return expected_audio != actual_audio
 
     def diff_image(self, expected_contents, actual_contents, tolerance=None):
-        """Compare two images and return a tuple of an image diff, and a percentage difference (0-100).
+        """Compare two images and return a tuple of an image diff, a percentage difference (0-100), and an error string.
 
         |tolerance| should be a percentage value (0.0 - 100.0).
         If it is omitted, the port default tolerance value is used.
@@ -327,9 +327,9 @@
         If an error occurs (like ImageDiff isn't found, or crashes, we log an error and return True (for a diff).
         """
         if not actual_contents and not expected_contents:
-            return (None, 0)
+            return (None, 0, None)
         if not actual_contents or not expected_contents:
-            return (True, 0)
+            return (True, 0, None)
         if not self._image_differ:
             self._image_differ = image_diff.ImageDiffer(self)
         self.set_option_default('tolerance', 0.1)

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/port/chromium.py (124957 => 124958)


--- trunk/Tools/Scripts/webkitpy/layout_tests/port/chromium.py	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/port/chromium.py	2012-08-08 01:08:48 UTC (rev 124958)
@@ -190,18 +190,16 @@
                                        override_step, logging)
 
     def diff_image(self, expected_contents, actual_contents, tolerance=None):
-        # FIXME: need unit tests for this.
-
         # tolerance is not used in chromium. Make sure caller doesn't pass tolerance other than zero or None.
         assert (tolerance is None) or tolerance == 0
 
         # If only one of them exists, return that one.
         if not actual_contents and not expected_contents:
-            return (None, 0)
+            return (None, 0, None)
         if not actual_contents:
-            return (expected_contents, 0)
+            return (expected_contents, 0, None)
         if not expected_contents:
-            return (actual_contents, 0)
+            return (actual_contents, 0, None)
 
         tempdir = self._filesystem.mkdtemp()
 
@@ -221,29 +219,23 @@
         comand = [executable, '--diff', native_actual_filename, native_expected_filename, native_diff_filename]
 
         result = None
+        err_str = None
         try:
             exit_code = self._executive.run_command(comand, return_exit_code=True)
             if exit_code == 0:
                 # The images are the same.
                 result = None
-            elif exit_code != 1:
-                _log.error("image diff returned an exit code of %s" % exit_code)
-                # Returning None here causes the script to think that we
-                # successfully created the diff even though we didn't.
-                # FIXME: Consider raising an exception here, so that the error
-                # is not accidentally overlooked while the test passes.
-                result = None
-        except OSError, e:
-            if e.errno == errno.ENOENT or e.errno == errno.EACCES:
-                _compare_available = False
+            elif exit_code == 1:
+                result = self._filesystem.read_binary_file(native_diff_filename)
             else:
-                raise
+                err_str = "image diff returned an exit code of %s" % exit_code
+        except OSError, e:
+            err_str = 'error running image diff: %s' % str(e)
         finally:
-            if exit_code == 1:
-                result = self._filesystem.read_binary_file(native_diff_filename)
             self._filesystem.rmtree(str(tempdir))
-        return (result, 0)  # FIXME: how to get % diff?
 
+        return (result, 0, err_str or None)  # FIXME: how to get % diff?
+
     def path_from_chromium_base(self, *comps):
         """Returns the full path to path made by joining the top of the
         Chromium source tree and the list of path components in |*comps|."""

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/port/chromium_port_testcase.py (124957 => 124958)


--- trunk/Tools/Scripts/webkitpy/layout_tests/port/chromium_port_testcase.py	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/port/chromium_port_testcase.py	2012-08-08 01:08:48 UTC (rev 124958)
@@ -158,6 +158,11 @@
             exception_raised = True
         self.assertFalse(exception_raised)
 
+    def test_diff_image_crashed(self):
+        port = ChromiumPortTestCase.TestLinuxPort()
+        port._executive = MockExecutive2(exit_code=2)
+        self.assertEquals(port.diff_image("EXPECTED", "ACTUAL"), (None, 0, 'image diff returned an exit code of 2'))
+
     def test_expectations_files(self):
         port = self.make_port()
         port.port_name = 'chromium'

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/port/image_diff.py (124957 => 124958)


--- trunk/Tools/Scripts/webkitpy/layout_tests/port/image_diff.py	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/port/image_diff.py	2012-08-08 01:08:48 UTC (rev 124958)
@@ -62,8 +62,7 @@
                 len(expected_contents), expected_contents))
             return self._read()
         except IOError as exception:
-            _log.error("Failed to compute an image diff: %s" % str(exception))
-            return (True, 0)
+            return (None, 0, "Failed to compute an image diff: %s" % str(exception))
 
     def _start(self, tolerance):
         command = [self._port._path_to_image_diff(), '--tolerance', str(tolerance)]
@@ -77,7 +76,7 @@
         output = None
         output_image = ""
 
-        while True:
+        while not self._process.timed_out and not self._process.has_crashed():
             output = self._process.read_stdout_line(deadline)
             if self._process.timed_out or self._process.has_crashed() or not output:
                 break
@@ -93,12 +92,14 @@
                 break
 
         stderr = self._process.pop_all_buffered_stderr()
+        err_str = ''
         if stderr:
-            _log.warn("ImageDiff produced stderr output:\n" + stderr)
+            err_str += "ImageDiff produced stderr output:\n" + stderr
         if self._process.timed_out:
-            _log.error("ImageDiff timed out")
+            err_str += "ImageDiff timed out\n"
         if self._process.has_crashed():
-            _log.error("ImageDiff crashed")
+            err_str += "ImageDiff crashed\n"
+
         # FIXME: There is no need to shut down the ImageDiff server after every diff.
         self._process.stop()
 
@@ -106,10 +107,10 @@
         if output and output.startswith('diff'):
             m = re.match('diff: (.+)% (passed|failed)', output)
             if m.group(2) == 'passed':
-                return [None, 0]
+                return (None, 0, None)
             diff_percent = float(m.group(1))
 
-        return (output_image, diff_percent)
+        return (output_image, diff_percent, err_str or None)
 
     def stop(self):
         if self._process:

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/port/image_diff_unittest.py (124957 => 124958)


--- trunk/Tools/Scripts/webkitpy/layout_tests/port/image_diff_unittest.py	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/port/image_diff_unittest.py	2012-08-08 01:08:48 UTC (rev 124958)
@@ -46,7 +46,12 @@
 
 
 class TestImageDiffer(unittest.TestCase):
-    def test_diff_image(self):
+    def test_diff_image_failed(self):
         port = FakePort(['diff: 100% failed\n'])
         image_differ = ImageDiffer(port)
-        self.assertEquals(image_differ.diff_image('foo', 'bar', 0.1), ('', 100.0))
+        self.assertEquals(image_differ.diff_image('foo', 'bar', 0.1), ('', 100.0, None))
+
+    def test_diff_image_passed(self):
+        port = FakePort(['diff: 0% passed\n'])
+        image_differ = ImageDiffer(port)
+        self.assertEquals(image_differ.diff_image('foo', 'bar', 0.1), (None, 0, None))

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py (124957 => 124958)


--- trunk/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/port/mock_drt_unittest.py	2012-08-08 01:08:48 UTC (rev 124958)
@@ -60,6 +60,9 @@
     def test_diff_image(self):
         pass
 
+    def test_diff_image_crashed(self):
+        pass
+
     def test_uses_apache(self):
         pass
 

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py (124957 => 124958)


--- trunk/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py	2012-08-08 01:08:48 UTC (rev 124958)
@@ -259,19 +259,32 @@
 
         port._server_process_constructor = make_proc
         port.setup_test_run()
-        self.assertEquals(port.diff_image('foo', 'bar'), ('', 100.0))
+        self.assertEquals(port.diff_image('foo', 'bar'), ('', 100.0, None))
         self.assertEquals(self.proc.cmd[1:3], ["--tolerance", "0.1"])
 
-        self.assertEquals(port.diff_image('foo', 'bar', None), ('', 100.0))
+        self.assertEquals(port.diff_image('foo', 'bar', None), ('', 100.0, None))
         self.assertEquals(self.proc.cmd[1:3], ["--tolerance", "0.1"])
 
-        self.assertEquals(port.diff_image('foo', 'bar', 0), ('', 100.0))
+        self.assertEquals(port.diff_image('foo', 'bar', 0), ('', 100.0, None))
         self.assertEquals(self.proc.cmd[1:3], ["--tolerance", "0"])
 
         port.clean_up_test_run()
         self.assertTrue(self.proc.stopped)
         self.assertEquals(port._image_differ, None)
 
+    def test_diff_image_crashed(self):
+        port = self.make_port()
+        self.proc = None
+
+        def make_proc(port, nm, cmd, env):
+            self.proc = MockServerProcess(port, nm, cmd, env, crashed=True)
+            return self.proc
+
+        port._server_process_constructor = make_proc
+        port.setup_test_run()
+        self.assertEquals(port.diff_image('foo', 'bar'), ('', 0, 'ImageDiff crashed\n'))
+        port.clean_up_test_run()
+
     def test_check_wdiff(self):
         port = self.make_port()
         port.check_wdiff()

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/port/server_process_mock.py (124957 => 124958)


--- trunk/Tools/Scripts/webkitpy/layout_tests/port/server_process_mock.py	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/port/server_process_mock.py	2012-08-08 01:08:48 UTC (rev 124958)
@@ -28,10 +28,10 @@
 
 
 class MockServerProcess(object):
-    def __init__(self, port_obj=None, name=None, cmd=None, env=None, universal_newlines=False, lines=None):
+    def __init__(self, port_obj=None, name=None, cmd=None, env=None, universal_newlines=False, lines=None, crashed=False):
         self.timed_out = False
         self.lines = lines or []
-        self.crashed = False
+        self.crashed = crashed
         self.writes = []
         self.cmd = cmd
         self.env = env

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/port/test.py (124957 => 124958)


--- trunk/Tools/Scripts/webkitpy/layout_tests/port/test.py	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/port/test.py	2012-08-08 01:08:48 UTC (rev 124958)
@@ -406,8 +406,8 @@
     def diff_image(self, expected_contents, actual_contents, tolerance=None):
         diffed = actual_contents != expected_contents
         if diffed:
-            return ["< %s\n---\n> %s\n" % (expected_contents, actual_contents), 1]
-        return (None, 0)
+            return ("< %s\n---\n> %s\n" % (expected_contents, actual_contents), 1, None)
+        return (None, 0, None)
 
     def layout_tests_dir(self):
         return LAYOUT_TEST_DIR

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py (124957 => 124958)


--- trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py	2012-08-08 01:06:45 UTC (rev 124957)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py	2012-08-08 01:08:48 UTC (rev 124958)
@@ -783,7 +783,7 @@
         class ImageDiffTestPort(TestPort):
             def diff_image(self, expected_contents, actual_contents, tolerance=None):
                 self.tolerance_used_for_diff_image = self._options.tolerance
-                return (True, 1)
+                return (True, 1, None)
 
         def get_port_for_run(args):
             options, parsed_args = run_webkit_tests.parse_args(args)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to