diff options
author | Steve Block <steveblock@google.com> | 2010-05-26 10:11:43 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2010-05-27 11:14:42 +0100 |
commit | e78cbe89e6f337f2f1fe40315be88f742b547151 (patch) | |
tree | d778000b84a04f24bbad50c7fa66244365e960e9 /WebKitTools/Scripts | |
parent | 7b582e96e4e909ed7dba1e07153d20fbddaec3f7 (diff) | |
download | external_webkit-e78cbe89e6f337f2f1fe40315be88f742b547151.zip external_webkit-e78cbe89e6f337f2f1fe40315be88f742b547151.tar.gz external_webkit-e78cbe89e6f337f2f1fe40315be88f742b547151.tar.bz2 |
Merge WebKit at r60074: Initial merge by git
Change-Id: I18a2dc5439e36c928351ea829d8fb4e39b062fc7
Diffstat (limited to 'WebKitTools/Scripts')
68 files changed, 1225 insertions, 249 deletions
diff --git a/WebKitTools/Scripts/VCSUtils.pm b/WebKitTools/Scripts/VCSUtils.pm index 41bbf40..24911ab 100644 --- a/WebKitTools/Scripts/VCSUtils.pm +++ b/WebKitTools/Scripts/VCSUtils.pm @@ -838,6 +838,81 @@ sub parseDiff($$) return (\@diffHashRefs, $line); } +# Parse an SVN property change diff from the given file handle, and advance +# the handle so the last line read is the first line after this diff. +# +# For the case of an SVN binary diff, the binary contents will follow the +# the property changes. +# +# This subroutine dies if the first line does not begin with "Property changes on" +# or if the separator line that follows this line is missing. +# +# Args: +# $fileHandle: advanced so the last line read from the handle is the first +# line of the footer to parse. This line begins with +# "Property changes on". +# $line: the line last read from $fileHandle. +# +# Returns ($propertyHashRef, $lastReadLine): +# $propertyHashRef: a hash reference representing an SVN diff footer. +# propertyPath: the path of the target file. +# executableBitDelta: the value 1 or -1 if the executable bit was added or +# removed from the target file, respectively. +# $lastReadLine: the line last read from $fileHandle. +# +# FIXME: This method is unused as of (05/22/2010). We will call this function +# as part of parsing a diff. See <https://bugs.webkit.org/show_bug.cgi?id=39409>. +sub parseSvnDiffProperties($$) +{ + my ($fileHandle, $line) = @_; + + $_ = $line; + + my $svnFooterDiffStartRegEx = qr#Property changes on: ([^\r\n]+)#; # $1 is normally the same as the index path. + + my %footer; + if (/$svnFooterDiffStartRegEx/) { + $footer{propertyPath} = $1; + } else { + die("Failed to find start of SVN property change, \"Property changes on \": \"$_\""); + } + + # We advance $fileHandle two lines so that the next line that + # we process is $svnPropertyStartRegEx in a well-formed footer. + # A well-formed footer has the form: + # Property changes on: FileA + # ___________________________________________________________________ + # Added: svn:executable + # + * + $_ = <$fileHandle>; # Not defined if end-of-file reached. + my $separator = "_" x 67; + if (defined($_) && /^$separator[\r\n]+$/) { + $_ = <$fileHandle>; + } else { + die("Failed to find separator line: \"$_\"."); + } + + # FIXME: We should expand this to support other SVN properties + # (e.g. return a hash of property key-values that represents + # all properties). + # + # Notice, we keep processing until we hit end-of-file or some + # line that does not resemble $svnPropertyStartRegEx, such as + # the empty line that precedes the start of the binary contents + # of a patch, or the start of the next diff (e.g. "Index:"). + my $propertyHashRef; + while (defined($_) && /$svnPropertyStartRegEx/) { + ($propertyHashRef, $_) = parseSvnProperty($fileHandle, $_); + if ($propertyHashRef->{name} eq "svn:executable") { + # Notice, for SVN properties, propertyChangeDelta is always non-zero + # because a property can only be added or removed. + $footer{executableBitDelta} = $propertyHashRef->{propertyChangeDelta}; + } + } + + return(\%footer, $_); +} + # Parse the next SVN property from the given file handle, and advance the handle so the last # line read is the first line after the property. # @@ -861,9 +936,6 @@ sub parseDiff($$) # propertyChangeDelta: the value 1 or -1 if the property was added or # removed, respectively. # $lastReadLine: the line last read from $fileHandle. -# -# FIXME: This method is unused as of (05/16/2010). We will call this function -# as part of parsing a SVN footer. See <https://bugs.webkit.org/show_bug.cgi?id=38885>. sub parseSvnProperty($$) { my ($fileHandle, $line) = @_; diff --git a/WebKitTools/Scripts/check-webkit-style b/WebKitTools/Scripts/check-webkit-style index f74c3bd..19d3762 100755 --- a/WebKitTools/Scripts/check-webkit-style +++ b/WebKitTools/Scripts/check-webkit-style @@ -50,7 +50,7 @@ import sys from webkitpy.style_references import detect_checkout import webkitpy.style.checker as checker -from webkitpy.style.checker import PatchReader +from webkitpy.style.patchreader import PatchReader from webkitpy.style.checker import StyleProcessor from webkitpy.style.filereader import TextFileReader from webkitpy.style.main import change_directory diff --git a/WebKitTools/Scripts/new-run-webkit-websocketserver b/WebKitTools/Scripts/new-run-webkit-websocketserver index 4f6deaa..3350582 100644 --- a/WebKitTools/Scripts/new-run-webkit-websocketserver +++ b/WebKitTools/Scripts/new-run-webkit-websocketserver @@ -91,7 +91,7 @@ def main(): if options.pidfile: kwds['pidfile'] = options.pidfile - port_obj = factory.get() + port_obj = factory.get(options=options) pywebsocket = websocket_server.PyWebSocket(port_obj, options.output_dir, **kwds) log_level = logging.WARN diff --git a/WebKitTools/Scripts/update-webkit b/WebKitTools/Scripts/update-webkit index 7602c41..3fc2efd 100755 --- a/WebKitTools/Scripts/update-webkit +++ b/WebKitTools/Scripts/update-webkit @@ -33,6 +33,7 @@ use strict; use FindBin; use lib $FindBin::Bin; use File::Basename; +use File::Path; use File::Spec; use Getopt::Long; use VCSUtils; @@ -67,6 +68,8 @@ __END__ exit 1; } +my $startTime = time(); + my @svnOptions = (); push @svnOptions, '-q' if $quiet; @@ -83,6 +86,13 @@ if (-d "../Internal") { runSvnUpdate() if $isSVN; runGitUpdate() if $isGit; } elsif (isChromium()) { + # Workaround for https://bugs.webkit.org/show_bug.cgi?id=38926 + # We should remove the following "if" block when we find a right fix. + if ((isCygwin() || isWindows()) && (stat("WebKit/chromium/features.gypi"))[9] >= $startTime) { + print "features.gypi has been updated. Cleaning the build directories.\n"; + rmtree(["WebKit/chromium/Debug", "WebKit/chromium/Release"]); + } + system("perl", "WebKitTools/Scripts/update-webkit-chromium") == 0 or die $!; } elsif (isAppleWinWebKit()) { system("perl", "WebKitTools/Scripts/update-webkit-auxiliary-libs") == 0 or die; diff --git a/WebKitTools/Scripts/webkit-patch b/WebKitTools/Scripts/webkit-patch index e0170ed..8300b9f 100755 --- a/WebKitTools/Scripts/webkit-patch +++ b/WebKitTools/Scripts/webkit-patch @@ -1,5 +1,5 @@ #!/usr/bin/env python -# Copyright (c) 2009, Google Inc. All rights reserved. +# Copyright (c) 2010 Google Inc. All rights reserved. # Copyright (c) 2009 Apple Inc. All rights reserved. # Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.org) # @@ -31,6 +31,7 @@ # # A tool for automating dealing with bugzilla, posting patches, committing patches, etc. +import logging import os import sys @@ -39,7 +40,14 @@ import webkitpy.python24.versioning as versioning def main(): - configure_logging() + # This is a hack to let us enable DEBUG logging as early as possible. + # Note this can't be ternary as versioning.check_version() + # hasn't run yet and this python might be older than 2.5. + if set(["-v", "--verbose"]).intersection(set(sys.argv)): + logging_level = logging.DEBUG + else: + logging_level = logging.INFO + configure_logging(logging_level=logging_level) versioning.check_version() diff --git a/WebKitTools/Scripts/webkitdirs.pm b/WebKitTools/Scripts/webkitdirs.pm index c512009..ca17757 100644 --- a/WebKitTools/Scripts/webkitdirs.pm +++ b/WebKitTools/Scripts/webkitdirs.pm @@ -1051,12 +1051,16 @@ sub setupCygwinEnv() sub dieIfWindowsPlatformSDKNotInstalled { - my $windowsPlatformSDKRegistryEntry = "/proc/registry/HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MicrosoftSDK/InstalledSDKs/D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1"; + my $registry32Path = "/proc/registry/"; + my $registry64Path = "/proc/registry64/"; + my $windowsPlatformSDKRegistryEntry = "HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MicrosoftSDK/InstalledSDKs/D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1"; - return if -e $windowsPlatformSDKRegistryEntry; + # FIXME: It would be better to detect whether we are using 32- or 64-bit Windows + # and only check the appropriate entry. But for now we just blindly check both. + return if (-e $registry32Path . $windowsPlatformSDKRegistryEntry) || (-e $registry64Path . $windowsPlatformSDKRegistryEntry); print "*************************************************************\n"; - print "Cannot find '$windowsPlatformSDKRegistryEntry'.\n"; + print "Cannot find registry entry '$windowsPlatformSDKRegistryEntry'.\n"; print "Please download and install the Microsoft Windows Server 2003 R2\n"; print "Platform SDK from <http://www.microsoft.com/downloads/details.aspx?\n"; print "familyid=0baf2b35-c656-4969-ace8-e4c0c0716adb&displaylang=en>.\n\n"; diff --git a/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffFooter.pl b/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffFooter.pl new file mode 100644 index 0000000..e305484 --- /dev/null +++ b/WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffFooter.pl @@ -0,0 +1,348 @@ +#!/usr/bin/perl -w +# +# Copyright (C) Research in Motion Limited 2010. All Rights Reserved. +# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Apple Computer, Inc. ("Apple") nor the names of +# its contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER OR 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. + +# Unit tests of parseSvnDiffProperties(). + +use strict; +use warnings; + +use Test::More; +use VCSUtils; + +my @testCaseHashRefs = ( +#### +# Simple test cases +## +{ + # New test + diffName => "simple: add svn:executable", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Added: svn:executable + + * +END + expectedReturn => [ +{ + propertyPath => "FileA", + executableBitDelta => 1, +}, +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "simple: delete svn:executable", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Deleted: svn:executable + - * +END + expectedReturn => [ +{ + propertyPath => "FileA", + executableBitDelta => -1, +}, +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "simple: delete svn:executable using SVN 1.4 syntax", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Name: svn:executable + - * +END + expectedReturn => [ +{ + propertyPath => "FileA", + executableBitDelta => -1, +}, +undef], + expectedNextLine => undef, +}, +#### +# Property value followed by empty line and start of next diff +## +{ + # New test + diffName => "add svn:executable, followed by empty line and start of next diff", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Added: svn:executable + + * + +Index: Makefile.shared +END + expectedReturn => [ +{ + propertyPath => "FileA", + executableBitDelta => 1, +}, +"\n"], + expectedNextLine => "Index: Makefile.shared\n", +}, +{ + # New test + diffName => "add svn:executable, followed by empty line and start of next property diff", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Added: svn:executable + + * + +Property changes on: Makefile.shared +END + expectedReturn => [ +{ + propertyPath => "FileA", + executableBitDelta => 1, +}, +"\n"], + expectedNextLine => "Property changes on: Makefile.shared\n", +}, +#### +# Property value followed by empty line and start of the binary contents +## +{ + # New test + diffName => "add svn:executable, followed by empty line and start of binary contents", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Added: svn:executable + + * + +Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== +END + expectedReturn => [ +{ + propertyPath => "FileA", + executableBitDelta => 1, +}, +"\n"], + expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\n", +}, +{ + # New test + diffName => "custom property followed by svn:executable, empty line and start of binary contents", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Added: documentation + + This is an example sentence. +Added: svn:executable + + * + +Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA== +END + expectedReturn => [ +{ + propertyPath => "FileA", + executableBitDelta => 1, +}, +"\n"], + expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\n", +}, +#### +# Successive properties +## +{ + # New test + diffName => "svn:executable followed by custom property", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Added: svn:executable + + * +Added: documentation + + This is an example sentence. +END + expectedReturn => [ +{ + propertyPath => "FileA", + executableBitDelta => 1, +}, +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "custom property followed by svn:executable", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Added: documentation + + This is an example sentence. +Added: svn:executable + + * +END + expectedReturn => [ +{ + propertyPath => "FileA", + executableBitDelta => 1, +}, +undef], + expectedNextLine => undef, +}, +#### +# Successive properties followed by empty line and start of next diff +## +{ + # New test + diffName => "custom property followed by svn:executable, empty line and start of next property diff", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Added: documentation + + This is an example sentence. +Added: svn:executable + + * + +Property changes on: Makefile.shared +END + expectedReturn => [ +{ + propertyPath => "FileA", + executableBitDelta => 1, +}, +"\n"], + expectedNextLine => "Property changes on: Makefile.shared\n", +}, +{ + # New test + diffName => "custom property followed by svn:executable, empty line and start of next index diff", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Added: documentation + + This is an example sentence. +Added: svn:executable + + * + +Index: Makefile.shared +END + expectedReturn => [ +{ + propertyPath => "FileA", + executableBitDelta => 1, +}, +"\n"], + expectedNextLine => "Index: Makefile.shared\n", +}, +#### +# Custom properties +## +# FIXME: We do not support anything other than the svn:executable property. +# We should add support for handling other properties. +{ + # New test + diffName => "simple: custom property", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Name: documentation + + This is an example sentence. +END + expectedReturn => [ +{ + propertyPath => "FileA", +}, +undef], + expectedNextLine => undef, +}, +{ + # New test + diffName => "custom property followed by custom property", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Added: copyright + + Copyright (C) Research in Motion Limited 2010. All Rights Reserved. +Added: documentation + + This is an example sentence. +END + expectedReturn => [ +{ + propertyPath => "FileA", +}, +undef], + expectedNextLine => undef, +}, +#### +# Malformed property diffs +## +# We shouldn't encounter such diffs in practice. +{ + # New test + diffName => "svn:executable followed by custom property and svn:executable", + inputText => <<'END', +Property changes on: FileA +___________________________________________________________________ +Added: svn:executable + + * +Added: documentation + + This is an example sentence. +Deleted: svn:executable + - * +END + expectedReturn => [ +{ + propertyPath => "FileA", + executableBitDelta => -1, +}, +undef], + expectedNextLine => undef, +}, +); + +my $testCasesCount = @testCaseHashRefs; +plan(tests => 2 * $testCasesCount); # Total number of assertions. + +foreach my $testCase (@testCaseHashRefs) { + my $testNameStart = "parseSvnDiffProperties(): $testCase->{diffName}: comparing"; + + my $fileHandle; + open($fileHandle, "<", \$testCase->{inputText}); + my $line = <$fileHandle>; + + my @got = VCSUtils::parseSvnDiffProperties($fileHandle, $line); + my $expectedReturn = $testCase->{expectedReturn}; + + is_deeply(\@got, $expectedReturn, "$testNameStart return value."); + + my $gotNextLine = <$fileHandle>; + is($gotNextLine, $testCase->{expectedNextLine}, "$testNameStart next read line."); +} diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/scm.py b/WebKitTools/Scripts/webkitpy/common/checkout/scm.py index ac9c42e..e68ccfa 100644 --- a/WebKitTools/Scripts/webkitpy/common/checkout/scm.py +++ b/WebKitTools/Scripts/webkitpy/common/checkout/scm.py @@ -584,25 +584,32 @@ class Git(SCM): def revert_files(self, file_paths): self.run(['git', 'checkout', 'HEAD'] + file_paths) + def _get_squash_error_message(self, num_local_commits): + working_directory_message = "" if self.working_directory_is_clean() else " and working copy changes" + return ("""There are %s local commits%s. Do one of the following: + 1) Use --squash or --no-squash + 2) git config webkit-patch.squash true/false + """ % (num_local_commits, working_directory_message)) + def should_squash(self, squash): - if squash is not None: - # Squash is specified on the command-line. - return squash - - config_squash = Git.read_git_config('webkit-patch.squash') - if (config_squash and config_squash is not ""): - return config_squash.lower() == "true" - - # Only raise an error if there are actually multiple commits to squash. - num_local_commits = len(self.local_commits()) - if num_local_commits > 1 or num_local_commits > 0 and not self.working_directory_is_clean(): - working_directory_message = "" if self.working_directory_is_clean() else " and working copy changes" - raise ScriptError(message="""There are %s local commits%s. Do one of the following: -1) Use --squash or --no-squash -2) git config webkit-patch.squash true/false -""" % (num_local_commits, working_directory_message)) - - return None + if squash is None: + config_squash = Git.read_git_config('webkit-patch.squash') + if (config_squash and config_squash is not ""): + squash = config_squash.lower() == "true" + else: + # Only raise an error if there are actually multiple commits to squash. + num_local_commits = len(self.local_commits()) + if num_local_commits > 1 or (num_local_commits > 0 and not self.working_directory_is_clean()): + raise ScriptError(message=self._get_squash_error_message(num_local_commits)) + + if squash and self._svn_branch_has_extra_commits(): + raise ScriptError(message="Cannot use --squash when HEAD is not fully merged/rebased to %s. " + "This branch needs to be synced first." % self.svn_branch_name()) + + return squash + + def _svn_branch_has_extra_commits(self): + return len(run_command(['git', 'rev-list', '--max-count=1', self.svn_branch_name(), '^head'])) def commit_with_message(self, message, username=None, git_commit=None, squash=None): # Username is ignored during Git commits. diff --git a/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py b/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py index 5a2c094..b6ae388 100644 --- a/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py +++ b/WebKitTools/Scripts/webkitpy/common/checkout/scm_unittest.py @@ -875,6 +875,12 @@ class GitTest(SCMTest): self.assertTrue(re.search(r'test_file_commit2', svn_log)) self.assertTrue(re.search(r'test_file_commit1', svn_log)) + def test_commit_with_message_not_synced_squash(self): + run_command(['git', 'checkout', '-b', 'my-branch', 'trunk~3']) + self._two_local_commits() + scm = detect_scm_system(self.git_checkout_path) + self.assertRaises(ScriptError, scm.commit_with_message, "another test commit", squash=True) + def test_reverse_diff(self): self._shared_test_reverse_diff() @@ -937,6 +943,12 @@ class GitTest(SCMTest): self.assertTrue(re.search(r'test_file_commit2', patch)) self.assertTrue(re.search(r'test_file_commit1', patch)) + def test_create_patch_not_synced_squash(self): + run_command(['git', 'checkout', '-b', 'my-branch', 'trunk~3']) + self._two_local_commits() + scm = detect_scm_system(self.git_checkout_path) + self.assertRaises(ScriptError, scm.create_patch, squash=True) + def test_create_binary_patch(self): # Create a git binary patch and check the contents. scm = detect_scm_system(self.git_checkout_path) @@ -1016,6 +1028,12 @@ class GitTest(SCMTest): self.assertTrue('test_file_commit2' in files) self.assertTrue('test_file_commit1' in files) + def test_changed_files_not_synced_squash(self): + run_command(['git', 'checkout', '-b', 'my-branch', 'trunk~3']) + self._two_local_commits() + scm = detect_scm_system(self.git_checkout_path) + self.assertRaises(ScriptError, scm.changed_files, squash=True) + def test_changed_files(self): self._shared_test_changed_files() diff --git a/WebKitTools/Scripts/webkitpy/common/config/committers.py b/WebKitTools/Scripts/webkitpy/common/config/committers.py index c33d2a6..02f1aed 100644 --- a/WebKitTools/Scripts/webkitpy/common/config/committers.py +++ b/WebKitTools/Scripts/webkitpy/common/config/committers.py @@ -85,6 +85,7 @@ committers_unable_to_review = [ Committer("Cameron McCormack", "cam@webkit.org", "heycam"), Committer("Carol Szabo", "carol.szabo@nokia.com"), Committer("Chang Shu", "Chang.Shu@nokia.com"), + Committer("Chris Evans", "cevans@google.com"), Committer("Chris Fleizach", "cfleizach@apple.com"), Committer("Chris Marrin", "cmarrin@apple.com", "cmarrin"), Committer("Chris Petersen", "cpetersen@apple.com", "cpetersen"), @@ -163,7 +164,7 @@ committers_unable_to_review = [ Committer("Xiaomei Ji", "xji@chromium.org", "xji"), Committer("Yael Aharon", "yael.aharon@nokia.com"), Committer("Yaar Schnitman", ["yaar@chromium.org", "yaar@google.com"]), - Committer("Yong Li", ["yong.li@torchmobile.com", "yong.li.webkit@gmail.com"], "yong"), + Committer("Yong Li", ["yong.li.webkit@gmail.com", "yong.li@torchmobile.com"], "yong"), Committer("Yongjun Zhang", "yongjun.zhang@nokia.com"), Committer("Yuzo Fujishima", "yuzo@google.com", "yuzo"), Committer("Zoltan Herczeg", "zherczeg@webkit.org", "zherczeg"), diff --git a/WebKitTools/Scripts/webkitpy/common/net/bugzilla.py b/WebKitTools/Scripts/webkitpy/common/net/bugzilla.py index 074a021..26d3652 100644 --- a/WebKitTools/Scripts/webkitpy/common/net/bugzilla.py +++ b/WebKitTools/Scripts/webkitpy/common/net/bugzilla.py @@ -104,6 +104,9 @@ class Attachment(object): def name(self): return self._attachment_dictionary.get("name") + def attach_date(self): + return self._attachment_dictionary.get("attach_date") + def review(self): return self._attachment_dictionary.get("review") @@ -430,6 +433,7 @@ class Bugzilla(object): attachment[flag_name] = flag['status'] if flag['status'] == '+': attachment[result_key] = flag['setter'] + # Sadly show_bug.cgi?ctype=xml does not expose the flag modification date. def _string_contents(self, soup): # WebKit's bugzilla instance uses UTF-8. @@ -439,8 +443,23 @@ class Bugzilla(object): # convert from NavigableString to a real unicode() object using unicode(). return unicode(soup.string) - def _parse_attachment_element(self, element, bug_id): + # Example: 2010-01-20 14:31 PST + # FIXME: Some bugzilla dates seem to have seconds in them? + # Python does not support timezones out of the box. + # Assume that bugzilla always uses PST (which is true for bugs.webkit.org) + _bugzilla_date_format = "%Y-%m-%d %H:%M" + + @classmethod + def _parse_date(cls, date_string): + (date, time, time_zone) = date_string.split(" ") + # Ignore the timezone because python doesn't understand timezones out of the box. + date_string = "%s %s" % (date, time) + return datetime.strptime(date_string, cls._bugzilla_date_format) + def _date_contents(self, soup): + return self._parse_date(self._string_contents(soup)) + + def _parse_attachment_element(self, element, bug_id): attachment = {} attachment['bug_id'] = bug_id attachment['is_obsolete'] = (element.has_key('isobsolete') and element['isobsolete'] == "1") @@ -448,6 +467,7 @@ class Bugzilla(object): attachment['id'] = int(element.find('attachid').string) # FIXME: No need to parse out the url here. attachment['url'] = self.attachment_url_for_id(attachment['id']) + attachment["attach_date"] = self._date_contents(element.find("date")) attachment['name'] = self._string_contents(element.find('desc')) attachment['attacher_email'] = self._string_contents(element.find('attacher')) attachment['type'] = self._string_contents(element.find('type')) @@ -564,6 +584,7 @@ class Bugzilla(object): raise Exception(errorMessage) else: self.authenticated = True + self.username = username def _fill_attachment_form(self, description, @@ -657,6 +678,7 @@ class Bugzilla(object): patch_description=None, cc=None, blocked=None, + assignee=None, mark_for_review=False, mark_for_commit_queue=False): self.authenticate() @@ -679,6 +701,10 @@ class Bugzilla(object): self.browser["cc"] = cc if blocked: self.browser["blocked"] = unicode(blocked) + if assignee == None: + assignee = self.username + if assignee: + self.browser["assigned_to"] = assignee self.browser["short_desc"] = bug_title self.browser["comment"] = bug_description diff --git a/WebKitTools/Scripts/webkitpy/common/net/bugzilla_unittest.py b/WebKitTools/Scripts/webkitpy/common/net/bugzilla_unittest.py index 62a0746..ce992e7 100644 --- a/WebKitTools/Scripts/webkitpy/common/net/bugzilla_unittest.py +++ b/WebKitTools/Scripts/webkitpy/common/net/bugzilla_unittest.py @@ -28,6 +28,8 @@ import unittest +import datetime + from webkitpy.common.config.committers import CommitterList, Reviewer, Committer from webkitpy.common.net.bugzilla import Bugzilla, BugzillaQueries, parse_bug_id, CommitterValidator, Bug from webkitpy.common.system.outputcapture import OutputCapture @@ -97,6 +99,7 @@ class BugzillaTest(unittest.TestCase): </attachment> ''' _expected_example_attachment_parsing = { + 'attach_date': datetime.datetime(2009, 07, 29, 10, 23), 'bug_id' : 100, 'is_obsolete' : True, 'is_patch' : True, @@ -204,6 +207,7 @@ ZEZpbmlzaExvYWRXaXRoUmVhc29uOnJlYXNvbl07Cit9CisKIEBlbmQKIAogI2VuZGlmCg== "reporter_email" : "eric@webkit.org", "assigned_to_email" : "webkit-unassigned@lists.webkit.org", "attachments" : [{ + "attach_date": datetime.datetime(2009, 12, 27, 23, 51), 'name': u'Patch', 'url' : "https://bugs.webkit.org/attachment.cgi?id=45548", 'is_obsolete': False, diff --git a/WebKitTools/Scripts/webkitpy/common/net/statusserver.py b/WebKitTools/Scripts/webkitpy/common/net/statusserver.py index d9b52a2..0bd68d1 100644 --- a/WebKitTools/Scripts/webkitpy/common/net/statusserver.py +++ b/WebKitTools/Scripts/webkitpy/common/net/statusserver.py @@ -31,9 +31,13 @@ from webkitpy.common.system.deprecated_logging import log from webkitpy.thirdparty.autoinstalled.mechanize import Browser from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup +import logging import urllib2 +_log = logging.getLogger("webkitpy.common.net.statusserver") + + class StatusServer: default_host = "webkit-commit-queue.appspot.com" @@ -83,6 +87,19 @@ class StatusServer: self.browser["broken_bot"] = broken_bot return self.browser.submit().read() + def _post_work_items_to_server(self, queue_name, work_items): + update_work_items_url = "%s/update-work-items" % self.url + self.browser.open(update_work_items_url) + self.browser.select_form(name="update_work_items") + self.browser["queue_name"] = queue_name + work_items = map(unicode, work_items) # .join expects strings + self.browser["work_items"] = " ".join(work_items) + return self.browser.submit().read() + + def update_work_items(self, queue_name, work_items): + _log.debug("Recording work items: %s for %s" % (work_items, queue_name)) + return NetworkTransaction().run(lambda: self._post_work_items_to_server(queue_name, work_items)) + def update_status(self, queue_name, status, patch=None, results_file=None): log(status) return NetworkTransaction().run(lambda: self._post_status_to_server(queue_name, status, patch, results_file)) diff --git a/WebKitTools/Scripts/webkitpy/common/system/executive.py b/WebKitTools/Scripts/webkitpy/common/system/executive.py index c7a7aec..9c5889b 100644 --- a/WebKitTools/Scripts/webkitpy/common/system/executive.py +++ b/WebKitTools/Scripts/webkitpy/common/system/executive.py @@ -41,6 +41,7 @@ import StringIO import signal import subprocess import sys +import time from webkitpy.common.system.deprecated_logging import tee @@ -255,6 +256,18 @@ class Executive(object): input = input.encode("utf-8") return (subprocess.PIPE, input) + def _command_for_printing(self, args): + """Returns a print-ready string representing command args. + The string should be copy/paste ready for execution in a shell.""" + escaped_args = [] + for arg in args: + if isinstance(arg, unicode): + # Escape any non-ascii characters for easy copy/paste + arg = arg.encode("unicode_escape") + # FIXME: Do we need to fix quotes here? + escaped_args.append(arg) + return " ".join(escaped_args) + # FIXME: run_and_throw_if_fail should be merged into this method. def run_command(self, args, @@ -265,6 +278,8 @@ class Executive(object): return_stderr=True, decode_output=True): """Popen wrapper for convenience and to work around python bugs.""" + assert(isinstance(args, list) or isinstance(args, tuple)) + start_time = time.time() args = map(unicode, args) # Popen will throw an exception if args are non-strings (like int()) stdin, string_to_communicate = self._compute_stdin(input) stderr = subprocess.STDOUT if return_stderr else None @@ -283,6 +298,8 @@ class Executive(object): # http://bugs.python.org/issue1731717 exit_code = process.wait() + _log.debug('"%s" took %.2fs' % (self._command_for_printing(args), time.time() - start_time)) + if return_exit_code: return exit_code diff --git a/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py b/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py index 30468ce..32f8f51 100644 --- a/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py +++ b/WebKitTools/Scripts/webkitpy/common/system/executive_unittest.py @@ -32,7 +32,7 @@ import subprocess import sys import unittest -from webkitpy.common.system.executive import Executive, run_command +from webkitpy.common.system.executive import Executive, run_command, ScriptError class ExecutiveTest(unittest.TestCase): @@ -42,6 +42,13 @@ class ExecutiveTest(unittest.TestCase): run_command(["foo_bar_command_blah"], error_handler=Executive.ignore_error, return_exit_code=True) self.failUnlessRaises(OSError, run_bad_command) + def test_run_command_args_type(self): + executive = Executive() + self.assertRaises(AssertionError, executive.run_command, "echo") + self.assertRaises(AssertionError, executive.run_command, u"echo") + executive.run_command(["echo", "foo"]) + executive.run_command(("echo", "foo")) + def test_run_command_with_unicode(self): """Validate that it is safe to pass unicode() objects to Executive.run* methods, and they will return unicode() diff --git a/WebKitTools/Scripts/webkitpy/common/system/user.py b/WebKitTools/Scripts/webkitpy/common/system/user.py index edce93d..4fa2fa3 100644 --- a/WebKitTools/Scripts/webkitpy/common/system/user.py +++ b/WebKitTools/Scripts/webkitpy/common/system/user.py @@ -30,6 +30,7 @@ import logging import os import shlex import subprocess +import sys import webbrowser diff --git a/WebKitTools/Scripts/webkitpy/common/thread/threadedmessagequeue.py b/WebKitTools/Scripts/webkitpy/common/thread/threadedmessagequeue.py index 6cb6f8c..17b6277 100644 --- a/WebKitTools/Scripts/webkitpy/common/thread/threadedmessagequeue.py +++ b/WebKitTools/Scripts/webkitpy/common/thread/threadedmessagequeue.py @@ -26,6 +26,8 @@ # (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 __future__ import with_statement + import threading @@ -36,20 +38,17 @@ class ThreadedMessageQueue(object): self._lock = threading.Lock() def post(self, message): - self._lock.acquire() - self._messages.append(message) - self._lock.release() + with self._lock: + self._messages.append(message) def stop(self): - self._lock.acquire() - self._is_running = False - self._lock.release() + with self._lock: + self._is_running = False def take_all(self): - self._lock.acquire() - messages = self._messages - is_running = self._is_running - self._messages = [] - self._lock.release() + with self._lock: + messages = self._messages + is_running = self._is_running + self._messages = [] return (messages, is_running) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-bg.html b/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-bg.html new file mode 100644 index 0000000..2022676 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-bg.html @@ -0,0 +1,22 @@ +<html> + <head> + <style> + div { background: -webkit-canvas(squares); width:600px; height:600px; border:2px solid black } + </style> + + <script type="application/x-javascript"> +function draw(w, h) { + var ctx = document.getCSSCanvasContext("2d", "squares", w, h); + + ctx.fillStyle = "rgb(200,0,0)"; + ctx.fillRect (10, 10, 55, 50); + + ctx.fillStyle = "rgba(0, 0, 200, 0.5)"; + ctx.fillRect (30, 30, 55, 50); +} + </script> + </head> + <body onload="draw(300, 300)"> + <div></div> + </body> +</html>
\ No newline at end of file diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.checksum b/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.checksum new file mode 100644 index 0000000..7373fe2 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.checksum @@ -0,0 +1 @@ +afa0f2d246120c180005d67d47636b92
\ No newline at end of file diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.png b/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.png Binary files differnew file mode 100644 index 0000000..44952b4 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.png diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.txt b/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.txt new file mode 100644 index 0000000..288458d --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.txt @@ -0,0 +1,22 @@ +layer at (0,0) size 800x600 + RenderView at (0,0) size 800x600 +layer at (0,0) size 800x600 + RenderBlock {HTML} at (0,0) size 800x600 + RenderBody {BODY} at (8,8) size 784x584 + RenderBlock {P} at (0,0) size 784x18 + RenderText {#text} at (0,0) size 624x18 + text run at (0,0) width 624: "These should be four green hollow boxes with dimensions 600x300, 100x300, 600x100, 100x100." + RenderBlock (anonymous) at (0,34) size 784x420 + RenderHTMLCanvas {CANVAS} at (0,0) size 606x306 [border: (3px solid #008000)] + RenderText {#text} at (606,292) size 4x18 + text run at (606,292) width 4: " " + RenderText {#text} at (0,0) size 0x0 + RenderHTMLCanvas {CANVAS} at (610,0) size 106x306 [border: (3px solid #008000)] + RenderText {#text} at (0,0) size 0x0 + RenderText {#text} at (0,0) size 0x0 + RenderHTMLCanvas {CANVAS} at (0,310) size 606x106 [border: (3px solid #008000)] + RenderText {#text} at (606,402) size 4x18 + text run at (606,402) width 4: " " + RenderText {#text} at (0,0) size 0x0 + RenderHTMLCanvas {CANVAS} at (610,310) size 106x106 [border: (3px solid #008000)] + RenderText {#text} at (0,0) size 0x0 diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-zoom.html b/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-zoom.html new file mode 100644 index 0000000..4dabce1 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/image/canvas-zoom.html @@ -0,0 +1,15 @@ +<style> + canvas { border: solid green; + zoom: 2; } +</style> +<p> + These should be four green hollow boxes with dimensions 600x300, 100x300, 600x100, 100x100. +</p> +<!-- 300x150 --> +<canvas id="canvas"></canvas> +<!-- 50x150 --> +<canvas id="canvas" width="50"></canvas> +<!-- 300x50 --> +<canvas id="canvas" height="50"></canvas> +<!-- 50x50 --> +<canvas id="canvas" width="50" height="50"></canvas> diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/crash-expected.txt b/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/crash-expected.txt new file mode 100644 index 0000000..521c3f5 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/crash-expected.txt @@ -0,0 +1 @@ +This test is expected to crash. diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/crash.html b/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/crash.html new file mode 100644 index 0000000..b9820d6 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/crash.html @@ -0,0 +1,5 @@ +<html> +<body> +This test is expected to crash. +</body> +</html> diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/missing-expectation.html b/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/missing-expectation.html new file mode 100644 index 0000000..1f00b50 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/missing-expectation.html @@ -0,0 +1,5 @@ +<html> +<body> +This test intentionally doesn't have an expected result checked in. +</body> +</html> diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/passing-expected.txt b/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/passing-expected.txt new file mode 100644 index 0000000..26bd316 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/passing-expected.txt @@ -0,0 +1 @@ +This test is expected to pass. diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/passing.html b/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/passing.html new file mode 100644 index 0000000..db7e3de --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/misc/passing.html @@ -0,0 +1,5 @@ +<html> +<body> +This test is expected to pass. +</body> +</html> diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.checksum b/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.checksum new file mode 100644 index 0000000..4cd8dac --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.checksum @@ -0,0 +1 @@ +790b681a41697634fcf2a2587afb89c6
\ No newline at end of file diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.png b/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.png Binary files differnew file mode 100644 index 0000000..3d00450 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.png diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.txt b/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.txt new file mode 100644 index 0000000..2411c0a --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.txt @@ -0,0 +1,6 @@ +layer at (0,0) size 785x620 + RenderView at (0,0) size 785x600 +layer at (0,0) size 785x620 + RenderBlock {HTML} at (0,0) size 785x620 + RenderBody {BODY} at (8,8) size 769x604 + RenderBlock {DIV} at (0,0) size 604x604 [border: (2px solid #000000)] diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt b/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt new file mode 100644 index 0000000..b78a01c --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt @@ -0,0 +1 @@ +WONTFIX : misc/missing-expectation.html = MISSING PASS diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/text/article-element-expected.txt b/WebKitTools/Scripts/webkitpy/layout_tests/data/text/article-element-expected.txt new file mode 100644 index 0000000..f60ac38 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/text/article-element-expected.txt @@ -0,0 +1,20 @@ +Various tests for the article element. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +<article> closes <p>: +PASS article1.parentNode.nodeName == "p" is false +<p> does not close <article>: +PASS p1.parentNode.nodeName is "ARTICLE" +<article> can be nested inside <article>: +PASS article3.parentNode.id is "article2" +Residual style: +PASS getWeight("article4") is "bold" +PASS getWeight("span1") is "bold" +FormatBlock: +PASS document.getElementById("span2").parentNode.nodeName is "ARTICLE" +PASS successfullyParsed is true + +TEST COMPLETE + diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/data/text/article-element.html b/WebKitTools/Scripts/webkitpy/layout_tests/data/text/article-element.html new file mode 100644 index 0000000..c0f4547 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/data/text/article-element.html @@ -0,0 +1,13 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<html> +<head> +<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css"> +<script src="../../fast/js/resources/js-test-pre.js"></script> +</head> +<body> +<p id="description"></p> +<div id="console"></div> +<script src="script-tests/article-element.js"></script> +<script src="../../fast/js/resources/js-test-post.js"></script> +</body> +</html> diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py index 6957fcd..09f9ac7 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py @@ -425,7 +425,8 @@ class TestShellThread(threading.Thread): # are generating a new baseline. (Otherwise, an image from a # previous run will be copied into the baseline.) image_hash = test_info.image_hash() - if image_hash and self._test_args.new_baseline: + if (image_hash and + (self._test_args.new_baseline or self._test_args.reset_results)): image_hash = "" start = time.time() crash, timeout, actual_checksum, output, error = \ diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py index dba1194..3804210 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py @@ -239,6 +239,8 @@ class Testprinter(unittest.TestCase): def test_print_test_result(self): result = get_result('foo.html') printer, err, out = self.get_printer(['--print', 'nothing']) + result = get_result(os.path.join(self._port.layout_tests_dir(), + 'foo.html')) printer.print_test_result(result, expected=False, exp_str='', got_str='') self.assertTrue(err.empty()) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py index d11f3e2..cf3c560 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py @@ -98,19 +98,18 @@ class TestExpectationsTest(unittest.TestCase): return os.path.join(self._port.layout_tests_dir(), test_name) def get_basic_tests(self): - return [self.get_test('fast/html/article-element.html'), - self.get_test('fast/html/header-element.html'), - self.get_test('fast/html/keygen.html'), - self.get_test('fast/html/tab-order.html'), - self.get_test('fast/events/space-scroll-event.html'), - self.get_test('fast/events/tab-imagemap.html')] + return [self.get_test('text/article-element.html'), + self.get_test('image/canvas-bg.html'), + self.get_test('image/canvas-zoom.html'), + self.get_test('misc/crash.html'), + self.get_test('misc/passing.html')] def get_basic_expectations(self): return """ -BUG_TEST : fast/html/article-element.html = TEXT -BUG_TEST SKIP : fast/html/keygen.html = CRASH -BUG_TEST REBASELINE : fast/htmltab-order.html = MISSING -BUG_TEST : fast/events = IMAGE +BUG_TEST : text/article-element.html = TEXT +BUG_TEST SKIP : misc/crash.html = CRASH +BUG_TEST REBASELINE : misc/missing-expectation.html = MISSING +BUG_TEST : image = IMAGE """ def parse_exp(self, expectations, overrides=None): @@ -128,42 +127,42 @@ BUG_TEST : fast/events = IMAGE set([result])) def test_basic(self): - self.parse_exp(self.get_basic_expectations()) - self.assert_exp('fast/html/article-element.html', TEXT) - self.assert_exp('fast/events/tab-imagemap.html', IMAGE) - self.assert_exp('fast/html/header-element.html', PASS) + self.parse_exp(self.get_basic_expectations()) + self.assert_exp('text/article-element.html', TEXT) + self.assert_exp('image/canvas-zoom.html', IMAGE) + self.assert_exp('misc/passing.html', PASS) def test_duplicates(self): - self.assertRaises(SyntaxError, self.parse_exp, """ -BUG_TEST : fast/html/article-element.html = TEXT -BUG_TEST : fast/html/article-element.html = IMAGE""") - self.assertRaises(SyntaxError, self.parse_exp, - self.get_basic_expectations(), """ -BUG_TEST : fast/html/article-element.html = TEXT -BUG_TEST : fast/html/article-element.html = IMAGE""") + self.assertRaises(SyntaxError, self.parse_exp, """ +BUG_TEST : text/article-element.html = TEXT +BUG_TEST : text/article-element.html = IMAGE""") + self.assertRaises(SyntaxError, self.parse_exp, + self.get_basic_expectations(), """ +BUG_TEST : text/article-element.html = TEXT +BUG_TEST : text/article-element.html = IMAGE""") def test_overrides(self): - self.parse_exp(self.get_basic_expectations(), """ -BUG_OVERRIDE : fast/html/article-element.html = IMAGE""") - self.assert_exp('fast/html/article-element.html', IMAGE) + self.parse_exp(self.get_basic_expectations(), """ +BUG_OVERRIDE : text/article-element.html = IMAGE""") + self.assert_exp('text/article-element.html', IMAGE) def test_matches_an_expected_result(self): - def match(test, result, pixel_tests_enabled): - return self._exp.matches_an_expected_result( - self.get_test(test), result, pixel_tests_enabled) + def match(test, result, pixel_tests_enabled): + return self._exp.matches_an_expected_result( + self.get_test(test), result, pixel_tests_enabled) - self.parse_exp(self.get_basic_expectations()) - self.assertTrue(match('fast/html/article-element.html', TEXT, True)) - self.assertTrue(match('fast/html/article-element.html', TEXT, False)) - self.assertFalse(match('fast/html/article-element.html', CRASH, True)) - self.assertFalse(match('fast/html/article-element.html', CRASH, False)) + self.parse_exp(self.get_basic_expectations()) + self.assertTrue(match('text/article-element.html', TEXT, True)) + self.assertTrue(match('text/article-element.html', TEXT, False)) + self.assertFalse(match('text/article-element.html', CRASH, True)) + self.assertFalse(match('text/article-element.html', CRASH, False)) - self.assertTrue(match('fast/events/tab-imagemap.html', IMAGE, True)) - self.assertTrue(match('fast/events/tab-imagemap.html', PASS, False)) + self.assertTrue(match('image/canvas-bg.html', IMAGE, True)) + self.assertTrue(match('image/canvas-bg.html', PASS, False)) - self.assertTrue(match('fast/html/keygen.html', SKIP, False)) - self.assertTrue(match('fast/html/tab-order.html', PASS, False)) + self.assertTrue(match('misc/crash.html', SKIP, False)) + self.assertTrue(match('misc/passing.html', PASS, False)) if __name__ == '__main__': unittest.main() diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py index a4cbe42..782c87c 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/base.py @@ -423,7 +423,7 @@ class Port(object): Returns: Operating-system's environment. """ - return os.environ + return os.environ.copy() def show_html_results_file(self, results_filename): """This routine should display the HTML file pointed at by diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py index bcbd498..b715f7b 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium.py @@ -158,9 +158,8 @@ class ChromiumPort(base.Port): return self.path_from_chromium_base('webkit', self._options.configuration, self._options.results_directory) except AssertionError: - return self.path_from_webkit_base('WebKit', 'chromium', - 'xcodebuild', self._options.configuration, - self._options.results_directory) + return self._build_path(self._options.configuration, + self._options.results_directory) def setup_test_run(self): # Delete the disk cache if any to ensure a clean test run. @@ -273,6 +272,12 @@ class ChromiumPort(base.Port): platform = self.name() return self.path_from_webkit_base('LayoutTests', 'platform', platform) + def _path_to_image_diff(self): + binary_name = 'image_diff' + if self._options.use_drt: + binary_name = 'ImageDiff' + return self._build_path(self._options.configuration, binary_name) + class ChromiumDriver(base.Driver): """Abstract interface for test_shell.""" diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_linux.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_linux.py index 979e225..0818d51 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_linux.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_linux.py @@ -81,11 +81,15 @@ class ChromiumLinuxPort(chromium.ChromiumPort): # def _build_path(self, *comps): - base = self.path_from_chromium_base() + if self._options.use_drt: + base = os.path.join(self.path_from_webkit_base(), 'WebKit', + 'chromium') + else: + base = self.path_from_chromium_base() if os.path.exists(os.path.join(base, 'sconsbuild')): - return self.path_from_chromium_base('sconsbuild', *comps) + return os.path.join(base, 'sconsbuild', *comps) else: - return self.path_from_chromium_base('out', *comps) + return os.path.join(base, 'out', *comps) def _check_apache_install(self): result = chromium.check_file_exists(self._path_to_apache(), @@ -147,14 +151,14 @@ class ChromiumLinuxPort(chromium.ChromiumPort): def _path_to_driver(self, configuration=None): if not configuration: configuration = self._options.configuration - return self._build_path(configuration, 'test_shell') + binary_name = 'test_shell' + if self._options.use_drt: + binary_name = 'DumpRenderTree' + return self._build_path(configuration, binary_name) def _path_to_helper(self): return None - def _path_to_image_diff(self): - return self._build_path(self._options.configuration, 'image_diff') - def _path_to_wdiff(self): if self._is_redhat_based(): return '/usr/bin/dwdiff' diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_mac.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_mac.py index ba67a3e..aa3ac8d 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_mac.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_mac.py @@ -150,12 +150,6 @@ class ChromiumMacPort(chromium.ChromiumPort): binary_name = 'LayoutTestHelper' return self._build_path(self._options.configuration, binary_name) - def _path_to_image_diff(self): - binary_name = 'image_diff' - if self._options.use_drt: - binary_name = 'ImageDiff' - return self._build_path(self._options.configuration, binary_name) - def _path_to_wdiff(self): return 'wdiff' diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py index 95d6378..a32eafd 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py @@ -27,6 +27,9 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import chromium +import chromium_linux +import chromium_mac +import chromium_win import unittest import StringIO @@ -78,3 +81,17 @@ class ChromiumDriverTest(unittest.TestCase): raise IOError self.driver._proc.stdout.readline = mock_readline self._assert_write_command_and_read_line(expected_crash=True) + + def test_path_to_image_diff(self): + class MockOptions: + def __init__(self): + self.use_drt = True + + port = chromium_linux.ChromiumLinuxPort('test-port', options=MockOptions()) + self.assertTrue(port._path_to_image_diff().endswith( + '/out/Release/ImageDiff')) + port = chromium_mac.ChromiumMacPort('test-port', options=MockOptions()) + self.assertTrue(port._path_to_image_diff().endswith( + '/xcodebuild/Release/ImageDiff')) + # FIXME: Figure out how this is going to work on Windows. + #port = chromium_win.ChromiumWinPort('test-port', options=MockOptions()) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py index ad78e61..3b11429 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win.py @@ -64,7 +64,7 @@ class ChromiumWinPort(chromium.ChromiumPort): setup_mount = self.path_from_chromium_base("third_party", "cygwin", "setup_mount.bat") - self._executive.run_command(setup_mount) + self._executive.run_command([setup_mount]) return env def baseline_search_path(self): @@ -117,6 +117,9 @@ class ChromiumWinPort(chromium.ChromiumPort): # def _build_path(self, *comps): + if self._options.use_drt: + return os.path.join(self.path_from_webkit_base(), 'WebKit', + 'chromium', *comps) p = self.path_from_chromium_base('webkit', *comps) if os.path.exists(p): return p diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py new file mode 100644 index 0000000..81db32c --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py @@ -0,0 +1,74 @@ +# 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: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER OR 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 sys +import unittest +import chromium_win +from webkitpy.common.system import outputcapture +from webkitpy.tool import mocktool + + +class ChromiumWinTest(unittest.TestCase): + + class RegisterCygwinOption(object): + def __init__(self): + self.register_cygwin = True + + def setUp(self): + self.orig_platform = sys.platform + + def tearDown(self): + sys.platform = self.orig_platform + + def _mock_path_from_chromium_base(self, *comps): + return os.path.join("/chromium/src", *comps) + + def test_setup_environ_for_server(self): + port = chromium_win.ChromiumWinPort() + port._executive = mocktool.MockExecute(True) + port.path_from_chromium_base = self._mock_path_from_chromium_base + output = outputcapture.OutputCapture() + orig_environ = os.environ.copy() + env = output.assert_outputs(self, port.setup_environ_for_server) + self.assertEqual(orig_environ["PATH"], os.environ["PATH"]) + self.assertNotEqual(env["PATH"], os.environ["PATH"]) + + def test_setup_environ_for_server_register_cygwin(self): + sys.platform = "win32" + port = chromium_win.ChromiumWinPort( + options=ChromiumWinTest.RegisterCygwinOption()) + port._executive = mocktool.MockExecute(True) + port.path_from_chromium_base = self._mock_path_from_chromium_base + setup_mount = self._mock_path_from_chromium_base("third_party", + "cygwin", + "setup_mount.bat") + expected_stderr = "MOCK run_command: %s\n" % [setup_mount] + output = outputcapture.OutputCapture() + output.assert_outputs(self, port.setup_environ_for_server, + expected_stderr=expected_stderr) diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/dryrun.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/dryrun.py index 2c92865..e01bd2f 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/dryrun.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/dryrun.py @@ -143,7 +143,7 @@ class DryrunDriver(base.Driver): text_filename = self._port.expected_filename(test_name, '.txt') text_output = _read_file(text_filename) - if image_hash: + if image_hash is not None: image_filename = self._port.expected_filename(test_name, '.png') image = _read_file(image_filename, 'rb') if self._image_path: diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py b/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py index 5d563cd..e6d4c99 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/port/test.py @@ -28,7 +28,9 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """Dummy Port implementation used for testing.""" +from __future__ import with_statement +import codecs import os import time @@ -45,9 +47,8 @@ class TestPort(base.Port): return ('test',) def baseline_path(self): - curdir = os.path.abspath(__file__) - self.topdir = curdir[0:curdir.index("WebKitTools")] - return os.path.join(self.topdir, 'LayoutTests', 'platform', 'test') + return os.path.join(self.layout_tests_dir(), 'platform', + self.name()) def baseline_search_path(self): return [self.baseline_path()] @@ -66,12 +67,9 @@ class TestPort(base.Port): expected_filename, actual_filename): return '' - def relative_test_filename(self, filename): - return filename - - def expected_filename(self, filename, suffix): - (basename, ext) = os.path.splitext(filename) - return basename + '.' + suffix + def layout_tests_dir(self): + return self.path_from_webkit_base('WebKitTools', 'Scripts', + 'webkitpy', 'layout_tests', 'data') def name(self): return self._name @@ -79,6 +77,11 @@ class TestPort(base.Port): def options(self): return self._options + def path_to_test_expectations_file(self): + return self.path_from_webkit_base('WebKitTools', 'Scripts', + 'webkitpy', 'layout_tests', 'data', 'platform', 'test', + 'test_expectations.txt') + def results_directory(self): return '/tmp/' + self._options.results_directory @@ -104,7 +107,13 @@ class TestPort(base.Port): pass def test_expectations(self): - return '' + """Returns the test expectations for this port. + + Basically this string should contain the equivalent of a + test_expectations file. See test_expectations.py for more details.""" + expectations_path = self.path_to_test_expectations_file() + with codecs.open(expectations_path, "r", "utf-8") as file: + return file.read() def test_base_platform_names(self): return ('test',) @@ -129,6 +138,7 @@ class TestDriver(base.Driver): self._driver_options = test_driver_options self._image_path = image_path self._port = port + self._image_written = False def poll(self): return True @@ -137,6 +147,15 @@ class TestDriver(base.Driver): return 0 def run_test(self, uri, timeoutms, image_hash): + if not self._image_written and self._port._options.pixel_tests: + with open(self._image_path, "w") as f: + f.write("bad png file from TestDriver") + self._image_written = True + + # We special-case this because we can't fake an image hash for a + # missing expectation. + if uri.find('misc/missing-expectation') != -1: + return (False, False, 'deadbeefdeadbeefdeadbeefdeadbeef', '', None) return (False, False, image_hash, '', None) def start(self): diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py index 148174d..6d5543d 100755 --- a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py @@ -575,6 +575,7 @@ class TestRunner: test_args.png_path = png_path test_args.new_baseline = self._options.new_baseline + test_args.reset_results = self._options.reset_results test_args.show_sources = self._options.sources @@ -1521,6 +1522,9 @@ def parse_args(args=None): default=False, help="Save all generated results as new baselines " "into the platform directory, overwriting whatever's " "already there."), + optparse.make_option("--reset-results", action="store_true", + default=False, help="Reset any existing baselines to the " + "generated results"), optparse.make_option("--no-show-results", action="store_false", default=True, dest="show_results", help="Don't launch a browser with results after the tests " diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py index e050cba..1c751d6 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py @@ -29,6 +29,7 @@ """Unit tests for run_webkit_tests.""" +import codecs import os import sys import unittest @@ -62,39 +63,99 @@ def logging_run(args): class MainTest(unittest.TestCase): def test_fast(self): + self.assertTrue(passing_run(['--platform', 'test'])) + self.assertTrue(passing_run(['--platform', 'test', '--run-singly'])) self.assertTrue(passing_run(['--platform', 'test', - 'fast/html'])) - self.assertTrue(passing_run(['--platform', 'test', - '--run-singly', - 'fast/html'])) - self.assertTrue(passing_run(['--platform', 'test', - 'fast/html/article-element.html'])) + 'text/article-element.html'])) self.assertTrue(passing_run(['--platform', 'test', '--child-processes', '1', - '--print', 'unexpected', - 'fast/html'])) + '--print', 'unexpected'])) def test_child_processes(self): (res, buildbot_output, regular_output) = logging_run( ['--platform', 'test', '--print', 'config', '--child-processes', - '1', 'fast/html']) + '1']) self.assertTrue('Running one DumpRenderTree\n' in regular_output.get()) (res, buildbot_output, regular_output) = logging_run( ['--platform', 'test', '--print', 'config', '--child-processes', - '2', 'fast/html']) + '2']) self.assertTrue('Running 2 DumpRenderTrees in parallel\n' in regular_output.get()) def test_last_results(self): - passing_run(['--platform', 'test', 'fast/html']) + passing_run(['--platform', 'test']) (res, buildbot_output, regular_output) = logging_run( ['--platform', 'test', '--print-last-failures']) self.assertEqual(regular_output.get(), ['\n\n']) self.assertEqual(buildbot_output.get(), []) +def _mocked_open(original_open, file_list): + def _wrapper(name, mode, encoding): + if name.find("-expected.") != -1 and mode == "w": + # we don't want to actually write new baselines, so stub these out + name.replace('\\', '/') + file_list.append(name) + return original_open(os.devnull, mode, encoding) + return original_open(name, mode, encoding) + return _wrapper + + +class RebaselineTest(unittest.TestCase): + def assertBaselines(self, file_list, file): + "assert that the file_list contains the baselines.""" + for ext in [".txt", ".png", ".checksum"]: + baseline = file + "-expected" + ext + self.assertTrue(any(f.find(baseline) != -1 for f in file_list)) + + def test_reset_results(self): + file_list = [] + original_open = codecs.open + try: + # Test that we update expectations in place. If the expectation + # is mssing, update the expected generic location. + file_list = [] + codecs.open = _mocked_open(original_open, file_list) + passing_run(['--platform', 'test', '--pixel-tests', + '--reset-results', + 'image/canvas-bg.html', + 'image/canvas-zoom.html', + 'misc/missing-expectation.html']) + self.assertEqual(len(file_list), 9) + self.assertBaselines(file_list, + "data/image/canvas-zoom") + self.assertBaselines(file_list, + "data/platform/test/image/canvas-bg") + self.assertBaselines(file_list, + "data/misc/missing-expectation") + finally: + codecs.open = original_open + + def test_new_baseline(self): + file_list = [] + original_open = codecs.open + try: + # Test that we update the platform expectations. If the expectation + # is mssing, then create a new expectation in the platform dir. + file_list = [] + codecs.open = _mocked_open(original_open, file_list) + passing_run(['--platform', 'test', '--pixel-tests', + '--new-baseline', + 'image/canvas-zoom.html', + 'image/canvas-bg.html', + 'misc/missing-expectation.html']) + self.assertEqual(len(file_list), 9) + self.assertBaselines(file_list, + "data/platform/test/image/canvas-zoom") + self.assertBaselines(file_list, + "data/platform/test/image/canvas-bg") + self.assertBaselines(file_list, + "data/platform/test/misc/missing-expectation") + finally: + codecs.open = original_open + class TestRunnerTest(unittest.TestCase): def test_results_html(self): mock_port = Mock() diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/image_diff.py b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/image_diff.py index b37f4b3..fe73a7b 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/image_diff.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/image_diff.py @@ -73,18 +73,24 @@ class ImageDiff(test_type_base.TestTypeBase): if errno.ENOENT != e.errno: raise - def _save_baseline_files(self, filename, png_path, checksum): + def _save_baseline_files(self, filename, png_path, checksum, + generate_new_baseline): """Saves new baselines for the PNG and checksum. Args: filename: test filename png_path: path to the actual PNG result file checksum: value of the actual checksum result + generate_new_baseline: whether to generate a new, platform-specific + baseline, or update the existing one """ with open(png_path, "rb") as png_file: png_data = png_file.read() - self._save_baseline_data(filename, png_data, ".png", encoding=None) - self._save_baseline_data(filename, checksum, ".checksum", encoding="ascii") + self._save_baseline_data(filename, png_data, ".png", encoding=None, + generate_new_baseline=generate_new_baseline) + self._save_baseline_data(filename, checksum, ".checksum", + encoding="ascii", + generate_new_baseline=generate_new_baseline) def _create_image_diff(self, port, filename, configuration): """Creates the visual diff of the expected/actual PNGs. @@ -128,9 +134,9 @@ class ImageDiff(test_type_base.TestTypeBase): return failures # If we're generating a new baseline, we pass. - if test_args.new_baseline: + if test_args.new_baseline or test_args.reset_results: self._save_baseline_files(filename, test_args.png_path, - test_args.hash) + test_args.hash, test_args.new_baseline) return failures # Compare hashes. diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py index cf0b9ec..8db2e3d 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py @@ -93,7 +93,8 @@ class TestTypeBase(object): self._port.relative_test_filename(filename)) self._port.maybe_make_directory(os.path.split(output_filename)[0]) - def _save_baseline_data(self, filename, data, modifier, encoding): + def _save_baseline_data(self, filename, data, modifier, encoding, + generate_new_baseline=True): """Saves a new baseline file into the port's baseline directory. The file will be named simply "<test>-expected<modifier>", suitable for @@ -103,18 +104,25 @@ class TestTypeBase(object): filename: path to the test file data: result to be saved as the new baseline modifier: type of the result file, e.g. ".txt" or ".png" + encoding: file encoding (none, "utf-8", etc.) + generate_new_baseline: whether to enerate a new, platform-specific + baseline, or update the existing one """ - relative_dir = os.path.dirname( - self._port.relative_test_filename(filename)) - baseline_path = self._port.baseline_path() - output_dir = os.path.join(baseline_path, relative_dir) - output_file = os.path.basename(os.path.splitext(filename)[0] + - self.FILENAME_SUFFIX_EXPECTED + modifier) + if generate_new_baseline: + relative_dir = os.path.dirname( + self._port.relative_test_filename(filename)) + baseline_path = self._port.baseline_path() + output_dir = os.path.join(baseline_path, relative_dir) + output_file = os.path.basename(os.path.splitext(filename)[0] + + self.FILENAME_SUFFIX_EXPECTED + modifier) + self._port.maybe_make_directory(output_dir) + output_path = os.path.join(output_dir, output_file) + _log.debug('writing new baseline result "%s"' % (output_path)) + else: + output_path = self._port.expected_filename(filename, modifier) + _log.debug('resetting baseline result "%s"' % output_path) - self._port.maybe_make_directory(output_dir) - output_path = os.path.join(output_dir, output_file) - _log.debug('writing new baseline to "%s"' % (output_path)) self._write_into_file_at_path(output_path, data, encoding) def output_filename(self, filename, modifier): diff --git a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/text_diff.py b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/text_diff.py index 9fed474..18f74b8 100644 --- a/WebKitTools/Scripts/webkitpy/layout_tests/test_types/text_diff.py +++ b/WebKitTools/Scripts/webkitpy/layout_tests/test_types/text_diff.py @@ -89,11 +89,12 @@ class TestTextDiff(test_type_base.TestTypeBase): failures = [] # If we're generating a new baseline, we pass. - if test_args.new_baseline: + if test_args.new_baseline or test_args.reset_results: # Although all test_shell/DumpRenderTree output should be utf-8, # we do not ever decode it inside run-webkit-tests. For some tests # DumpRenderTree may not output utf-8 text (e.g. webarchives). - self._save_baseline_data(filename, output, ".txt", encoding=None) + self._save_baseline_data(filename, output, ".txt", encoding=None, + generate_new_baseline=test_args.new_baseline) return failures # Normalize text to diff diff --git a/WebKitTools/Scripts/webkitpy/style/checker.py b/WebKitTools/Scripts/webkitpy/style/checker.py index 59a3d39..8fc86c3 100644 --- a/WebKitTools/Scripts/webkitpy/style/checker.py +++ b/WebKitTools/Scripts/webkitpy/style/checker.py @@ -43,7 +43,6 @@ from error_handlers import DefaultStyleErrorHandler from filter import FilterConfiguration from optparser import ArgumentParser from optparser import DefaultCommandOptionValues -from webkitpy.style_references import parse_patch from webkitpy.style_references import configure_logging as _configure_logging _log = logging.getLogger("webkitpy.style.checker") @@ -697,42 +696,3 @@ class StyleProcessor(ProcessorBase): _log.debug("Using class: " + checker.__class__.__name__) checker.check(lines) - - -class PatchReader(object): - - """Supports checking style in patches.""" - - def __init__(self, text_file_reader): - """Create a PatchReader instance. - - Args: - text_file_reader: A TextFileReader instance. - - """ - self._text_file_reader = text_file_reader - - def check(self, patch_string): - """Check style in the given patch.""" - patch_files = parse_patch(patch_string) - - # The diff variable is a DiffFile instance. - for path, diff in patch_files.iteritems(): - line_numbers = set() - for line in diff.lines: - # When deleted line is not set, it means that - # the line is newly added (or modified). - if not line[0]: - line_numbers.add(line[1]) - - _log.debug('Found %s new or modified lines in: %s' - % (len(line_numbers), path)) - - # If line_numbers is empty, the file has no new or - # modified lines. In this case, we don't check the file - # because we'll never output errors for the file. - # This optimization also prevents the program from exiting - # due to a deleted file. - if line_numbers: - self._text_file_reader.process_file(file_path=path, - line_numbers=line_numbers) diff --git a/WebKitTools/Scripts/webkitpy/style/checker_unittest.py b/WebKitTools/Scripts/webkitpy/style/checker_unittest.py index 6e1eaa2..e99ac68 100755 --- a/WebKitTools/Scripts/webkitpy/style/checker_unittest.py +++ b/WebKitTools/Scripts/webkitpy/style/checker_unittest.py @@ -39,7 +39,6 @@ import os import unittest import checker as style -from webkitpy.style_references import parse_patch from webkitpy.style_references import LogTesting from webkitpy.style_references import TestLogStream from checker import _BASE_FILTER_RULES @@ -50,7 +49,6 @@ from checker import check_webkit_style_configuration from checker import check_webkit_style_parser from checker import configure_logging from checker import CheckerDispatcher -from checker import PatchReader from checker import ProcessorBase from checker import StyleProcessor from checker import StyleProcessorConfiguration @@ -769,52 +767,3 @@ class StyleProcessor_CodeCoverageTest(LoggingTestCase): self.assertRaises(AssertionError, self._processor.process, lines=['line1', 'line2'], file_path=path, line_numbers=[100]) - - -class PatchReaderTest(unittest.TestCase): - - """Test the PatchReader class.""" - - class MockTextFileReader(object): - - def __init__(self): - self.passed_to_process_file = [] - """A list of (file_path, line_numbers) pairs.""" - - def process_file(self, file_path, line_numbers): - self.passed_to_process_file.append((file_path, line_numbers)) - - def setUp(self): - file_reader = self.MockTextFileReader() - self._file_reader = file_reader - self._patch_checker = PatchReader(file_reader) - - def _call_check_patch(self, patch_string): - self._patch_checker.check(patch_string) - - def _assert_checked(self, passed_to_process_file): - self.assertEquals(self._file_reader.passed_to_process_file, - passed_to_process_file) - - def test_check_patch(self): - # The modified line_numbers array for this patch is: [2]. - self._call_check_patch("""diff --git a/__init__.py b/__init__.py -index ef65bee..e3db70e 100644 ---- a/__init__.py -+++ b/__init__.py -@@ -1,1 +1,2 @@ - # Required for Python to search this directory for module files -+# New line -""") - self._assert_checked([("__init__.py", set([2]))]) - - def test_check_patch_with_deletion(self): - self._call_check_patch("""Index: __init__.py -=================================================================== ---- __init__.py (revision 3593) -+++ __init__.py (working copy) -@@ -1 +0,0 @@ --foobar -""") - # _mock_check_file should not be called for the deletion patch. - self._assert_checked([]) diff --git a/WebKitTools/Scripts/webkitpy/style/patchreader.py b/WebKitTools/Scripts/webkitpy/style/patchreader.py new file mode 100644 index 0000000..7ba2b66 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/style/patchreader.py @@ -0,0 +1,75 @@ +# Copyright (C) 2010 Google Inc. All rights reserved. +# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com) +# Copyright (C) 2010 ProFUSION embedded systems +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER OR 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 logging + +from webkitpy.common.checkout.diff_parser import DiffParser + + +_log = logging.getLogger("webkitpy.style.patchreader") + + +class PatchReader(object): + + """Supports checking style in patches.""" + + def __init__(self, text_file_reader): + """Create a PatchReader instance. + + Args: + text_file_reader: A TextFileReader instance. + + """ + self._text_file_reader = text_file_reader + + def check(self, patch_string): + """Check style in the given patch.""" + patch_files = DiffParser(patch_string.splitlines()).files + + # The diff variable is a DiffFile instance. + for path, diff in patch_files.iteritems(): + line_numbers = set() + for line in diff.lines: + # When deleted line is not set, it means that + # the line is newly added (or modified). + if not line[0]: + line_numbers.add(line[1]) + + _log.debug('Found %s new or modified lines in: %s' + % (len(line_numbers), path)) + + # If line_numbers is empty, the file has no new or + # modified lines. In this case, we don't check the file + # because we'll never output errors for the file. + # This optimization also prevents the program from exiting + # due to a deleted file. + if line_numbers: + self._text_file_reader.process_file(file_path=path, + line_numbers=line_numbers) diff --git a/WebKitTools/Scripts/webkitpy/style/patchreader_unittest.py b/WebKitTools/Scripts/webkitpy/style/patchreader_unittest.py new file mode 100644 index 0000000..10791e4 --- /dev/null +++ b/WebKitTools/Scripts/webkitpy/style/patchreader_unittest.py @@ -0,0 +1,85 @@ +#!/usr/bin/python +# +# Copyright (C) 2010 Google Inc. All rights reserved. +# Copyright (C) 2009 Torch Mobile Inc. +# Copyright (C) 2009 Apple Inc. All rights reserved. +# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com) +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * 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. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +# OWNER OR 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 unittest + +from webkitpy.style.patchreader import PatchReader + + +class PatchReaderTest(unittest.TestCase): + + """Test the PatchReader class.""" + + class MockTextFileReader(object): + + def __init__(self): + self.passed_to_process_file = [] + """A list of (file_path, line_numbers) pairs.""" + + def process_file(self, file_path, line_numbers): + self.passed_to_process_file.append((file_path, line_numbers)) + + def setUp(self): + file_reader = self.MockTextFileReader() + self._file_reader = file_reader + self._patch_checker = PatchReader(file_reader) + + def _call_check_patch(self, patch_string): + self._patch_checker.check(patch_string) + + def _assert_checked(self, passed_to_process_file): + self.assertEquals(self._file_reader.passed_to_process_file, + passed_to_process_file) + + def test_check_patch(self): + # The modified line_numbers array for this patch is: [2]. + self._call_check_patch("""diff --git a/__init__.py b/__init__.py +index ef65bee..e3db70e 100644 +--- a/__init__.py ++++ b/__init__.py +@@ -1,1 +1,2 @@ + # Required for Python to search this directory for module files ++# New line +""") + self._assert_checked([("__init__.py", set([2]))]) + + def test_check_patch_with_deletion(self): + self._call_check_patch("""Index: __init__.py +=================================================================== +--- __init__.py (revision 3593) ++++ __init__.py (working copy) +@@ -1 +0,0 @@ +-foobar +""") + # _mock_check_file should not be called for the deletion patch. + self._assert_checked([]) diff --git a/WebKitTools/Scripts/webkitpy/style_references.py b/WebKitTools/Scripts/webkitpy/style_references.py index 1bf087d..bab30ca 100644 --- a/WebKitTools/Scripts/webkitpy/style_references.py +++ b/WebKitTools/Scripts/webkitpy/style_references.py @@ -56,14 +56,6 @@ def detect_checkout(): return None if scm is None else WebKitCheckout(scm) -def parse_patch(patch_string): - - """Parse a patch string and return the affected files.""" - - patch = DiffParser(patch_string.splitlines()) - return patch.files - - class WebKitCheckout(object): """Simple facade to the SCM class for use by style package.""" diff --git a/WebKitTools/Scripts/webkitpy/tool/bot/patchcollection.py b/WebKitTools/Scripts/webkitpy/tool/bot/patchcollection.py index 9a2cdfa..6100cf8 100644 --- a/WebKitTools/Scripts/webkitpy/tool/bot/patchcollection.py +++ b/WebKitTools/Scripts/webkitpy/tool/bot/patchcollection.py @@ -1,4 +1,4 @@ -# Copyright (c) 2009 Google Inc. All rights reserved. +# 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 @@ -26,6 +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. + class PersistentPatchCollectionDelegate: def collection_name(self): raise NotImplementedError, "subclasses must implement" @@ -56,9 +57,22 @@ class PersistentPatchCollection: self._status_cache[patch_id] = status return status - def next(self): + def _is_active_patch_id(self, patch_id): + """Active patches are patches waiting to be processed from this collection.""" + status = self._cached_status(patch_id) + return not status or not self._delegate.is_terminal_status(status) + + def _fetch_active_patch_ids(self): patch_ids = self._delegate.fetch_potential_patch_ids() - for patch_id in patch_ids: - status = self._cached_status(patch_id) - if not status or not self._delegate.is_terminal_status(status): - return patch_id + return filter(lambda patch_id: self._is_active_patch_id(patch_id), patch_ids) + + def next(self): + # Note: We only fetch all the ids so we can post them back to the server. + # This will go away once we have a feeder queue and all other queues are + # just pulling their next work item from the server. + patch_ids = self._fetch_active_patch_ids() + # FIXME: We're assuming self._name is a valid queue-name. + self._status.update_work_items(self._name, patch_ids) + if not patch_ids: + return None + return patch_ids[0] diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem.py b/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem.py index 7505c62..9fbfda6 100644 --- a/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem.py +++ b/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem.py @@ -116,6 +116,9 @@ class QtEWS(AbstractEarlyWarningSystem): class WinEWS(AbstractEarlyWarningSystem): name = "win-ews" port_name = "win" + # Use debug, the Apple Win port fails to link Release on 32-bit Windows. + # https://bugs.webkit.org/show_bug.cgi?id=39197 + _build_style = "debug" class AbstractChromiumEWS(AbstractEarlyWarningSystem): diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py index 3d0ddd1..27e09ba 100644 --- a/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py +++ b/WebKitTools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py @@ -47,6 +47,7 @@ class EarlyWarningSytemTest(QueuesTest): expected_stderr = { "begin_work_queue": "CAUTION: %(name)s will discard all local changes in \"%(checkout_dir)s\"\nRunning WebKit %(name)s.\n" % string_replacemnts, "handle_unexpected_error": "Mock error message\n", + "next_work_item": "MOCK: update_work_items: %(name)s [103]\n" % string_replacemnts, "process_work_item": "MOCK: update_status: %(name)s Pass\n" % string_replacemnts, } return expected_stderr diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/queues.py b/WebKitTools/Scripts/webkitpy/tool/commands/queues.py index 78ca729..08bd3aa 100644 --- a/WebKitTools/Scripts/webkitpy/tool/commands/queues.py +++ b/WebKitTools/Scripts/webkitpy/tool/commands/queues.py @@ -135,6 +135,9 @@ class AbstractPatchQueue(AbstractQueue): def _update_status(self, message, patch=None, results_file=None): self.tool.status_server.update_status(self.name, message, patch, results_file) + def _update_work_items(self, patch_ids): + self.tool.status_server.update_work_items(self.name, patch_ids) + def _did_pass(self, patch): self._update_status(self._pass_status, patch) @@ -169,12 +172,21 @@ class CommitQueue(AbstractPatchQueue, StepSequenceErrorHandler): all_patches = sum([self.tool.bugs.fetch_bug(bug_id).commit_queued_patches(include_invalid=True) for bug_id in bug_ids], []) return self.committer_validator.patches_after_rejecting_invalid_commiters_and_reviewers(all_patches) + def _patch_cmp(self, a, b): + # Sort first by is_rollout, then by attach_date. + # Reversing the order so that is_rollout is first. + rollout_cmp = cmp(b.is_rollout(), a.is_rollout()) + if (rollout_cmp != 0): + return rollout_cmp + return cmp(a.attach_date(), b.attach_date()) + def next_work_item(self): patches = self._validate_patches_in_commit_queue() + patches = sorted(patches, self._patch_cmp) + self._update_work_items([patch.id() for patch in patches]) builders_are_green = self._builders_are_green() if not builders_are_green: patches = filter(lambda patch: patch.is_rollout(), patches) - # FIXME: We could sort the patches in a specific order here, was suggested by https://bugs.webkit.org/show_bug.cgi?id=33395 if not patches: queue_text = "queue" if builders_are_green else "rollout queue" self._update_status("Empty %s" % queue_text) diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/queues_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/queues_unittest.py index 0bd42fb..a5d56da 100644 --- a/WebKitTools/Scripts/webkitpy/tool/commands/queues_unittest.py +++ b/WebKitTools/Scripts/webkitpy/tool/commands/queues_unittest.py @@ -122,7 +122,8 @@ class CommitQueueTest(QueuesTest): # FIXME: The commit-queue warns about bad committers twice. This is due to the fact that we access Attachment.reviewer() twice and it logs each time. "next_work_item" : """Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com) Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com) -2 patches in commit-queue [197, 106] +MOCK: update_work_items: commit-queue [106, 197] +2 patches in commit-queue [106, 197] """, "process_work_item" : "MOCK: update_status: commit-queue Pass\n", } @@ -137,6 +138,7 @@ Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.c # FIXME: The commit-queue warns about bad committers twice. This is due to the fact that we access Attachment.reviewer() twice and it logs each time. "next_work_item" : """Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com) Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com) +MOCK: update_work_items: commit-queue [106, 197] MOCK: update_status: commit-queue Builders ["Builder2"] are red. See http://build.webkit.org 1 patch in commit-queue [106] """, @@ -154,6 +156,7 @@ MOCK: update_status: commit-queue Builders ["Builder2"] are red. See http://buil # FIXME: The commit-queue warns about bad committers twice. This is due to the fact that we access Attachment.reviewer() twice and it logs each time. "next_work_item": """Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com) Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com) +MOCK: update_work_items: commit-queue [106, 197] MOCK: update_status: commit-queue Builders ["Builder2"] are red. See http://build.webkit.org 1 patch in commit-queue [106] """, @@ -170,11 +173,31 @@ MOCK: update_status: commit-queue Builders ["Builder2"] are red. See http://buil expected_run_args = ["echo", "--status-host=example.com", "build-and-test", "--force-clean", "--build", "--test", "--non-interactive", "--no-update", "--build-style=both", "--quiet"] tool.executive.run_and_throw_if_fail.assert_called_with(expected_run_args) + def _mock_attachment(self, is_rollout, attach_date): + attachment = Mock() + attachment.is_rollout = lambda: is_rollout + attachment.attach_date = lambda: attach_date + return attachment + + def test_patch_cmp(self): + long_ago_date = datetime(1900, 1, 21) + recent_date = datetime(2010, 1, 21) + attachment1 = self._mock_attachment(is_rollout=False, attach_date=recent_date) + attachment2 = self._mock_attachment(is_rollout=False, attach_date=long_ago_date) + attachment3 = self._mock_attachment(is_rollout=True, attach_date=recent_date) + attachment4 = self._mock_attachment(is_rollout=True, attach_date=long_ago_date) + attachments = [attachment1, attachment2, attachment3, attachment4] + expected_sort = [attachment4, attachment3, attachment2, attachment1] + queue = CommitQueue() + attachments.sort(queue._patch_cmp) + self.assertEqual(attachments, expected_sort) + class StyleQueueTest(QueuesTest): def test_style_queue(self): expected_stderr = { "begin_work_queue" : "CAUTION: style-queue will discard all local changes in \"%s\"\nRunning WebKit style-queue.\n" % MockSCM.fake_checkout_root, + "next_work_item": "MOCK: update_work_items: style-queue [103]\n", "should_proceed_with_work_item": "MOCK: update_status: style-queue Checking style\n", "process_work_item" : "MOCK: update_status: style-queue Pass\n", "handle_unexpected_error" : "Mock error message\n", diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/upload.py b/WebKitTools/Scripts/webkitpy/tool/commands/upload.py index 4797ef6..cf715b9 100644 --- a/WebKitTools/Scripts/webkitpy/tool/commands/upload.py +++ b/WebKitTools/Scripts/webkitpy/tool/commands/upload.py @@ -168,7 +168,6 @@ class Post(AbstractPatchUploadingCommand): name = "post" help_text = "Attach the current working directory diff to a bug as a patch file" argument_names = "[BUGID]" - show_in_main_help = True steps = [ steps.CheckStyle, steps.ConfirmDiff, @@ -193,7 +192,6 @@ class Prepare(AbstractSequencedCommand): name = "prepare" help_text = "Creates a bug (or prompts for an existing bug) and prepares the ChangeLogs" argument_names = "[BUGID]" - show_in_main_help = True steps = [ steps.PromptForBugOrTitle, steps.CreateBug, diff --git a/WebKitTools/Scripts/webkitpy/tool/commands/upload_unittest.py b/WebKitTools/Scripts/webkitpy/tool/commands/upload_unittest.py index 8f6483a..d52775b 100644 --- a/WebKitTools/Scripts/webkitpy/tool/commands/upload_unittest.py +++ b/WebKitTools/Scripts/webkitpy/tool/commands/upload_unittest.py @@ -55,6 +55,7 @@ class UploadCommandsTest(CommandsTest): options.description = "MOCK description" options.request_commit = False options.review = True + options.comment = None # Rietveld upload code requires a real SCM checkout. options.fancy_review = False options.cc = None @@ -85,6 +86,7 @@ MOCK: user.open_url: http://example.com/42 options.description = "MOCK description" options.request_commit = False options.review = True + options.comment = None # Rietveld upload code requires a real SCM checkout. options.fancy_review = False options.cc = None diff --git a/WebKitTools/Scripts/webkitpy/tool/main.py b/WebKitTools/Scripts/webkitpy/tool/main.py index 2dc177d..1f43145 100755 --- a/WebKitTools/Scripts/webkitpy/tool/main.py +++ b/WebKitTools/Scripts/webkitpy/tool/main.py @@ -56,6 +56,7 @@ from webkitpy.common.system.deprecated_logging import log class WebKitPatch(MultiCommandTool): global_options = [ + make_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="enable all logging"), make_option("--dry-run", action="store_true", dest="dry_run", default=False, help="do not touch remote servers"), make_option("--status-host", action="store", dest="status_host", type="string", nargs=1, help="Hostname (e.g. localhost or commit.webkit.org) where status updates should be posted."), make_option("--irc-password", action="store", dest="irc_password", type="string", nargs=1, help="Password to use when communicating via IRC."), diff --git a/WebKitTools/Scripts/webkitpy/tool/mocktool.py b/WebKitTools/Scripts/webkitpy/tool/mocktool.py index 47fff1b..2f192d9 100644 --- a/WebKitTools/Scripts/webkitpy/tool/mocktool.py +++ b/WebKitTools/Scripts/webkitpy/tool/mocktool.py @@ -477,6 +477,9 @@ class MockStatusServer(object): def svn_revision(self, svn_revision): return None + def update_work_items(self, queue_name, work_items): + log("MOCK: update_work_items: %s %s" % (queue_name, work_items)) + def update_status(self, queue_name, status, patch=None, results_file=None): log("MOCK: update_status: %s %s" % (queue_name, status)) return 187 diff --git a/WebKitTools/Scripts/webkitpy/tool/steps/options.py b/WebKitTools/Scripts/webkitpy/tool/steps/options.py index 524a252..186d292 100644 --- a/WebKitTools/Scripts/webkitpy/tool/steps/options.py +++ b/WebKitTools/Scripts/webkitpy/tool/steps/options.py @@ -36,6 +36,7 @@ class Options(object): check_style = make_option("--ignore-style", action="store_false", dest="check_style", default=True, help="Don't check to see if the patch has proper style before uploading.") clean = make_option("--no-clean", action="store_false", dest="clean", default=True, help="Don't check if the working directory is clean before applying patches") close_bug = make_option("--no-close", action="store_false", dest="close_bug", default=True, help="Leave bug open after landing.") + comment = make_option("--comment", action="store", type="string", dest="comment", help="Comment to post to bug.") component = make_option("--component", action="store", type="string", dest="component", help="Component for the new bug.") confirm = make_option("--no-confirm", action="store_false", dest="confirm", default=True, help="Skip confirmation steps.") description = make_option("-m", "--description", action="store", type="string", dest="description", help="Description string for the attachment (default: \"patch\")") diff --git a/WebKitTools/Scripts/webkitpy/tool/steps/postdiff.py b/WebKitTools/Scripts/webkitpy/tool/steps/postdiff.py index 79739cd..c40b6ff 100644 --- a/WebKitTools/Scripts/webkitpy/tool/steps/postdiff.py +++ b/WebKitTools/Scripts/webkitpy/tool/steps/postdiff.py @@ -35,6 +35,7 @@ class PostDiff(AbstractStep): def options(cls): return AbstractStep.options() + [ Options.description, + Options.comment, Options.review, Options.request_commit, Options.open_bug, @@ -43,7 +44,7 @@ class PostDiff(AbstractStep): def run(self, state): diff = self.cached_lookup(state, "diff") description = self._options.description or "Patch" - comment_text = None + comment_text = self._options.comment self._tool.bugs.add_patch_to_bug(state["bug_id"], diff, description, comment_text=comment_text, mark_for_review=self._options.review, mark_for_commit_queue=self._options.request_commit) if self._options.open_bug: self._tool.user.open_url(self._tool.bugs.bug_url_for_bug_id(state["bug_id"])) diff --git a/WebKitTools/Scripts/webkitpy/tool/steps/runtests.py b/WebKitTools/Scripts/webkitpy/tool/steps/runtests.py index 0734d8f..22b9452 100644 --- a/WebKitTools/Scripts/webkitpy/tool/steps/runtests.py +++ b/WebKitTools/Scripts/webkitpy/tool/steps/runtests.py @@ -58,9 +58,10 @@ class RunTests(AbstractStep): args.append("--no-launch-safari") args.append("--exit-after-n-failures=1") # FIXME: Hack to work around https://bugs.webkit.org/show_bug.cgi?id=38912 - # when running the commit-queue on a mac leopard machine. + # when running the commit-queue on a mac leopard machine since compositing + # does not work reliably on Leopard due to various graphics driver/system bugs. if self.port().name() == "Mac" and self.port().is_leopard(): - args.extend(["--ignore-tests", "compositing/iframes"]) + args.extend(["--ignore-tests", "compositing"]) if self._options.quiet: args.append("--quiet") diff --git a/WebKitTools/Scripts/webkitpy/tool/steps/steps_unittest.py b/WebKitTools/Scripts/webkitpy/tool/steps/steps_unittest.py index eee183b..1fd2bad 100644 --- a/WebKitTools/Scripts/webkitpy/tool/steps/steps_unittest.py +++ b/WebKitTools/Scripts/webkitpy/tool/steps/steps_unittest.py @@ -78,6 +78,6 @@ MOCK run_and_throw_if_fail: ['WebKitTools/Scripts/test-webkitperl'] Running JavaScriptCore tests MOCK run_and_throw_if_fail: ['WebKitTools/Scripts/run-javascriptcore-tests'] Running run-webkit-tests -MOCK run_and_throw_if_fail: ['WebKitTools/Scripts/run-webkit-tests', '--no-launch-safari', '--exit-after-n-failures=1', '--ignore-tests', 'compositing/iframes', '--quiet'] +MOCK run_and_throw_if_fail: ['WebKitTools/Scripts/run-webkit-tests', '--no-launch-safari', '--exit-after-n-failures=1', '--ignore-tests', 'compositing', '--quiet'] """ OutputCapture().assert_outputs(self, step.run, [{}], expected_stderr=expected_stderr) |