summaryrefslogtreecommitdiffstats
path: root/Tools/Scripts/webkitpy/common/net
diff options
context:
space:
mode:
authorSteve Block <steveblock@google.com>2011-05-18 13:36:51 +0100
committerSteve Block <steveblock@google.com>2011-05-24 15:38:28 +0100
commit2fc2651226baac27029e38c9d6ef883fa32084db (patch)
treee396d4bf89dcce6ed02071be66212495b1df1dec /Tools/Scripts/webkitpy/common/net
parentb3725cedeb43722b3b175aaeff70552e562d2c94 (diff)
downloadexternal_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.zip
external_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.tar.gz
external_webkit-2fc2651226baac27029e38c9d6ef883fa32084db.tar.bz2
Merge WebKit at r78450: Initial merge by git.
Change-Id: I6d3e5f1f868ec266a0aafdef66182ddc3f265dc1
Diffstat (limited to 'Tools/Scripts/webkitpy/common/net')
-rw-r--r--Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py5
-rw-r--r--Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py6
-rw-r--r--Tools/Scripts/webkitpy/common/net/irc/ircbot.py2
-rw-r--r--Tools/Scripts/webkitpy/common/net/layouttestresults.py4
-rw-r--r--Tools/Scripts/webkitpy/common/net/testoutput.py179
-rw-r--r--Tools/Scripts/webkitpy/common/net/testoutput_unittest.py133
-rw-r--r--Tools/Scripts/webkitpy/common/net/testoutputset.py130
-rw-r--r--Tools/Scripts/webkitpy/common/net/testoutputset_unittest.py125
8 files changed, 578 insertions, 6 deletions
diff --git a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
index 3cb6da5..76cd31d 100644
--- a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
+++ b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
@@ -266,10 +266,11 @@ class BuildBot(object):
# See https://bugs.webkit.org/show_bug.cgi?id=33296 and related bugs.
self.core_builder_names_regexps = [
"SnowLeopard.*Build",
- "SnowLeopard.*\(Test", # Exclude WebKit2 for now.
+ "SnowLeopard.*\(Test",
+ "SnowLeopard.*\(WebKit2 Test",
"Leopard",
- "Tiger",
"Windows.*Build",
+ "EFL",
"GTK.*32",
"GTK.*64.*Debug", # Disallow the 64-bit Release bot which is broken.
"Qt",
diff --git a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py
index 57290d1..f158827 100644
--- a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py
+++ b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py
@@ -222,7 +222,6 @@ class BuildBotTest(unittest.TestCase):
# For complete testing, this list should match the list of builders at build.webkit.org:
example_builders = [
- {'name': u'Tiger Intel Release', },
{'name': u'Leopard Intel Release (Build)', },
{'name': u'Leopard Intel Release (Tests)', },
{'name': u'Leopard Intel Debug (Build)', },
@@ -256,22 +255,23 @@ class BuildBotTest(unittest.TestCase):
name_regexps = [
"SnowLeopard.*Build",
"SnowLeopard.*\(Test",
+ "SnowLeopard.*\(WebKit2 Test",
"Leopard",
- "Tiger",
"Windows.*Build",
+ "EFL",
"GTK.*32",
"GTK.*64.*Debug", # Disallow the 64-bit Release bot which is broken.
"Qt",
"Chromium.*Release$",
]
expected_builders = [
- {'name': u'Tiger Intel Release', },
{'name': u'Leopard Intel Release (Build)', },
{'name': u'Leopard Intel Release (Tests)', },
{'name': u'Leopard Intel Debug (Build)', },
{'name': u'Leopard Intel Debug (Tests)', },
{'name': u'SnowLeopard Intel Release (Build)', },
{'name': u'SnowLeopard Intel Release (Tests)', },
+ {'name': u'SnowLeopard Intel Release (WebKit2 Tests)', },
{'name': u'Windows Release (Build)', },
{'name': u'Windows Debug (Build)', },
{'name': u'GTK Linux 32-bit Release', },
diff --git a/Tools/Scripts/webkitpy/common/net/irc/ircbot.py b/Tools/Scripts/webkitpy/common/net/irc/ircbot.py
index f742867..061a43c 100644
--- a/Tools/Scripts/webkitpy/common/net/irc/ircbot.py
+++ b/Tools/Scripts/webkitpy/common/net/irc/ircbot.py
@@ -26,7 +26,7 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-import webkitpy.common.config.irc as config_irc
+from webkitpy.common.config import irc as config_irc
from webkitpy.common.thread.messagepump import MessagePump, MessagePumpDelegate
from webkitpy.thirdparty.autoinstalled.irc import ircbot
diff --git a/Tools/Scripts/webkitpy/common/net/layouttestresults.py b/Tools/Scripts/webkitpy/common/net/layouttestresults.py
index 28caad4..249ecc9 100644
--- a/Tools/Scripts/webkitpy/common/net/layouttestresults.py
+++ b/Tools/Scripts/webkitpy/common/net/layouttestresults.py
@@ -51,11 +51,13 @@ class LayoutTestResults(object):
timeout_key = u'Tests that timed out:'
crash_key = u'Tests that caused the DumpRenderTree tool to crash:'
missing_key = u'Tests that had no expected results (probably new):'
+ webprocess_crash_key = u'Tests that caused the Web process to crash:'
expected_keys = [
stderr_key,
fail_key,
crash_key,
+ webprocess_crash_key,
timeout_key,
missing_key,
]
@@ -87,6 +89,8 @@ class LayoutTestResults(object):
return cls._failures_from_fail_row(row)
if table_title == cls.crash_key:
return [test_failures.FailureCrash()]
+ if table_title == cls.webprocess_crash_key:
+ return [test_failures.FailureCrash()]
if table_title == cls.timeout_key:
return [test_failures.FailureTimeout()]
if table_title == cls.missing_key:
diff --git a/Tools/Scripts/webkitpy/common/net/testoutput.py b/Tools/Scripts/webkitpy/common/net/testoutput.py
new file mode 100644
index 0000000..37c1445
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/testoutput.py
@@ -0,0 +1,179 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import re
+
+
+class NaiveImageDiffer(object):
+ def same_image(self, img1, img2):
+ return img1 == img2
+
+
+class TestOutput(object):
+ """Represents the output that a single layout test generates when it is run
+ on a particular platform.
+ Note that this is the raw output that is produced when the layout test is
+ run, not the results of the subsequent comparison between that output and
+ the expected output."""
+ def __init__(self, platform, output_type, files):
+ self._output_type = output_type
+ self._files = files
+ file = files[0] # Pick some file to do test name calculation.
+ self._name = self._extract_test_name(file.name())
+ self._is_actual = '-actual.' in file.name()
+
+ self._platform = platform or self._extract_platform(file.name())
+
+ def _extract_platform(self, filename):
+ """Calculates the platform from the name of the file if it isn't known already"""
+ path = re.split(os.path.sep, filename)
+ if 'platform' in path:
+ return path[path.index('platform') + 1]
+ return None
+
+ def _extract_test_name(self, filename):
+ path = re.split(os.path.sep, filename)
+ if 'LayoutTests' in path:
+ path = path[1 + path.index('LayoutTests'):]
+ if 'layout-test-results' in path:
+ path = path[1 + path.index('layout-test-results'):]
+ if 'platform' in path:
+ path = path[2 + path.index('platform'):]
+
+ filename = path[-1]
+ filename = re.sub('-expected\..*$', '', filename)
+ filename = re.sub('-actual\..*$', '', filename)
+ path[-1] = filename
+ return os.path.sep.join(path)
+
+ def save_to(self, path):
+ """Have the files in this TestOutput write themselves to the disk at the specified location."""
+ for file in self._files:
+ file.save_to(path)
+
+ def is_actual(self):
+ """Is this output the actual output of a test? (As opposed to expected output.)"""
+ return self._is_actual
+
+ def name(self):
+ """The name of this test (doesn't include extension)"""
+ return self._name
+
+ def __eq__(self, other):
+ return (other != None and
+ self.name() == other.name() and
+ self.type() == other.type() and
+ self.platform() == other.platform() and
+ self.is_actual() == other.is_actual() and
+ self.same_content(other))
+
+ def __hash__(self):
+ return hash(str(self.name()) + str(self.type()) + str(self.platform()))
+
+ def is_new_baseline_for(self, other):
+ return (self.name() == other.name() and
+ self.type() == other.type() and
+ self.platform() == other.platform() and
+ self.is_actual() and
+ (not other.is_actual()))
+
+ def __str__(self):
+ actual_str = '[A] ' if self.is_actual() else ''
+ return "TestOutput[%s/%s] %s%s" % (self._platform, self._output_type, actual_str, self.name())
+
+ def type(self):
+ return self._output_type
+
+ def platform(self):
+ return self._platform
+
+ def _path_to_platform(self):
+ """Returns the path that tests for this platform are stored in."""
+ if self._platform is None:
+ return ""
+ else:
+ return os.path.join("self._platform", self._platform)
+
+ def _save_expected_result(self, file, path):
+ path = os.path.join(path, self._path_to_platform())
+ extension = os.path.splitext(file.name())[1]
+ filename = self.name() + '-expected' + extension
+ file.save_to(path, filename)
+
+ def save_expected_results(self, path_to_layout_tests):
+ """Save the files of this TestOutput to the appropriate directory
+ inside the LayoutTests directory. Typically this means that these files
+ will be saved in "LayoutTests/platform/<platform>/, or simply
+ LayoutTests if the platform is None."""
+ for file in self._files:
+ self._save_expected_result(file, path_to_layout_tests)
+
+ def delete(self):
+ """Deletes the files that comprise this TestOutput from disk. This
+ fails if the files are virtual files (eg: the files may reside inside a
+ remote zip file)."""
+ for file in self._files:
+ file.delete()
+
+
+class TextTestOutput(TestOutput):
+ """Represents a text output of a single test on a single platform"""
+ def __init__(self, platform, text_file):
+ self._text_file = text_file
+ TestOutput.__init__(self, platform, 'text', [text_file])
+
+ def same_content(self, other):
+ return self._text_file.contents() == other._text_file.contents()
+
+ def retarget(self, platform):
+ return TextTestOutput(platform, self._text_file)
+
+
+class ImageTestOutput(TestOutput):
+ image_differ = NaiveImageDiffer()
+ """Represents an image output of a single test on a single platform"""
+ def __init__(self, platform, image_file, checksum_file):
+ self._checksum_file = checksum_file
+ self._image_file = image_file
+ files = filter(bool, [self._checksum_file, self._image_file])
+ TestOutput.__init__(self, platform, 'image', files)
+
+ def has_checksum(self):
+ return self._checksum_file is not None
+
+ def same_content(self, other):
+ # FIXME This should not assume that checksums are up to date.
+ if self.has_checksum() and other.has_checksum():
+ return self._checksum_file.contents() == other._checksum_file.contents()
+ else:
+ self_contents = self._image_file.contents()
+ other_contents = other._image_file.contents()
+ return ImageTestOutput.image_differ.same_image(self_contents, other_contents)
+
+ def retarget(self, platform):
+ return ImageTestOutput(platform, self._image_file, self._checksum_file)
+
+ def checksum(self):
+ return self._checksum_file.contents()
diff --git a/Tools/Scripts/webkitpy/common/net/testoutput_unittest.py b/Tools/Scripts/webkitpy/common/net/testoutput_unittest.py
new file mode 100644
index 0000000..ad38ca6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/testoutput_unittest.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import re
+import testoutput
+import unittest
+
+
+class FakeFile(object):
+ def __init__(self, filename, contents="fake contents"):
+ self._filename = filename
+ self._contents = contents
+
+ def name(self):
+ return self._filename
+
+ def contents(self):
+ return self._contents
+
+
+class FakeTestOutput(testoutput.TestOutput):
+ def __init__(self, platform, output_type, contents, is_expected=False):
+ self._output_type = output_type
+ self._contents = contents
+ self._is_expected = is_expected
+ actual = 'actual'
+ if is_expected:
+ actual = 'expected'
+ test_name = 'anonymous-test-%s.txt' % actual
+ file = FakeFile(test_name, contents)
+ super(FakeTestOutput, self).__init__(platform, output_type, [file])
+
+ def contents(self):
+ return self._contents
+
+ def retarget(self, platform):
+ return FakeTestOutput(platform, self._output_type, self._contents, self._is_expected)
+
+
+class TestOutputTest(unittest.TestCase):
+ def _check_name(self, filename, expected_test_name):
+ r = testoutput.TextTestOutput(None, FakeFile(filename))
+ self.assertEquals(expected_test_name, r.name())
+
+ def _check_platform(self, filename, expected_platform):
+ r = testoutput.TextTestOutput(None, FakeFile(filename))
+ self.assertEquals(expected_platform, r.platform())
+
+ def test_extracts_name_correctly(self):
+ self._check_name('LayoutTests/fast/dom/a-expected.txt', 'fast/dom/a')
+ self._check_name('LayoutTests/fast/dom/a-actual.txt', 'fast/dom/a')
+ self._check_name('LayoutTests/platform/win/fast/a-expected.txt', 'fast/a')
+ self._check_name('LayoutTests/platform/win/fast/a-expected.checksum', 'fast/a')
+ self._check_name('fast/dom/test-expected.txt', 'fast/dom/test')
+ self._check_name('layout-test-results/fast/a-actual.checksum', 'fast/a')
+
+ def test_extracts_platform_correctly(self):
+ self._check_platform('LayoutTests/platform/win/fast/a-expected.txt', 'win')
+ self._check_platform('platform/win/fast/a-expected.txt', 'win')
+ self._check_platform('platform/mac/fast/a-expected.txt', 'mac')
+ self._check_platform('fast/a-expected.txt', None)
+
+ def test_outputs_from_an_actual_file_are_marked_as_such(self):
+ r = testoutput.TextTestOutput(None, FakeFile('test-actual.txt'))
+ self.assertTrue(r.is_actual())
+
+ def test_outputs_from_an_expected_file_are_not_actual(self):
+ r = testoutput.TextTestOutput(None, FakeFile('test-expected.txt'))
+ self.assertFalse(r.is_actual())
+
+ def test_is_new_baseline_for(self):
+ expected = testoutput.TextTestOutput('mac', FakeFile('test-expected.txt'))
+ actual = testoutput.TextTestOutput('mac', FakeFile('test-actual.txt'))
+ self.assertTrue(actual.is_new_baseline_for(expected))
+ self.assertFalse(expected.is_new_baseline_for(actual))
+
+ def test__eq__(self):
+ r1 = testoutput.TextTestOutput('mac', FakeFile('test-expected.txt', 'contents'))
+ r2 = testoutput.TextTestOutput('mac', FakeFile('test-expected.txt', 'contents'))
+ r3 = testoutput.TextTestOutput('win', FakeFile('test-expected.txt', 'contents'))
+
+ self.assertEquals(r1, r2)
+ self.assertEquals(r1, r2.retarget('mac'))
+ self.assertNotEquals(r1, r2.retarget('win'))
+
+ def test__hash__(self):
+ r1 = testoutput.TextTestOutput('mac', FakeFile('test-expected.txt', 'contents'))
+ r2 = testoutput.TextTestOutput('mac', FakeFile('test-expected.txt', 'contents'))
+ r3 = testoutput.TextTestOutput(None, FakeFile('test-expected.txt', None))
+
+ x = set([r1, r2])
+ self.assertEquals(1, len(set([r1, r2])))
+ self.assertEquals(2, len(set([r1, r2, r3])))
+
+ def test_image_diff_is_invoked_for_image_outputs_without_checksum(self):
+ r1 = testoutput.ImageTestOutput('mac', FakeFile('test-expected.png', 'asdf'), FakeFile('test-expected.checksum', 'check'))
+ r2 = testoutput.ImageTestOutput('mac', FakeFile('test-expected.png', 'asdf'), None)
+
+ # Default behaviour is to just compare on image contents.
+ self.assertTrue(r1.same_content(r2))
+
+ class AllImagesAreDifferent(object):
+ def same_image(self, image1, image2):
+ return False
+
+ # But we can install other image differs.
+ testoutput.ImageTestOutput.image_differ = AllImagesAreDifferent()
+
+ self.assertFalse(r1.same_content(r2))
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/net/testoutputset.py b/Tools/Scripts/webkitpy/common/net/testoutputset.py
new file mode 100644
index 0000000..4074686
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/testoutputset.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitpy.common.system.directoryfileset import DirectoryFileSet
+from webkitpy.common.system.zipfileset import ZipFileSet
+import re
+import testoutput
+import urllib
+
+
+class TestOutputSet(object):
+ def __init__(self, name, platform, zip_file, **kwargs):
+ self._name = name
+ self._platform = platform
+ self._zip_file = zip_file
+ self._include_expected = kwargs.get('include_expected', True)
+
+ @classmethod
+ def from_zip_url(cls, platform, zip_path):
+ return TestOutputSet('local zip %s builder' % platform, platform, ZipFileSet(zip_path))
+
+ @classmethod
+ def from_zip(cls, platform, zip):
+ return TestOutputSet('local zip %s builder' % platform, platform, zip)
+
+ @classmethod
+ def from_zip_map(cls, zip_map):
+ output_sets = []
+ for k, v in zip_map.items():
+ output_sets.append(TestOutputSet.from_zip(k, v))
+ return AggregateTestOutputSet(output_sets)
+
+ @classmethod
+ def from_path(self, path, platform=None):
+ return TestOutputSet('local %s builder' % platform, platform, DirectoryFileSet(path))
+
+ def name(self):
+ return self._name
+
+ def set_platform(self, platform):
+ self._platform = platform
+
+ def files(self):
+ return [self._zip_file.open(filename) for filename in self._zip_file.namelist()]
+
+ def _extract_output_files(self, name, exact_match):
+ name_matcher = re.compile(name)
+ actual_matcher = re.compile(r'-actual\.')
+ expected_matcher = re.compile(r'-expected\.')
+
+ checksum_files = []
+ text_files = []
+ image_files = []
+ for output_file in self.files():
+ name_match = name_matcher.search(output_file.name())
+ actual_match = actual_matcher.search(output_file.name())
+ expected_match = expected_matcher.search(output_file.name())
+ if not (name_match and (actual_match or (self._include_expected and expected_match))):
+ continue
+ if output_file.name().endswith('.checksum'):
+ checksum_files.append(output_file)
+ elif output_file.name().endswith('.txt'):
+ text_files.append(output_file)
+ elif output_file.name().endswith('.png'):
+ image_files.append(output_file)
+
+ return (checksum_files, text_files, image_files)
+
+ def _extract_file_with_name(self, name, files):
+ for file in files:
+ if file.name() == name:
+ return file
+ return None
+
+ def _make_output_from_image(self, image_file, checksum_files):
+ checksum_file_name = re.sub('\.png', '.checksum', image_file.name())
+ checksum_file = self._extract_file_with_name(checksum_file_name, checksum_files)
+ return testoutput.ImageTestOutput(self._platform, image_file, checksum_file)
+
+ def outputs_for(self, name, **kwargs):
+ target_type = kwargs.get('target_type', None)
+ exact_match = kwargs.get('exact_match', False)
+ if re.search(r'\.x?html', name):
+ name = name[:name.rindex('.')]
+
+ (checksum_files, text_files, image_files) = self._extract_output_files(name, exact_match)
+
+ outputs = [self._make_output_from_image(image_file, checksum_files) for image_file in image_files]
+
+ outputs += [testoutput.TextTestOutput(self._platform, text_file) for text_file in text_files]
+
+ if exact_match:
+ outputs = filter(lambda output: output.name() == name, outputs)
+
+ outputs = filter(lambda r: target_type in [None, r.type()], outputs)
+
+ return outputs
+
+
+class AggregateTestOutputSet(object):
+ """Set of test outputs from a list of builders"""
+ def __init__(self, builders):
+ self._builders = builders
+
+ def outputs_for(self, name, **kwargs):
+ return sum([builder.outputs_for(name, **kwargs) for builder in self._builders], [])
+
+ def builders(self):
+ return self._builders
diff --git a/Tools/Scripts/webkitpy/common/net/testoutputset_unittest.py b/Tools/Scripts/webkitpy/common/net/testoutputset_unittest.py
new file mode 100644
index 0000000..a70a539
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/testoutputset_unittest.py
@@ -0,0 +1,125 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+from webkitpy.common.system.zip_mock import MockZip
+import testoutputset
+import unittest
+
+
+class TestOutputSetTest(unittest.TestCase):
+ def _outputset_with_zip(self, zip, **kwargs):
+ return testoutputset.TestOutputSet('<fake-outputset>', '<fake-platform>', zip, **kwargs)
+
+ def test_text_files_get_interpreted_as_text_outputs(self):
+ zip = MockZip()
+ zip.insert('fast/dom/some-test-actual.txt', 'actual outputs')
+ b = self._outputset_with_zip(zip)
+ self.assertEquals(1, len(b.outputs_for('fast/dom/some-test')))
+ self.assertEquals('fast/dom/some-test', b.outputs_for('fast/dom/some-test.html')[0].name())
+
+ def test_image_and_checksum_files_get_interpreted_as_a_single_image_output(self):
+ zip = MockZip()
+ zip.insert('fast/dom/some-test-actual.checksum', 'abc123')
+ zip.insert('fast/dom/some-test-actual.png', '<image data>')
+ b = self._outputset_with_zip(zip)
+ outputs = b.outputs_for('fast/dom/some-test')
+ self.assertEquals(1, len(outputs))
+ output = outputs[0]
+ self.assertEquals('image', output.type())
+ self.assertEquals('abc123', output.checksum())
+
+ def test_multiple_image_outputs_are_detected(self):
+ zip = MockZip()
+ zip.insert('platform/win/fast/dom/some-test-actual.checksum', 'checksum1')
+ zip.insert('platform/win/fast/dom/some-test-actual.png', '<image data 1>')
+ zip.insert('platform/mac/fast/dom/some-test-actual.checksum', 'checksum2')
+ zip.insert('platform/mac/fast/dom/some-test-actual.png', '<image data 2>')
+ b = self._outputset_with_zip(zip)
+ outputs = b.outputs_for('fast/dom/some-test')
+ self.assertEquals(2, len(outputs))
+ self.assertFalse(outputs[0].same_content(outputs[1]))
+
+ def test_aggregate_output_set_correctly_retrieves_tests_from_multiple_output_sets(self):
+ outputset1_zip = MockZip()
+ outputset1_zip.insert('fast/dom/test-actual.txt', 'linux text output')
+ outputset1 = testoutputset.TestOutputSet('linux-outputset', 'linux', outputset1_zip)
+ outputset2_zip = MockZip()
+ outputset2_zip.insert('fast/dom/test-actual.txt', 'windows text output')
+ outputset2 = testoutputset.TestOutputSet('win-outputset', 'win', outputset2_zip)
+
+ b = testoutputset.AggregateTestOutputSet([outputset1, outputset2])
+ self.assertEquals(2, len(b.outputs_for('fast/dom/test')))
+
+ def test_can_infer_platform_from_path_if_none_provided(self):
+ zip = MockZip()
+ zip.insert('platform/win/some-test-expected.png', '<image data>')
+ zip.insert('platform/win/some-test-expected.checksum', 'abc123')
+ b = testoutputset.TestOutputSet('local LayoutTests outputset', None, zip)
+
+ outputs = b.outputs_for('some-test')
+ self.assertEquals(1, len(outputs))
+ self.assertEquals('win', outputs[0].platform())
+
+ def test_test_extension_is_ignored(self):
+ zip = MockZip()
+ zip.insert('test/test-a-actual.txt', 'actual outputs')
+ b = self._outputset_with_zip(zip)
+ outputs = b.outputs_for('test/test-a.html')
+ self.assertEquals(1, len(outputs))
+ self.assertEquals('test/test-a', outputs[0].name())
+
+ def test_existing_outputs_are_marked_as_such(self):
+ zip = MockZip()
+ zip.insert('test/test-a-expected.txt', 'expected outputs')
+ b = self._outputset_with_zip(zip)
+ outputs = b.outputs_for('test/test-a.html')
+ self.assertEquals(1, len(outputs))
+ self.assertFalse(outputs[0].is_actual())
+
+ def test_only_returns_outputs_of_specified_type(self):
+ zip = MockZip()
+ zip.insert('test/test-a-expected.txt', 'expected outputs')
+ zip.insert('test/test-a-expected.checksum', 'expected outputs')
+ zip.insert('test/test-a-expected.png', 'expected outputs')
+ b = self._outputset_with_zip(zip)
+
+ outputs = b.outputs_for('test/test-a.html')
+ text_outputs = b.outputs_for('test/test-a.html', target_type='text')
+ image_outputs = b.outputs_for('test/test-a.html', target_type='image')
+
+ self.assertEquals(2, len(outputs))
+ self.assertEquals(1, len(text_outputs))
+ self.assertEquals(1, len(image_outputs))
+ self.assertEquals('text', text_outputs[0].type())
+ self.assertEquals('image', image_outputs[0].type())
+
+ def test_exclude_expected_outputs_works(self):
+ zip = MockZip()
+ zip.insert('test-expected.txt', 'expected outputs stored on server for some reason')
+ b = self._outputset_with_zip(zip, include_expected=False)
+ outputs = b.outputs_for('test', target_type=None)
+ self.assertEquals(0, len(outputs))
+
+if __name__ == "__main__":
+ unittest.main()