diff options
| author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-03-12 14:11:15 +0100 |
|---|---|---|
| committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-03-12 14:11:15 +0100 |
| commit | dd91e772430dc294e3bf478c119ef8d43c0a3358 (patch) | |
| tree | 6f33ce4d5872a5691e0291eb45bf6ab373a5f567 /Tools/Scripts/webkitpy | |
| parent | ad0d549d4cc13433f77c1ac8f0ab379c83d93f28 (diff) | |
| download | qtwebkit-dd91e772430dc294e3bf478c119ef8d43c0a3358.tar.gz | |
Imported WebKit commit 3db4eb1820ac8fb03065d7ea73a4d9db1e8fea1a (http://svn.webkit.org/repository/webkit/trunk@110422)
This includes build fixes for the latest qtbase/qtdeclarative as well as the final QML2 API.
Diffstat (limited to 'Tools/Scripts/webkitpy')
46 files changed, 743 insertions, 1956 deletions
diff --git a/Tools/Scripts/webkitpy/bindings/main.py b/Tools/Scripts/webkitpy/bindings/main.py index 5154f399b..15884bb73 100644 --- a/Tools/Scripts/webkitpy/bindings/main.py +++ b/Tools/Scripts/webkitpy/bindings/main.py @@ -73,7 +73,7 @@ class BindingsTests: cmd = ['perl', '-w', '-IWebCore/bindings/scripts', - 'WebCore/bindings/scripts/resolve-supplemental.pl', + 'WebCore/bindings/scripts/preprocess-idls.pl', '--idlFilesList', idl_files_list[1], '--defines', '', '--supplementalDependencyFile', supplemental_dependency_file, diff --git a/Tools/Scripts/webkitpy/common/checkout/changelog.py b/Tools/Scripts/webkitpy/common/checkout/changelog.py index fd41871a0..55b05982b 100644 --- a/Tools/Scripts/webkitpy/common/checkout/changelog.py +++ b/Tools/Scripts/webkitpy/common/checkout/changelog.py @@ -263,7 +263,7 @@ class ChangeLog(object): entry_lines.append(line) return None # We never found a date line! - svn_blame_regexp = re.compile(r'^(\s*(?P<revision>\d+) [^ ]+)\s(?P<line>.*?\n)') + svn_blame_regexp = re.compile(r'^(\s*(?P<revision>\d+) [^ ]+)\s*(?P<line>.*?\n)') @staticmethod def _separate_revision_and_line(line): diff --git a/Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py b/Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py index db4a55b06..431c86701 100644 --- a/Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py +++ b/Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py @@ -250,39 +250,40 @@ class ChangeLogTest(unittest.TestCase): self.assertEquals(parsed_entries[8].reviewer_text(), 'Darin Adler') def test_parse_log_entries_from_annotated_file(self): - changelog_file = StringIO(u'''100000 ossy@webkit.org 2011-11-11 Csaba Osztrogon\u00e1c <ossy@webkit.org> -100000 ossy@webkit.org -100000 ossy@webkit.org 100,000 !!! -100000 ossy@webkit.org -100000 ossy@webkit.org Reviewed by Zoltan Herczeg. -100000 ossy@webkit.org -100000 ossy@webkit.org * ChangeLog: Point out revision 100,000. -100000 ossy@webkit.org -93798 ap@apple.com 2011-08-25 Alexey Proskuryakov <ap@apple.com> -93798 ap@apple.com -93798 ap@apple.com Fix build when GCC 4.2 is not installed. -93798 ap@apple.com -93798 ap@apple.com * gtest/xcode/Config/CompilerVersion.xcconfig: Copied from Source/WebCore/Configurations/CompilerVersion.xcconfig. -93798 ap@apple.com * gtest/xcode/Config/General.xcconfig: -93798 ap@apple.com Use the same compiler version as other projects do. -93798 ap@apple.com -99491 andreas.kling@nokia.com 2011-11-03 Andreas Kling <kling@webkit.org> -99491 andreas.kling@nokia.com -99190 andreas.kling@nokia.com Unreviewed build fix, sigh. -99190 andreas.kling@nokia.com -99190 andreas.kling@nokia.com * css/CSSFontFaceRule.h: -99190 andreas.kling@nokia.com * css/CSSMutableStyleDeclaration.h: -99190 andreas.kling@nokia.com -99190 andreas.kling@nokia.com 2011-11-03 Andreas Kling <kling@webkit.org> -99190 andreas.kling@nokia.com -99187 andreas.kling@nokia.com Unreviewed build fix, out-of-line StyleSheet::parentStyleSheet() -99187 andreas.kling@nokia.com again since there's a cycle in the includes between CSSRule/StyleSheet. -99187 andreas.kling@nokia.com -99187 andreas.kling@nokia.com * css/StyleSheet.cpp: -99187 andreas.kling@nokia.com (WebCore::StyleSheet::parentStyleSheet): -99187 andreas.kling@nokia.com * css/StyleSheet.h: -99187 andreas.kling@nokia.com -''') + # Note that there are trailing spaces on some of the lines intentionally. + changelog_file = StringIO(u"100000 ossy@webkit.org 2011-11-11 Csaba Osztrogon\u00e1c <ossy@webkit.org>\n" + u"100000 ossy@webkit.org\n" + u"100000 ossy@webkit.org 100,000 !!!\n" + u"100000 ossy@webkit.org \n" + u"100000 ossy@webkit.org Reviewed by Zoltan Herczeg.\n" + u"100000 ossy@webkit.org \n" + u"100000 ossy@webkit.org * ChangeLog: Point out revision 100,000.\n" + u"100000 ossy@webkit.org \n" + u"93798 ap@apple.com 2011-08-25 Alexey Proskuryakov <ap@apple.com>\n" + u"93798 ap@apple.com \n" + u"93798 ap@apple.com Fix build when GCC 4.2 is not installed.\n" + u"93798 ap@apple.com \n" + u"93798 ap@apple.com * gtest/xcode/Config/CompilerVersion.xcconfig: Copied from Source/WebCore/Configurations/CompilerVersion.xcconfig.\n" + u"93798 ap@apple.com * gtest/xcode/Config/General.xcconfig:\n" + u"93798 ap@apple.com Use the same compiler version as other projects do.\n" + u"93798 ap@apple.com\n" + u"99491 andreas.kling@nokia.com 2011-11-03 Andreas Kling <kling@webkit.org>\n" + u"99491 andreas.kling@nokia.com \n" + u"99190 andreas.kling@nokia.com Unreviewed build fix, sigh.\n" + u"99190 andreas.kling@nokia.com \n" + u"99190 andreas.kling@nokia.com * css/CSSFontFaceRule.h:\n" + u"99190 andreas.kling@nokia.com * css/CSSMutableStyleDeclaration.h:\n" + u"99190 andreas.kling@nokia.com\n" + u"99190 andreas.kling@nokia.com 2011-11-03 Andreas Kling <kling@webkit.org>\n" + u"99190 andreas.kling@nokia.com \n" + u"99187 andreas.kling@nokia.com Unreviewed build fix, out-of-line StyleSheet::parentStyleSheet()\n" + u"99187 andreas.kling@nokia.com again since there's a cycle in the includes between CSSRule/StyleSheet.\n" + u"99187 andreas.kling@nokia.com \n" + u"99187 andreas.kling@nokia.com * css/StyleSheet.cpp:\n" + u"99187 andreas.kling@nokia.com (WebCore::StyleSheet::parentStyleSheet):\n" + u"99187 andreas.kling@nokia.com * css/StyleSheet.h:\n" + u"99187 andreas.kling@nokia.com \n") + parsed_entries = list(ChangeLog.parse_entries_from_file(changelog_file)) self.assertEquals(parsed_entries[0].revision(), 100000) self.assertEquals(parsed_entries[0].reviewer_text(), "Zoltan Herczeg") @@ -390,17 +391,27 @@ class ChangeLogTest(unittest.TestCase): self.assertEquals(reviewer_text_list, expected_text_list) self.assertEquals(self._entry_with_reviewer(reviewer_text).reviewers(), self._contributors(expected_contributors)) - def test_fuzzy_reviewer_match(self): - self._assert_fuzzy_reviewer_match('Reviewed by Dimitri Glazkov, build fix', ['Dimitri Glazkov', 'build fix'], ['Dimitri Glazkov']) + def test_fuzzy_reviewer_match__none(self): self._assert_fuzzy_reviewer_match('Reviewed by BUILD FIX', ['BUILD FIX'], []) self._assert_fuzzy_reviewer_match('Reviewed by Mac build fix', ['Mac build fix'], []) + + def test_fuzzy_reviewer_match_adam_barth(self): + self._assert_fuzzy_reviewer_match('Reviewed by Adam Barth.:w', ['Adam Barth.:w'], ['Adam Barth']) + + def test_fuzzy_reviewer_match_darin_adler_et_al(self): + self._assert_fuzzy_reviewer_match('Reviewed by Darin Adler in <https://bugs.webkit.org/show_bug.cgi?id=47736>.', ['Darin Adler in'], ['Darin Adler']) self._assert_fuzzy_reviewer_match('Reviewed by Darin Adler, Dan Bernstein, Adele Peterson, and others.', ['Darin Adler', 'Dan Bernstein', 'Adele Peterson', 'others'], ['Darin Adler', 'Dan Bernstein', 'Adele Peterson']) + + def test_fuzzy_reviewer_match_dimitri_glazkov(self): + self._assert_fuzzy_reviewer_match('Reviewed by Dimitri Glazkov, build fix', ['Dimitri Glazkov', 'build fix'], ['Dimitri Glazkov']) + + def test_fuzzy_reviewer_match_george_staikos(self): self._assert_fuzzy_reviewer_match('Reviewed by George Staikos (and others)', ['George Staikos', 'others'], ['George Staikos']) + + def test_fuzzy_reviewer_match_mark_rowe(self): self._assert_fuzzy_reviewer_match('Reviewed by Mark Rowe, but Dan Bernstein also reviewed and asked thoughtful questions.', ['Mark Rowe', 'but Dan Bernstein also reviewed', 'asked thoughtful questions'], ['Mark Rowe']) - self._assert_fuzzy_reviewer_match('Reviewed by Darin Adler in <https://bugs.webkit.org/show_bug.cgi?id=47736>.', ['Darin Adler in'], ['Darin Adler']) - self._assert_fuzzy_reviewer_match('Reviewed by Adam Barth.:w', ['Adam Barth.:w'], ['Adam Barth']) def _assert_parse_authors(self, author_text, expected_contributors): parsed_authors = [(author['name'], author['email']) for author in self._entry_with_author(author_text).authors()] diff --git a/Tools/Scripts/webkitpy/common/checkout/scm/git.py b/Tools/Scripts/webkitpy/common/checkout/scm/git.py index 7c5d80cc3..c7dbd7ca1 100644 --- a/Tools/Scripts/webkitpy/common/checkout/scm/git.py +++ b/Tools/Scripts/webkitpy/common/checkout/scm/git.py @@ -170,11 +170,28 @@ class Git(SCM, SVNRepository): return_code = self.run(["git", "show", "HEAD:%s" % path], return_exit_code=True, decode_output=False) return return_code != self.ERROR_FILE_IS_MISSING + def _branch_from_ref(self, ref): + return ref.replace('refs/heads/', '') + + def _current_branch(self): + return self._branch_from_ref(self.run(['git', 'symbolic-ref', '-q', 'HEAD'], cwd=self.checkout_root).strip()) + + def _upstream_branch(self): + current_branch = self._current_branch() + return self._branch_from_ref(self.read_git_config('branch.%s.merge' % current_branch, cwd=self.checkout_root).strip()) + def merge_base(self, git_commit): if git_commit: - # Special-case HEAD.. to mean working-copy changes only. - if git_commit.upper() == 'HEAD..': - return 'HEAD' + # Rewrite UPSTREAM to the upstream branch + if 'UPSTREAM' in git_commit: + upstream = self._upstream_branch() + if not upstream: + raise ScriptError(message='No upstream/tracking branch set.') + git_commit = git_commit.replace('UPSTREAM', upstream) + + # Special-case <refname>.. to include working copy changes, e.g., 'HEAD....' shows only the diffs from HEAD. + if git_commit.endswith('....'): + return git_commit[:-4] if '..' not in git_commit: git_commit = git_commit + "^.." + git_commit @@ -350,8 +367,7 @@ class Git(SCM, SVNRepository): return self.push_local_commits_to_server(username=username, password=password) def _commit_on_branch(self, message, git_commit, username=None, password=None): - branch_ref = self.run(['git', 'symbolic-ref', 'HEAD']).strip() - branch_name = branch_ref.replace('refs/heads/', '') + branch_name = self._current_branch() commit_ids = self.commit_ids_from_commitish_arguments([git_commit]) # We want to squash all this branch's commits into one commit with the proper description. diff --git a/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py b/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py index 4b88c3da1..7ce714a19 100644 --- a/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py +++ b/Tools/Scripts/webkitpy/common/checkout/scm/scm_unittest.py @@ -1167,9 +1167,12 @@ class GitSVNTest(SCMTest): write_into_file_at_path('test_file_commit2', 'still more test content') run_command(['git', 'add', 'test_file_commit2']) + def _second_local_commit(self): + self._local_commit('test_file_commit2', 'still more test content', 'yet another test commit') + def _two_local_commits(self): self._one_local_commit() - self._local_commit('test_file_commit2', 'still more test content', 'yet another test commit') + self._second_local_commt() def _three_local_commits(self): self._local_commit('test_file_commit0', 'more test content', 'another test commit') @@ -1213,13 +1216,6 @@ class GitSVNTest(SCMTest): self.assertTrue(re.search(r'test_file_commit1', svn_log)) self.assertTrue(re.search(r'test_file_commit2', svn_log)) - def test_changed_files_working_copy_only(self): - self._one_local_commit_plus_working_copy_changes() - scm = detect_scm_system(self.git_checkout_path) - commit_text = scm.commit_with_message("another test commit", git_commit="HEAD..") - self.assertFalse(re.search(r'test_file_commit1', svn_log)) - self.assertTrue(re.search(r'test_file_commit2', svn_log)) - def test_commit_with_message_only_local_commit(self): self._one_local_commit() scm = detect_scm_system(self.git_checkout_path) @@ -1291,6 +1287,11 @@ class GitSVNTest(SCMTest): # There's a conflict between trunk and the test_file2 modification. self.assertRaises(ScriptError, scm.commit_with_message, "another test commit", force_squash=True) + def test_upstream_branch(self): + run_command(['git', 'checkout', '-t', '-b', 'my-branch']) + run_command(['git', 'checkout', '-t', '-b', 'my-second-branch']) + self.assertEquals(self.scm._upstream_branch(), 'my-branch') + def test_remote_branch_ref(self): self.assertEqual(self.scm.remote_branch_ref(), 'refs/remotes/trunk') @@ -1360,7 +1361,7 @@ class GitSVNTest(SCMTest): def test_create_patch_working_copy_only(self): self._one_local_commit_plus_working_copy_changes() scm = detect_scm_system(self.git_checkout_path) - patch = scm.create_patch(git_commit="HEAD..") + patch = scm.create_patch(git_commit="HEAD....") self.assertFalse(re.search(r'test_file_commit1', patch)) self.assertTrue(re.search(r'test_file_commit2', patch)) @@ -1413,6 +1414,16 @@ class GitSVNTest(SCMTest): self.assertTrue('test_file_commit1' in files) self.assertTrue('test_file_commit2' in files) + # working copy should *not* be in the list. + files = scm.changed_files('trunk..') + self.assertTrue('test_file_commit1' in files) + self.assertFalse('test_file_commit2' in files) + + # working copy *should* be in the list. + files = scm.changed_files('trunk....') + self.assertTrue('test_file_commit1' in files) + self.assertTrue('test_file_commit2' in files) + def test_changed_files_git_commit(self): self._two_local_commits() scm = detect_scm_system(self.git_checkout_path) @@ -1431,7 +1442,7 @@ class GitSVNTest(SCMTest): def test_changed_files_working_copy_only(self): self._one_local_commit_plus_working_copy_changes() scm = detect_scm_system(self.git_checkout_path) - files = scm.changed_files(git_commit="HEAD..") + files = scm.changed_files(git_commit="HEAD....") self.assertFalse('test_file_commit1' in files) self.assertTrue('test_file_commit2' in files) @@ -1466,6 +1477,26 @@ class GitSVNTest(SCMTest): def test_changed_files_for_revision(self): self._shared_test_changed_files_for_revision() + def test_changed_files_upstream(self): + run_command(['git', 'checkout', '-t', '-b', 'my-branch']) + self._one_local_commit() + run_command(['git', 'checkout', '-t', '-b', 'my-second-branch']) + self._second_local_commit() + write_into_file_at_path('test_file_commit0', 'more test content') + run_command(['git', 'add', 'test_file_commit0']) + + # equivalent to 'git diff my-branch..HEAD, should not include working changes + files = self.scm.changed_files(git_commit='UPSTREAM..') + self.assertFalse('test_file_commit1' in files) + self.assertTrue('test_file_commit2' in files) + self.assertFalse('test_file_commit0' in files) + + # equivalent to 'git diff my-branch', *should* include working changes + files = self.scm.changed_files(git_commit='UPSTREAM....') + self.assertFalse('test_file_commit1' in files) + self.assertTrue('test_file_commit2' in files) + self.assertTrue('test_file_commit0' in files) + def test_contents_at_revision(self): self._shared_test_contents_at_revision() diff --git a/Tools/Scripts/webkitpy/common/config/committers.py b/Tools/Scripts/webkitpy/common/config/committers.py index 54dbbed80..f646db7a9 100644 --- a/Tools/Scripts/webkitpy/common/config/committers.py +++ b/Tools/Scripts/webkitpy/common/config/committers.py @@ -141,7 +141,6 @@ contributors_who_are_not_committers = [ Contributor("Peter Linss", "peter.linss@hp.com", "plinss"), Contributor("Radar WebKit Bug Importer", "webkit-bug-importer@group.apple.com"), Contributor("Roland Takacs", "takacs.roland@stud.u-szeged.hu", "rtakacs"), - Contributor("Stephen Chenney", "schenney@chromium.org", "schenney"), Contributor("Szilard Ledan-Muntean", "muntean-ledan.szilard@stud.u-szeged.hu", "szledan"), Contributor("Tab Atkins", ["tabatkins@google.com", "jackalmage@gmail.com"], "tabatkins"), Contributor("Tamas Czene", ["tczene@inf.u-szeged.hu", "Czene.Tamas@stud.u-szeged.hu"], "tczene"), @@ -164,8 +163,8 @@ committers_unable_to_review = [ Committer("Adam Klein", "adamk@chromium.org", "aklein"), Committer("Adam Langley", "agl@chromium.org", "agl"), Committer("Ademar de Souza Reis Jr", ["ademar.reis@gmail.com", "ademar@webkit.org"], "ademar"), - Committer("Adrienne Walker", ["enne@google.com", "enne@chromium.org"], "enne"), Committer("Albert J. Wong", "ajwong@chromium.org"), + Committer(u"Alexander F\u00e6r\u00f8y", ["ahf@0x90.dk", "alexander.faeroy@nokia.com"], "ahf"), Committer("Alexander Kellett", ["lypanov@mac.com", "a-lists001@lypanov.net", "lypanov@kde.org"], "lypanov"), Committer("Alexander Pavlov", "apavlov@chromium.org", "apavlov"), Committer("Alexandru Chiculita", "achicu@adobe.com", "achicu"), @@ -198,6 +197,7 @@ committers_unable_to_review = [ Committer("Carlos Garcia Campos", ["cgarcia@igalia.com", "carlosgc@gnome.org", "carlosgc@webkit.org"], "KaL"), Committer("Carol Szabo", ["carol@webkit.org", "carol.szabo@nokia.com"], "cszabo1"), Committer("Cary Clark", ["caryclark@google.com", "caryclark@chromium.org"], "caryclark"), + Committer("Charles Wei", ["charles.wei@torchmobile.com.cn"], "cswei"), Committer("Chris Evans", ["cevans@google.com", "cevans@chromium.org"]), Committer("Chris Guillory", ["ctguil@chromium.org", "chris.guillory@google.com"], "ctguil"), Committer("Chris Petersen", "cpetersen@apple.com", "cpetersen"), @@ -234,7 +234,7 @@ committers_unable_to_review = [ Committer("Hayato Ito", "hayato@chromium.org", "hayato"), Committer("Helder Correia", "helder@sencha.com", "helder"), Committer("Hin-Chung Lam", ["hclam@google.com", "hclam@chromium.org"]), - Committer("Igor Trindade Oliveira", ["igor.oliveira@webkit.org", "igor.oliveira@openbossa.org"], "igoroliveira"), + Committer("Igor Trindade Oliveira", ["igor.oliveira@webkit.org", "igor.o@sisa.samsung.com"], "igoroliveira"), Committer("Ilya Sherman", "isherman@chromium.org", "isherman"), Committer("Ilya Tikhonovsky", "loislo@chromium.org", "loislo"), Committer("Ivan Krsti\u0107", "ike@apple.com"), @@ -251,7 +251,6 @@ committers_unable_to_review = [ Committer("Jens Alfke", ["snej@chromium.org", "jens@apple.com"]), Committer("Jer Noble", "jer.noble@apple.com", "jernoble"), Committer("Jeremy Moskovich", ["playmobil@google.com", "jeremy@chromium.org"], "jeremymos"), - Committer("Jessie Berlin", ["jberlin@webkit.org", "jberlin@apple.com"]), Committer("Jesus Sanchez-Palencia", ["jesus@webkit.org", "jesus.palencia@openbossa.org"], "jeez_"), Committer("Jia Pu", "jpu@apple.com"), Committer("Jocelyn Turcotte", "jocelyn.turcotte@nokia.com", "jturcotte"), @@ -334,6 +333,7 @@ committers_unable_to_review = [ Committer("Shawn Singh", "shawnsingh@chromium.org", "shawnsingh"), Committer("Shinya Kawanaka", "shinyak@chromium.org", "shinyak"), Committer("Siddharth Mathur", "siddharth.mathur@nokia.com", "simathur"), + Committer("Stephen Chenney", "schenney@chromium.org", "schenney"), Committer("Steve Lacey", "sjl@chromium.org", "stevela"), Committer("Takashi Toyoshima", "toyoshim@chromium.org", "toyoshim"), Committer("Thomas Sepez", "tsepez@chromium.org", "tsepez"), @@ -374,10 +374,11 @@ committers_unable_to_review = [ reviewers_list = [ Reviewer("Ada Chan", "adachan@apple.com", "chanada"), Reviewer("Adam Barth", "abarth@webkit.org", "abarth"), - Reviewer("Adam Roben", "aroben@apple.com", "aroben"), + Reviewer("Adam Roben", ["aroben@webkit.org", "aroben@apple.com"], "aroben"), Reviewer("Adam Treat", ["treat@kde.org", "treat@webkit.org", "atreat@rim.com"], "manyoso"), - Reviewer("Alejandro G. Castro", ["alex@igalia.com", "alex@webkit.org"], "alexg__"), Reviewer("Adele Peterson", "adele@apple.com", "adele"), + Reviewer("Adrienne Walker", ["enne@google.com", "enne@chromium.org"], "enne"), + Reviewer("Alejandro G. Castro", ["alex@igalia.com", "alex@webkit.org"], "alexg__"), Reviewer("Alexey Proskuryakov", ["ap@webkit.org", "ap@apple.com"], "ap"), Reviewer("Alice Liu", "alice.liu@apple.com", "aliu"), Reviewer("Alp Toker", ["alp@nuanti.com", "alp@atoker.com", "alp@webkit.org"], "alp"), @@ -428,6 +429,7 @@ reviewers_list = [ Reviewer("James Robinson", ["jamesr@chromium.org", "jamesr@google.com"], "jamesr"), Reviewer("Jan Alonzo", ["jmalonzo@gmail.com", "jmalonzo@webkit.org"], "janm"), Reviewer("Jeremy Orlow", ["jorlow@webkit.org", "jorlow@chromium.org"], "jorlow"), + Reviewer("Jessie Berlin", ["jberlin@webkit.org", "jberlin@apple.com"], "jessieberlin"), Reviewer("Jian Li", "jianli@chromium.org", "jianli"), Reviewer("John Sullivan", "sullivan@apple.com", "sullivan"), Reviewer("Jon Honeycutt", "jhoneycutt@apple.com", "jhoneycutt"), diff --git a/Tools/Scripts/webkitpy/common/config/committers_unittest.py b/Tools/Scripts/webkitpy/common/config/committers_unittest.py index 53d9c4d14..1c8c86a1a 100644 --- a/Tools/Scripts/webkitpy/common/config/committers_unittest.py +++ b/Tools/Scripts/webkitpy/common/config/committers_unittest.py @@ -7,8 +7,7 @@ # * 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 +# 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 @@ -110,141 +109,205 @@ class CommittersTest(unittest.TestCase): expected_names = [name_of_expected_contributor] if name_of_expected_contributor else [] self.assertEqual(([contributor.full_name for contributor in contributors], distance), (expected_names, expected_distance)) + # Basic testing of the edit distance matching ... def test_contributors_by_fuzzy_match(self): self._assert_fuzz_match('Geoff Garen', 'Geoffrey Garen', 3) self._assert_fuzz_match('Kenneth Christiansen', 'Kenneth Rohde Christiansen', 6) - self._assert_fuzz_match('Ken Russell', 'Kenneth Russell', 4) - self._assert_fuzz_match('Dave Hyatt', 'David Hyatt', 2) - self._assert_fuzz_match('Dave Kilzer', 'David Kilzer', 2) - self._assert_fuzz_match('Antti "printf" Koivisto', 'Antti Koivisto', 9) - self._assert_fuzz_match('Sammy Weinig', 'Sam Weinig', 2) - self._assert_fuzz_match('Andres Kling', 'Andreas Kling', 1) - self._assert_fuzz_match('Darin Adler\'', 'Darin Adler', 1) - self._assert_fuzz_match('Joe Pecoraro', 'Joseph Pecoraro', 3) - self._assert_fuzz_match('Dr Dan Bernstein', 'Dan Bernstein', 3) - self._assert_fuzz_match('Mitzpettel', 'Dan Bernstein', 0) - self._assert_fuzz_match('rniwa@webkit.org', 'Ryosuke Niwa', 0) - self._assert_fuzz_match('Ap', 'Alexey Proskuryakov', 0) self._assert_fuzz_match('Sam', 'Sam Weinig', 0) - self._assert_fuzz_match('darin', 'Darin Adler', 0) - self._assert_fuzz_match('harrison', 'David Harrison', 0) self._assert_fuzz_match('me', None, 2) + + # The remaining tests test that certain names are resolved in a specific way. + # We break this up into multiple tests so that each is faster and they can + # be run in parallel. Unfortunately each test scans the entire committers list, + # so these are inherently slow (see https://bugs.webkit.org/show_bug.cgi?id=79179). + # + # Commented out lines are test cases imported from the bug 26533 yet to pass. + + def integration_test_contributors__none(self): self._assert_fuzz_match('myself', None, 6) self._assert_fuzz_match('others', None, 6) self._assert_fuzz_match('BUILD FIX', None, 9) + + def integration_test_contributors__none_2(self): self._assert_fuzz_match('but Dan Bernstein also reviewed', None, 31) self._assert_fuzz_match('asked thoughtful questions', None, 26) self._assert_fuzz_match('build fix of mac', None, 16) + + def integration_test_contributors__none_3(self): self._assert_fuzz_match('a spell checker', None, 15) self._assert_fuzz_match('nobody, build fix', None, 17) self._assert_fuzz_match('NOBODY (chromium build fix)', None, 27) - def test_contributors_by_fuzzy_match_with_legacy_names(self): - # Commented out lines are test cases imported from the bug 26533 yet to pass. - + def integration_test_contributors_ada_chan(self): self._assert_fuzz_match('Ada', 'Ada Chan', 0) + + def integration_test_contributors_adele_peterson(self): self._assert_fuzz_match('adele', 'Adele Peterson', 0) -# self._assert_fuzz_match('Adam', 'Adam Roben', 0) + + def integration_test_contributors_adele_peterson(self): + # self._assert_fuzz_match('Adam', 'Adam Roben', 0) self._assert_fuzz_match('aroben', 'Adam Roben', 0) -# self._assert_fuzz_match('Alexey', 'Alexey Proskuryakov', 0) + + def integration_test_contributors_alexey_proskuryakov(self): + # self._assert_fuzz_match('Alexey', 'Alexey Proskuryakov', 0) self._assert_fuzz_match('ap', 'Alexey Proskuryakov', 0) self._assert_fuzz_match('Alexey P', 'Alexey Proskuryakov', 0) -# self._assert_fuzz_match('Alice', 'Alice Liu', 0) + + def integration_test_contributors_alice_liu(self): + # self._assert_fuzz_match('Alice', 'Alice Liu', 0) self._assert_fuzz_match('aliu', 'Alice Liu', 0) self._assert_fuzz_match('Liu', 'Alice Liu', 0) + + def integration_test_contributors_alp_toker(self): self._assert_fuzz_match('Alp', 'Alp Toker', 0) + + def integration_test_contributors_anders_carlsson(self): self._assert_fuzz_match('Anders', 'Anders Carlsson', 0) self._assert_fuzz_match('andersca', 'Anders Carlsson', 0) self._assert_fuzz_match('anders', 'Anders Carlsson', 0) self._assert_fuzz_match('Andersca', 'Anders Carlsson', 0) + + def integration_test_contributors_antti_koivisto(self): + self._assert_fuzz_match('Antti "printf" Koivisto', 'Antti Koivisto', 9) self._assert_fuzz_match('Antti', 'Antti Koivisto', 0) + def integration_test_contributors_beth_dakin(self): self._assert_fuzz_match('Beth', 'Beth Dakin', 0) self._assert_fuzz_match('beth', 'Beth Dakin', 0) self._assert_fuzz_match('bdakin', 'Beth Dakin', 0) + + def integration_test_contributors_brady_eidson(self): self._assert_fuzz_match('Brady', 'Brady Eidson', 0) self._assert_fuzz_match('bradee-oh', 'Brady Eidson', 0) + self._assert_fuzz_match('Brady', 'Brady Eidson', 0) + + def integration_test_contributors_cameron_zwarich(self): + pass # self._assert_fuzz_match('Cameron', 'Cameron Zwarich', 0) + # self._assert_fuzz_match('cpst', 'Cameron Zwarich', 1) -# self._assert_fuzz_match('Cameron', 'Cameron Zwarich', 0) -# self._assert_fuzz_match('cpst', 'Cameron Zwarich', 1) -# self._assert_fuzz_match('Chris', 'Chris Blumenberg', 0) + def integration_test_contributors_chris_blumenberg(self): + # self._assert_fuzz_match('Chris', 'Chris Blumenberg', 0) self._assert_fuzz_match('cblu', 'Chris Blumenberg', 0) + def integration_test_contributors_dan_bernstein(self): self._assert_fuzz_match('Dan', ['Dan Winship', 'Dan Bernstein'], 0) self._assert_fuzz_match('Dan B', 'Dan Bernstein', 0) -# self._assert_fuzz_match('mitz', 'Dan Bernstein', 0) + # self._assert_fuzz_match('mitz', 'Dan Bernstein', 0) self._assert_fuzz_match('Mitz Pettel', 'Dan Bernstein', 1) self._assert_fuzz_match('Mitzpettel', 'Dan Bernstein', 0) self._assert_fuzz_match('Mitz Pettel RTL', 'Dan Bernstein', 5) + + def integration_test_contributors_dan_bernstein_2(self): self._assert_fuzz_match('Teh Mitzpettel', 'Dan Bernstein', 4) -# self._assert_fuzz_match('The Mitz', 'Dan Bernstein', 0) + # self._assert_fuzz_match('The Mitz', 'Dan Bernstein', 0) + self._assert_fuzz_match('Dr Dan Bernstein', 'Dan Bernstein', 3) + def integration_test_contributors_darin_adler(self): + self._assert_fuzz_match('Darin Adler\'', 'Darin Adler', 1) self._assert_fuzz_match('Darin', 'Darin Adler', 0) # Thankfully "Fisher" is longer than "Adler" + self._assert_fuzz_match('darin', 'Darin Adler', 0) + def integration_test_contributors_david_harrison(self): self._assert_fuzz_match('Dave Harrison', 'David Harrison', 2) self._assert_fuzz_match('harrison', 'David Harrison', 0) self._assert_fuzz_match('Dr. Harrison', 'David Harrison', 4) + + def integration_test_contributors_david_harrison_2(self): self._assert_fuzz_match('Dave Harrson', 'David Harrison', 3) self._assert_fuzz_match('Dave Harrsion', 'David Harrison', 4) # Damerau-Levenshtein distance is 3 + def integration_test_contributors_david_hyatt(self): + self._assert_fuzz_match('Dave Hyatt', 'David Hyatt', 2) self._assert_fuzz_match('Daddy Hyatt', 'David Hyatt', 3) -# self._assert_fuzz_match('Dave', 'David Hyatt', 0) # 'Dave' could mean harrison. + # self._assert_fuzz_match('Dave', 'David Hyatt', 0) # 'Dave' could mean harrison. self._assert_fuzz_match('hyatt', 'David Hyatt', 0) -# self._assert_fuzz_match('Haytt', 'David Hyatt', 0) # Works if we had implemented Damerau-Levenshtein distance! + # self._assert_fuzz_match('Haytt', 'David Hyatt', 0) # Works if we had implemented Damerau-Levenshtein distance! + + def integration_test_contributors_david_kilzer(self): self._assert_fuzz_match('Dave Kilzer', 'David Kilzer', 2) self._assert_fuzz_match('David D. Kilzer', 'David Kilzer', 3) self._assert_fuzz_match('ddkilzer', 'David Kilzer', 0) + + def integration_test_contributors_don_melton(self): self._assert_fuzz_match('Don', 'Don Melton', 0) self._assert_fuzz_match('Gramps', 'Don Melton', 0) -# self._assert_fuzz_match('eric', 'Eric Seidel', 0) + def integration_test_contributors_eric_seidel(self): + # self._assert_fuzz_match('eric', 'Eric Seidel', 0) self._assert_fuzz_match('Eric S', 'Eric Seidel', 0) -# self._assert_fuzz_match('MacDome', 'Eric Seidel', 0) + # self._assert_fuzz_match('MacDome', 'Eric Seidel', 0) self._assert_fuzz_match('eseidel', 'Eric Seidel', 0) -# self._assert_fuzz_match('Geof', 'Geoffrey Garen', 4) -# self._assert_fuzz_match('Geoff', 'Geoffrey Garen', 3) + def integration_test_contributors_geoffrey_garen(self): + # self._assert_fuzz_match('Geof', 'Geoffrey Garen', 4) + # self._assert_fuzz_match('Geoff', 'Geoffrey Garen', 3) self._assert_fuzz_match('Geoff Garen', 'Geoffrey Garen', 3) self._assert_fuzz_match('ggaren', 'Geoffrey Garen', 0) -# self._assert_fuzz_match('geoff', 'Geoffrey Garen', 0) + # self._assert_fuzz_match('geoff', 'Geoffrey Garen', 0) self._assert_fuzz_match('Geoffrey', 'Geoffrey Garen', 0) self._assert_fuzz_match('GGaren', 'Geoffrey Garen', 0) -# self._assert_fuzz_match('Greg', 'Greg Bolsinga', 0) + def integration_test_contributors_greg_bolsinga(self): + pass # self._assert_fuzz_match('Greg', 'Greg Bolsinga', 0) + + def integration_test_contributors_holger_freyther(self): self._assert_fuzz_match('Holger', 'Holger Freyther', 0) self._assert_fuzz_match('Holger Hans Peter Freyther', 'Holger Freyther', 11) -# self._assert_fuzz_match('john', 'John Sullivan', 0) + def integration_test_contributors_jon_sullivan(self): + # self._assert_fuzz_match('john', 'John Sullivan', 0) self._assert_fuzz_match('sullivan', 'John Sullivan', 0) + + def integration_test_contributors_jon_honeycutt(self): self._assert_fuzz_match('John Honeycutt', 'Jon Honeycutt', 1) -# self._assert_fuzz_match('Jon', 'Jon Honeycutt', 0) -# self._assert_fuzz_match('justin', 'Justin Garcia', 0) + # self._assert_fuzz_match('Jon', 'Jon Honeycutt', 0) + + def integration_test_contributors_jon_honeycutt(self): + # self._assert_fuzz_match('justin', 'Justin Garcia', 0) self._assert_fuzz_match('justing', 'Justin Garcia', 0) + def integration_test_contributors_joseph_pecoraro(self): + self._assert_fuzz_match('Joe Pecoraro', 'Joseph Pecoraro', 3) + + def integration_test_contributors_ken_kocienda(self): self._assert_fuzz_match('ken', 'Ken Kocienda', 0) self._assert_fuzz_match('kocienda', 'Ken Kocienda', 0) + + def integration_test_contributors_kenneth_russell(self): + self._assert_fuzz_match('Ken Russell', 'Kenneth Russell', 4) + + def integration_test_contributors_kevin_decker(self): self._assert_fuzz_match('kdecker', 'Kevin Decker', 0) + + def integration_test_contributors_kevin_mccullough(self): self._assert_fuzz_match('Kevin M', 'Kevin McCullough', 0) self._assert_fuzz_match('Kevin McCulough', 'Kevin McCullough', 1) self._assert_fuzz_match('mccullough', 'Kevin McCullough', 0) + def integration_test_contributors_lars_knoll(self): self._assert_fuzz_match('lars', 'Lars Knoll', 0) + + def integration_test_contributors_lars_weintraub(self): self._assert_fuzz_match('levi', 'Levi Weintraub', 0) + def integration_test_contributors_maciej_stachowiak(self): self._assert_fuzz_match('Maciej', 'Maciej Stachowiak', 0) -# self._assert_fuzz_match('mjs', 'Maciej Stachowiak', 0) + # self._assert_fuzz_match('mjs', 'Maciej Stachowiak', 0) self._assert_fuzz_match('Maciej S', 'Maciej Stachowiak', 0) -# self._assert_fuzz_match('Mark', 'Mark Rowe', 0) + def integration_test_contributors_mark_rowe(self): + # self._assert_fuzz_match('Mark', 'Mark Rowe', 0) self._assert_fuzz_match('bdash', 'Mark Rowe', 0) self._assert_fuzz_match('mrowe', 'Mark Rowe', 0) -# self._assert_fuzz_match('Brian Dash', 'Mark Rowe', 0) + # self._assert_fuzz_match('Brian Dash', 'Mark Rowe', 0) -# self._assert_fuzz_match('Niko', 'Nikolas Zimmermann', 1) + def integration_test_contributors_nikolas_zimmermann(self): + # self._assert_fuzz_match('Niko', 'Nikolas Zimmermann', 1) self._assert_fuzz_match('Niko Zimmermann', 'Nikolas Zimmermann', 3) self._assert_fuzz_match('Nikolas', 'Nikolas Zimmermann', 0) -# self._assert_fuzz_match('Oliver', 'Oliver Hunt', 0) + def integration_test_contributors_oliver_hunt(self): + # self._assert_fuzz_match('Oliver', 'Oliver Hunt', 0) self._assert_fuzz_match('Ollie', 'Oliver Hunt', 1) self._assert_fuzz_match('Olliej', 'Oliver Hunt', 0) self._assert_fuzz_match('Olliej Hunt', 'Oliver Hunt', 3) @@ -252,36 +315,54 @@ class CommittersTest(unittest.TestCase): self._assert_fuzz_match('ollie', 'Oliver Hunt', 1) self._assert_fuzz_match('ollliej', 'Oliver Hunt', 1) + def integration_test_contributors_oliver_hunt(self): self._assert_fuzz_match('Richard', 'Richard Williamson', 0) self._assert_fuzz_match('rjw', 'Richard Williamson', 0) + + def integration_test_contributors_oliver_hunt(self): self._assert_fuzz_match('Rob', 'Rob Buis', 0) self._assert_fuzz_match('rwlbuis', 'Rob Buis', 0) + def integration_test_contributors_rniwa(self): + self._assert_fuzz_match('rniwa@webkit.org', 'Ryosuke Niwa', 0) + + def disabled_integration_test_contributors_simon_fraser(self): + pass # self._assert_fuzz_match('Simon', 'Simon Fraser', 0) + + def integration_test_contributors_steve_falkenburg(self): + self._assert_fuzz_match('Sfalken', 'Steve Falkenburg', 0) + # self._assert_fuzz_match('Steve', 'Steve Falkenburg', 0) + + def integration_test_contributors_sam_weinig(self): self._assert_fuzz_match('Sam', 'Sam Weinig', 0) -# self._assert_fuzz_match('Weinig Sam', 'weinig', 0) + # self._assert_fuzz_match('Weinig Sam', 'weinig', 0) self._assert_fuzz_match('Weinig', 'Sam Weinig', 0) self._assert_fuzz_match('Sam W', 'Sam Weinig', 0) self._assert_fuzz_match('Sammy Weinig', 'Sam Weinig', 2) -# self._assert_fuzz_match('Simon', 'Simon Fraser', 0) - self._assert_fuzz_match('Sfalken', 'Steve Falkenburg', 0) -# self._assert_fuzz_match('Steve', 'Steve Falkenburg', 0) -# self._assert_fuzz_match('timo', 'Tim Omernick', 0) + def integration_test_contributors_tim_omernick(self): + # self._assert_fuzz_match('timo', 'Tim Omernick', 0) self._assert_fuzz_match('TimO', 'Tim Omernick', 0) -# self._assert_fuzz_match('Timo O', 'Tim Omernick', 0) -# self._assert_fuzz_match('Tim O.', 'Tim Omernick', 0) + # self._assert_fuzz_match('Timo O', 'Tim Omernick', 0) + # self._assert_fuzz_match('Tim O.', 'Tim Omernick', 0) self._assert_fuzz_match('Tim O', 'Tim Omernick', 0) -# self._assert_fuzz_match('Tim', 'Timothy Hatcher', 0) -# self._assert_fuzz_match('Tim H', 'Timothy Hatcher', 0) + def integration_test_contributors_timothy_hatcher(self): + # self._assert_fuzz_match('Tim', 'Timothy Hatcher', 0) + # self._assert_fuzz_match('Tim H', 'Timothy Hatcher', 0) self._assert_fuzz_match('Tim Hatcher', 'Timothy Hatcher', 4) self._assert_fuzz_match('Tim Hatcheri', 'Timothy Hatcher', 5) self._assert_fuzz_match('timothy', 'Timothy Hatcher', 0) self._assert_fuzz_match('thatcher', 'Timothy Hatcher', 1) self._assert_fuzz_match('xenon', 'Timothy Hatcher', 0) self._assert_fuzz_match('Hatcher', 'Timothy Hatcher', 0) -# self._assert_fuzz_match('TimH', 'Timothy Hatcher', 0) + # self._assert_fuzz_match('TimH', 'Timothy Hatcher', 0) + def integration_test_contributors_tor_arne_vestbo(self): self._assert_fuzz_match('Tor Arne', u"Tor Arne Vestb\u00f8", 1) # Matches IRC nickname + + def integration_test_contributors_vicki_murley(self): self._assert_fuzz_match('Vicki', u"Vicki Murley", 0) + + def integration_test_contributors_zack_rusin(self): self._assert_fuzz_match('Zack', 'Zack Rusin', 0) diff --git a/Tools/Scripts/webkitpy/common/config/watchlist b/Tools/Scripts/webkitpy/common/config/watchlist index bf92f05da..dbdbd392d 100755 --- a/Tools/Scripts/webkitpy/common/config/watchlist +++ b/Tools/Scripts/webkitpy/common/config/watchlist @@ -21,14 +21,19 @@ "ChromiumPublicApi": { "filename": r"Source/WebKit/chromium/public/" }, + "ChromiumPlatformApi": { + "filename": r"Source/Platform/chromium/public/" + }, "AppleMacPublicApi": { "filename": r"Source/WebCore/bindings/objc/PublicDOMInterfaces.h" }, "Forms": { - "filename": r"Source/WebCore/html/HTML(FieldSet|Form|FormControl|Input|Label" - r"|OptGroup|Option|Select|TextArea|TextFormControl)Element\." + "filename": r"Source/WebCore/html/HTML(DataList|FieldSet|Form|FormControl|Input|Keygen|Label" + r"|Legend|OptGroup|Option|Output|Select|TextArea|TextFormControl)Element\." + r"|Source/WebCore/html/FormAssociatedElement\." r"|Source/WebCore/html/\w*InputType\." - r"|Source/WebCore/rendering/Render(ListBox|MenuList|Slider|TextControl" + r"|Source/WebCore/html/shadow/(SliderThumbElement|TextControlInnerElements)\." + r"|Source/WebCore/rendering/Render(FileUploadControl|ListBox|MenuList|Slider|TextControl" r"|TextControlMultiLine|TextControlSingleLine)\." }, "GStreamerGraphics": { @@ -133,6 +138,9 @@ "SoupNetwork": { "filename": r"Source/WebCore/platform/network/soup/", }, + "ScrollingCoordinator": { + "filename": r"Source/WebCore/page/scrolling/", + } }, "CC_RULES": { # Note: All email addresses listed must be registered with bugzilla. @@ -140,7 +148,8 @@ # two different accounts as far as bugzilla is concerned. "ChromiumDumpRenderTree": [ "tkent@chromium.org", ], "ChromiumGraphics": [ "jamesr@chromium.org", "cc-bugs@google.com" ], - "ChromiumPublicApi": [ "fishd@chromium.org", ], + "ChromiumPublicApi": [ "abarth@webkit.org", "fishd@chromium.org" ], + "ChromiumPlatformApi": [ "abarth@webkit.org", "fishd@chromium.org", "jamesr@chromium.org" ], "AppleMacPublicApi": [ "timothy@apple.com" ], "Forms": [ "tkent@chromium.org", ], "GStreamerGraphics": [ "alexis.menard@openbossa.org", "pnormand@igalia.com", "gns@gnome.org" ], @@ -148,7 +157,7 @@ "StyleChecker": [ "levin@chromium.org", ], "ThreadingFiles|ThreadingUsage": [ "levin+threading@chromium.org", ], "WatchListScript": [ "levin+watchlist@chromium.org", ], - "V8Bindings|BindingsScripts": [ "abarth@webkit.org", "japhet@chromium.org" ], + "V8Bindings|BindingsScripts": [ "abarth@webkit.org", "japhet@chromium.org", "haraken@chromium.org" ], "FrameLoader": [ "abarth@webkit.org", "japhet@chromium.org" ], "Loader": [ "japhet@chromium.org" ], "SecurityCritical": [ "abarth@webkit.org" ], @@ -162,10 +171,13 @@ "EFL": [ "kubo@profusion.mobi", ], "CMake": [ "kubo@profusion.mobi", ], "SoupNetwork": [ "kubo@profusion.mobi", ], + "ScrollingCoordinator": [ "andersca@apple.com", "jamesr@chromium.org", "tonikitoo@webkit.org" ], }, "MESSAGE_RULES": { "ChromiumPublicApi": [ "Please wait for approval from fishd@chromium.org before submitting " "because this patch contains changes to the Chromium public API.", ], + "ChromiumPlatformApi": [ "Please wait for approval from fishd@chromium.org, abarth@webkit.org or jamesr@chromium.org before submitting " + "because this patch contains changes to the Chromium platform API.", ], "AppleMacPublicApi": [ "Please wait for approval from timothy@apple.com (or another member " "of the Apple Safari Team) before submitting " "because this patch contains changes to the Apple Mac " diff --git a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py index 6fb1dcaee..2ff688af7 100644 --- a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py +++ b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py @@ -110,6 +110,8 @@ class MockFileSystem(object): raise IOError(errno.EISDIR, source, os.strerror(errno.ISDIR)) if self.isdir(destination): raise IOError(errno.EISDIR, destination, os.strerror(errno.ISDIR)) + if not self.exists(self.dirname(destination)): + raise IOError(errno.ENOENT, destination, os.strerror(errno.ENOENT)) self.files[destination] = self.files[source] self.written_files[destination] = self.files[source] diff --git a/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py b/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py index 38f75bdac..6375820cd 100644 --- a/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py +++ b/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py @@ -198,11 +198,14 @@ class SingleTestRunner: if driver_output.crash: failures.append(test_failures.FailureCrash(bool(reference_filename))) - _log.debug("%s Stacktrace for %s:\n%s" % (self._worker_name, testname, - driver_output.error)) + if driver_output.error: + _log.debug("%s %s crashed, stack trace:" % (self._worker_name, testname)) + else: + _log.debug("%s %s crashed, no stack trace" % (self._worker_name, testname)) elif driver_output.error: - _log.debug("%s %s output stderr lines:\n%s" % (self._worker_name, testname, - driver_output.error)) + _log.debug("%s %s output stderr lines:" % (self._worker_name, testname)) + for line in driver_output.error.splitlines(): + _log.debug(" %s" % line) return failures def _compare_output(self, driver_output, expected_driver_output): @@ -266,7 +269,7 @@ class SingleTestRunner: failures.append(test_failures.FailureImageHashMismatch(diff_result[1])) else: # See https://bugs.webkit.org/show_bug.cgi?id=69444 for why this isn't a full failure. - _log.warning('%s -> pixel hash failed (but pixel test still passes)' % self._test_name) + _log.warning(' %s -> pixel hash failed (but pixel test still passes)' % self._test_name) return failures def _run_reftest(self): diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base.py b/Tools/Scripts/webkitpy/layout_tests/port/base.py index 1b86bfe0d..11aa5081c 100755 --- a/Tools/Scripts/webkitpy/layout_tests/port/base.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/base.py @@ -379,6 +379,11 @@ class Port(object): platform_dir, baseline_filename = self.expected_baselines(test_name, suffix)[0] if platform_dir: return self._filesystem.join(platform_dir, baseline_filename) + + actual_test_name = self.lookup_virtual_test_base(test_name) + if actual_test_name: + return self.expected_filename(actual_test_name, suffix) + return self._filesystem.join(self.layout_tests_dir(), baseline_filename) def expected_checksum(self, test_name): @@ -459,6 +464,9 @@ class Port(object): def tests(self, paths): """Return the list of tests found.""" + return self._real_tests(paths).union(self._virtual_tests(paths, self.populated_virtual_test_suites())) + + def _real_tests(self, paths): # When collecting test cases, skip these directories skipped_directories = set(['.svn', '_svn', 'resources', 'script-tests', 'reference', 'reftest']) files = find_files.find(self._filesystem, self.layout_tests_dir(), paths, skipped_directories, Port._is_test_file) @@ -498,22 +506,26 @@ class Port(object): def test_isfile(self, test_name): """Return True if the test name refers to a directory of tests.""" # Used by test_expectations.py to apply rules to whole directories. - test_path = self.abspath_for_test(test_name) - return self._filesystem.isfile(test_path) + if self._filesystem.isfile(self.abspath_for_test(test_name)): + return True + base = self.lookup_virtual_test_base(test_name) + return base and self._filesystem.isfile(self.abspath_for_test(base)) @memoized def test_isdir(self, test_name): """Return True if the test name refers to a directory of tests.""" # Used by test_expectations.py to apply rules to whole directories. - test_path = self.abspath_for_test(test_name) - return self._filesystem.isdir(test_path) + if self._filesystem.isdir(self.abspath_for_test(test_name)): + return True + base = self.lookup_virtual_test_base(test_name) + return base and self._filesystem.isdir(self.abspath_for_test(base)) + @memoized def test_exists(self, test_name): """Return True if the test name refers to an existing test or baseline.""" # Used by test_expectations.py to determine if an entry refers to a # valid test and by printing.py to determine if baselines exist. - test_path = self.abspath_for_test(test_name) - return self._filesystem.exists(test_path) + return self.test_isfile(test_name) or self.test_isdir(test_name) def split_test(self, test_name): """Splits a test name into the 'directory' part and the 'basename' part.""" @@ -533,7 +545,7 @@ class Port(object): def driver_cmd_line(self): """Prints the DRT command line that will be used.""" driver = self.create_driver(0) - return driver.cmd_line() + return driver.cmd_line(self.get_option('pixel_tests'), []) def update_baseline(self, baseline_path, data): """Updates the baseline for a test. @@ -1043,3 +1055,56 @@ class Port(object): def _driver_class(self): """Returns the port's driver implementation.""" raise NotImplementedError('Port._driver_class') + + def virtual_test_suites(self): + return [] + + @memoized + def populated_virtual_test_suites(self): + suites = self.virtual_test_suites() + + # Sanity-check the suites to make sure they don't point to other suites. + suite_dirs = [suite.name for suite in suites] + for suite in suites: + assert suite.base not in suite_dirs + + for suite in suites: + base_tests = self._real_tests([suite.base]) + suite.tests = {} + for test in base_tests: + suite.tests[test.replace(suite.base, suite.name)] = test + return suites + + def _virtual_tests(self, paths, suites): + virtual_tests = set() + for suite in suites: + if paths: + for test in suite.tests: + if any(test.startswith(p) for p in paths): + virtual_tests.add(test) + else: + virtual_tests.update(set(suite.tests.keys())) + return virtual_tests + + def lookup_virtual_test_base(self, test_name): + for suite in self.populated_virtual_test_suites(): + if test_name.startswith(suite.name): + return suite.tests.get(test_name) + return None + + def lookup_virtual_test_args(self, test_name): + for suite in self.populated_virtual_test_suites(): + if test_name.startswith(suite.name): + return suite.args + return [] + + +class VirtualTestSuite(object): + def __init__(self, name, base, args, tests=None): + self.name = name + self.base = base + self.args = args + self.tests = tests or set() + + def __repr__(self): + return "VirtualTestSuite('%s', '%s', %s)" % (self.name, self.base, self.args) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py index 8465f6019..fde05fda0 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py @@ -312,7 +312,7 @@ class PortTest(unittest.TestCase): def test_find_with_skipped_directories(self): port = self.make_port(with_tests=True) - tests = port.tests('userscripts') + tests = port.tests(['userscripts']) self.assertTrue('userscripts/resources/iframe.html' not in tests) def test_find_with_skipped_directories_2(self): @@ -406,6 +406,52 @@ class PortTest(unittest.TestCase): self.assertVirtual(port._path_to_lighttpd_php) self.assertVirtual(port._path_to_wdiff) + def test_test_exists(self): + port = self.make_port(with_tests=True) + self.assertTrue(port.test_exists('passes')) + self.assertTrue(port.test_exists('passes/text.html')) + self.assertFalse(port.test_exists('passes/does_not_exist.html')) + + self.assertTrue(port.test_exists('virtual')) + self.assertFalse(port.test_exists('virtual/does_not_exist.html')) + self.assertTrue(port.test_exists('virtual/passes/text.html')) + + def test_test_isfile(self): + port = self.make_port(with_tests=True) + self.assertFalse(port.test_isfile('passes')) + self.assertTrue(port.test_isfile('passes/text.html')) + self.assertFalse(port.test_isfile('passes/does_not_exist.html')) + + self.assertFalse(port.test_isfile('virtual')) + self.assertTrue(port.test_isfile('virtual/passes/text.html')) + self.assertFalse(port.test_isfile('virtual/does_not_exist.html')) + + def test_test_isdir(self): + port = self.make_port(with_tests=True) + self.assertTrue(port.test_isdir('passes')) + self.assertFalse(port.test_isdir('passes/text.html')) + self.assertFalse(port.test_isdir('passes/does_not_exist.html')) + self.assertFalse(port.test_isdir('passes/does_not_exist/')) + + self.assertTrue(port.test_isdir('virtual')) + self.assertFalse(port.test_isdir('virtual/does_not_exist.html')) + self.assertFalse(port.test_isdir('virtual/does_not_exist/')) + self.assertFalse(port.test_isdir('virtual/passes/text.html')) + + def test_tests(self): + port = self.make_port(with_tests=True) + tests = port.tests([]) + self.assertTrue('passes/text.html' in tests) + self.assertTrue('virtual/passes/text.html' in tests) + + tests = port.tests(['passes']) + self.assertTrue('passes/text.html' in tests) + self.assertFalse('virtual/passes/text.html' in tests) + + tests = port.tests(['virtual/passes']) + self.assertFalse('passes/text.html' in tests) + self.assertTrue('virtual/passes/text.html' in tests) + if __name__ == '__main__': unittest.main() diff --git a/Tools/Scripts/webkitpy/layout_tests/port/builders.py b/Tools/Scripts/webkitpy/layout_tests/port/builders.py index 3f7e413ce..ea6b468cd 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/builders.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/builders.py @@ -50,13 +50,7 @@ _exact_matches = { "Webkit Mac10.5 (dbg)(2)": {"port_name": "chromium-mac-leopard", "specifiers": set(["leopard", "debug"])}, "Webkit Mac10.6": {"port_name": "chromium-mac-snowleopard", "specifiers": set(["snowleopard"])}, "Webkit Mac10.6 (dbg)": {"port_name": "chromium-mac-snowleopard", "specifiers": set(["snowleopard", "debug"])}, - "Webkit Win - GPU": {"port_name": "chromium-gpu-win-xp", "specifiers": set(["xp", "release", "gpu"])}, - "Webkit Win7 - GPU": {"port_name": "chromium-gpu-win-win7", "specifiers": set(["win7", "vista", "release", "gpu"])}, - # FIXME: For some reason, these port names don't work correctly. - # "Webkit Linux - GPU": {"port_name": "chromium-gpu-linux-x86_64", "specifiers": set(["linux", "gpu"])}, - # "Webkit Linux 32 - GPU": {"port_name": "chromium-gpu-linux-x86", "specifiers": set(["linux", "x86", "gpu"])}, - "Webkit Mac10.6 (dbg) - GPU": {"port_name": "chromium-gpu-mac-snowleopard", "specifiers": set(["snowleopard", "gpu", "debug"])}, - "Webkit Mac10.6 - GPU": {"port_name": "chromium-gpu-mac-snowleopard", "specifiers": set(["snowleopard", "gpu"])}, + "Webkit Mac10.7": {"port_name": "chromium-mac-lion", "specifiers": set(["lion"]), "move_overwritten_baselines_to": "chromium-mac-snowleopard"}, # These builders are on build.webkit.org. "GTK Linux 32-bit Debug": {"port_name": "gtk", "specifiers": set(["gtk"])}, @@ -83,9 +77,6 @@ _fuzzy_matches = { _ports_without_builders = [ - # FIXME: Including chromium-gpu-linux below is a workaround for - # chromium-gpu-linux-x86_64 and chromium-gpu-linux-x86 not working properly. - "chromium-gpu-linux", "google-chrome-linux32", "google-chrome-linux64", "qt-mac", @@ -130,3 +121,7 @@ def builder_name_for_port_name(target_port_name): def builder_path_for_port_name(port_name): builder_path_from_name(builder_name_for_port_name(port_name)) + + +def fallback_port_name_for_new_port(builder_name): + return _exact_matches[builder_name].get("move_overwritten_baselines_to") diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py index 83139e0fc..f80f53bb5 100755 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py @@ -45,7 +45,7 @@ from webkitpy.common.system.path import cygpath from webkitpy.layout_tests.controllers.manager import Manager from webkitpy.layout_tests.models import test_expectations from webkitpy.layout_tests.models.test_configuration import TestConfiguration -from webkitpy.layout_tests.port.base import Port +from webkitpy.layout_tests.port.base import Port, VirtualTestSuite from webkitpy.layout_tests.port.driver import Driver, DriverOutput from webkitpy.layout_tests.port import builders from webkitpy.layout_tests.servers import http_server @@ -75,7 +75,6 @@ class ChromiumPort(Port): 'chromium-mac-lion', 'chromium-mac-snowleopard', 'chromium-mac-leopard', 'chromium-win-win7', 'chromium-win-vista', 'chromium-win-xp', 'chromium-linux-x86_64', 'chromium-linux-x86', - 'chromium-gpu-mac-snowleopard', 'chromium-gpu-win-win7', 'chromium-gpu-linux-x86_64', ] CONFIGURATION_SPECIFIER_MACROS = { @@ -342,6 +341,15 @@ class ChromiumPort(Port): repos.append(('chromium', self.path_from_chromium_base('build'))) return repos + def virtual_test_suites(self): + return [ + VirtualTestSuite('platform/chromium/virtual/gpu/fast/canvas', + 'fast/canvas', + ['--enable-accelerated-2d-canvas']), + VirtualTestSuite('platform/chromium/virtual/gpu/canvas/philip', + 'canvas/philip', + ['--enable-accelerated-2d-canvas'])] + # # PROTECTED METHODS # @@ -395,12 +403,12 @@ class ChromiumDriver(Driver): Driver.__init__(self, port, worker_number, pixel_tests, no_timeout) self._proc = None self._image_path = None - if self._pixel_tests: - self._image_path = self._port._filesystem.join(self._port.results_directory(), 'png_result%s.png' % self._worker_number) - def _wrapper_options(self): + def _wrapper_options(self, pixel_tests): cmd = [] - if self._pixel_tests: + if pixel_tests or self._pixel_tests: + if not self._image_path: + self._image_path = self._port._filesystem.join(self._port.results_directory(), 'png_result%s.png' % self._worker_number) # See note above in diff_image() for why we need _convert_path(). cmd.append("--pixel-tests=" + self._port._convert_path(self._image_path)) # FIXME: This is not None shouldn't be necessary, unless --js-flags="''" changes behavior somehow? @@ -433,21 +441,23 @@ class ChromiumDriver(Driver): cmd.extend(self._port.get_option('additional_drt_flag', [])) return cmd - def cmd_line(self): + def cmd_line(self, pixel_tests, per_test_args): cmd = self._command_wrapper(self._port.get_option('wrapper')) cmd.append(self._port._path_to_driver()) # FIXME: Why does --test-shell exist? TestShell is dead, shouldn't this be removed? # It seems it's still in use in Tools/DumpRenderTree/chromium/DumpRenderTree.cpp as of 8/10/11. cmd.append('--test-shell') - cmd.extend(self._wrapper_options()) + cmd.extend(self._wrapper_options(pixel_tests)) + cmd.extend(per_test_args) + return cmd - def _start(self): + def _start(self, pixel_tests, per_test_args): assert not self._proc # FIXME: This should use ServerProcess like WebKitDriver does. # FIXME: We should be reading stderr and stdout separately like how WebKitDriver does. close_fds = sys.platform != 'win32' - self._proc = subprocess.Popen(self.cmd_line(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=close_fds) + self._proc = subprocess.Popen(self.cmd_line(pixel_tests, per_test_args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=close_fds) def has_crashed(self): if self._proc is None: @@ -508,7 +518,7 @@ class ChromiumDriver(Driver): def run_test(self, driver_input): if not self._proc: - self._start() + self._start(driver_input.is_reftest or self._pixel_tests, driver_input.args) output = [] error = [] @@ -594,9 +604,9 @@ class ChromiumDriver(Driver): return DriverOutput(text, output_image, actual_checksum, audio=audio_bytes, crash=crash, crashed_process_name=crashed_process_name, test_time=run_time, timeout=timeout, error=error) - def start(self): + def start(self, pixel_tests, per_test_args): if not self._proc: - self._start() + self._start(pixel_tests, per_test_args) def stop(self): if not self._proc: diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py index bdb2cbb31..2b6d53625 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_android.py @@ -141,12 +141,6 @@ class ChromiumAndroidPort(chromium.ChromiumPort): def __init__(self, host, port_name, **kwargs): chromium.ChromiumPort.__init__(self, host, port_name, **kwargs) - # The chromium-android port always uses the GPU code path, so we set - # these options here, almost as if this was the chromium-gpu-android - # port. - self._options.accelerated_2d_canvas = True - self._options.accelerated_video = True - self._operating_system = 'android' self._version = 'icecreamsandwich' # FIXME: we may support other architectures in the future. @@ -401,14 +395,13 @@ class ChromiumAndroidPort(chromium.ChromiumPort): class ChromiumAndroidDriver(chromium.ChromiumDriver): def __init__(self, port, worker_number, pixel_tests, no_timeout=False): chromium.ChromiumDriver.__init__(self, port, worker_number, pixel_tests, no_timeout) - if self._image_path: - self._device_image_path = DEVICE_DRT_DIR + port.host.filesystem.basename(self._image_path) + self._device_image_path = None - def _start(self): + def _start(self, pixel_tests, per_test_args): # Convert the original command line into to two parts: # - the 'adb shell' command line to start an interactive adb shell; # - the DumpRenderTree command line to send to the adb shell. - original_cmd = self.cmd_line() + original_cmd = self.cmd_line(pixel_tests, per_test_args) shell_cmd = [] drt_args = [] path_to_driver = self._port._path_to_driver() @@ -421,6 +414,8 @@ class ChromiumAndroidDriver(chromium.ChromiumDriver): shell_cmd.append(param) else: if param.startswith('--pixel-tests='): + if not self._device_image_path: + self._device_image_path = DEVICE_DRT_DIR + self._port.host.filesystem.basename(self._image_path) param = '--pixel-tests=' + self._device_image_path drt_args.append(param) @@ -430,10 +425,10 @@ class ChromiumAndroidDriver(chromium.ChromiumDriver): while True: _log.debug('Starting adb shell for DumpRenderTree: ' + ' '.join(shell_cmd)) executive = self._port.host.executive - self._proc = executive.Popen(shell_cmd, stdin=executive.PIPE, stdout=executive.PIPE, stderr=executive.STDOUT, close_fds=True) - # Read back the shell prompt ('# ') to ensure adb shell ready. - prompt = self._proc.stdout.read(2) - assert(prompt == '# ') + self._proc = executive.popen(shell_cmd, stdin=executive.PIPE, stdout=executive.PIPE, stderr=executive.STDOUT, + close_fds=True, universal_newlines=True) + # Read back the shell prompt to ensure adb shell ready. + self._read_prompt() # Some tests rely on this to produce proper number format etc., # e.g. fast/speech/input-appearance-numberandspeech.html. self._write_command_and_read_line("export LC_CTYPE='en_US'\n") @@ -526,3 +521,14 @@ class ChromiumAndroidDriver(chromium.ChromiumDriver): # (which causes Shell to output a message), and dumps the stack strace. # We use the Shell output as a crash hint. return line is not None and line.find('[1] + Stopped (signal)') >= 0 + + def _read_prompt(self): + last_char = '' + while True: + current_char = self._proc.stdout.read(1) + if current_char == ' ': + if last_char == '#': + return + if last_char == '$': + raise AssertionError('Adbd is not running as root') + last_char = current_char diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py deleted file mode 100644 index fdc1117c9..000000000 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2010 Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * 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. - -# 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 sys - -import chromium_linux -import chromium_mac -import chromium_win - - -# FIXME: This whole file needs to go away and we need to eliminate the GPU configuration. - -def _set_gpu_options(port, graphics_type='gpu'): - port._graphics_type = graphics_type - if port.get_option('accelerated_2d_canvas') is None: - port._options.accelerated_2d_canvas = True - if port.get_option('accelerated_video') is None: - port._options.accelerated_video = True - if port.get_option('experimental_fully_parallel') is None: - port._options.experimental_fully_parallel = True - - # FIXME: Remove this after http://codereview.chromium.org/5133001/ is enabled - # on the bots. - if port.get_option('builder_name') is not None and not ' - GPU' in port._options.builder_name: - port._options.builder_name += ' - GPU' - - -def _default_tests_paths(port): - paths = [] - if port.name() != 'chromium-gpu-mac-leopard': - # Only run tests requiring accelerated compositing on platforms that - # support it. - # FIXME: we should add the above paths here as well but let's test - # the waters with media first. - paths += ['media'] - - paths += ['fast/canvas', 'canvas/philip'] - - if not paths: - # FIXME: This is a hack until we can turn off the webkit_gpu - # tests on the bots. If paths is empty, port.tests() - # finds *everything*. However, we have to return something, - # or NRWT thinks there's something wrong. So, we return a single - # short directory. See https://bugs.webkit.org/show_bug.cgi?id=72498. - paths = ['fast/html'] - - return paths - - -class ChromiumGpuLinuxPort(chromium_linux.ChromiumLinuxPort): - port_name = 'chromium-gpu-linux' - - def __init__(self, host, port_name, **kwargs): - chromium_linux.ChromiumLinuxPort.__init__(self, host, port_name, **kwargs) - _set_gpu_options(self) - - def baseline_search_path(self): - # Mimic the Linux -> Win expectations fallback in the ordinary Chromium port. - return (map(self._webkit_baseline_path, ['chromium-gpu-linux', 'chromium-gpu-win', 'chromium-gpu']) + - chromium_linux.ChromiumLinuxPort.baseline_search_path(self)) - - def tests(self, paths): - paths = paths or _default_tests_paths(self) - return chromium_linux.ChromiumLinuxPort.tests(self, paths) - - -class ChromiumGpuMacPort(chromium_mac.ChromiumMacPort): - port_name = 'chromium-gpu-mac' - - def __init__(self, host, port_name, **kwargs): - chromium_mac.ChromiumMacPort.__init__(self, host, port_name, **kwargs) - _set_gpu_options(self) - - def baseline_search_path(self): - return (map(self._webkit_baseline_path, ['chromium-gpu-mac', 'chromium-gpu']) + - chromium_mac.ChromiumMacPort.baseline_search_path(self)) - - def tests(self, paths): - paths = paths or _default_tests_paths(self) - return chromium_mac.ChromiumMacPort.tests(self, paths) - - -class ChromiumGpuWinPort(chromium_win.ChromiumWinPort): - port_name = 'chromium-gpu-win' - - def __init__(self, host, port_name, **kwargs): - chromium_win.ChromiumWinPort.__init__(self, host, port_name, **kwargs) - _set_gpu_options(self) - - def baseline_search_path(self): - return (map(self._webkit_baseline_path, ['chromium-gpu-win', 'chromium-gpu']) + - chromium_win.ChromiumWinPort.baseline_search_path(self)) - - def tests(self, paths): - paths = paths or _default_tests_paths(self) - return chromium_win.ChromiumWinPort.tests(self, paths) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py deleted file mode 100755 index c96b7eb18..000000000 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2010 Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * 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. - -# 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 sys -import unittest - -from webkitpy.common.system.filesystem_mock import MockFileSystem -from webkitpy.common.system.systemhost_mock import MockSystemHost -from webkitpy.layout_tests.port import chromium_gpu -from webkitpy.layout_tests.port import port_testcase -from webkitpy.layout_tests.port.factory import PortFactory -from webkitpy.tool.mocktool import MockOptions - - -class ChromiumGpuTest(unittest.TestCase): - def integration_test_chromium_gpu_linux(self): - self.assert_port_works('chromium-gpu-linux') - self.assert_port_works('chromium-gpu-linux', 'chromium-gpu', 'linux2') - self.assert_port_works('chromium-gpu-linux', 'chromium-gpu', 'linux3') - - def integration_test_chromium_gpu_mac(self): - self.assert_port_works('chromium-gpu-mac') - self.assert_port_works('chromium-gpu-mac', 'chromium-gpu', 'darwin') - - def integration_test_chromium_gpu_win(self): - self.assert_port_works('chromium-gpu-win') - self.assert_port_works('chromium-gpu-win', 'chromium-gpu', 'win32') - self.assert_port_works('chromium-gpu-win', 'chromium-gpu', 'cygwin') - - def assert_port_works(self, port_name, input_name=None, platform=None): - host = MockSystemHost() - host.filesystem = FileSystem() # FIXME: This test should not use a real filesystem! - - # test that we got the right port - mock_options = MockOptions(accelerated_2d_canvas=None, - accelerated_video=None, - builder_name='foo', - child_processes=None) - if input_name and platform: - port = PortFactory(host).get(host, platform=platform, port_name=input_name, options=mock_options) - else: - port = PortFactory(host).get(host, port_name=port_name, options=mock_options) - self.assertTrue(port._options.accelerated_2d_canvas) - self.assertTrue(port._options.accelerated_video) - self.assertTrue(port._options.experimental_fully_parallel) - self.assertEqual(port._options.builder_name, 'foo - GPU') - - self.assertTrue(port.name().startswith(port_name)) - - # test that it has the right directories in front of the search path. - paths = port.baseline_search_path() - self.assertEqual(port._webkit_baseline_path(port_name), paths[0]) - if port_name == 'chromium-gpu-linux': - self.assertEqual(port._webkit_baseline_path('chromium-gpu-win'), paths[1]) - self.assertEqual(port._webkit_baseline_path('chromium-gpu'), paths[2]) - else: - self.assertEqual(port._webkit_baseline_path('chromium-gpu'), paths[1]) - - # Test that we're limiting to the correct directories. - # These two tests are picked mostly at random, but we make sure they - # exist separately from being filtered out by the port. - - # Note that this is using a real filesystem. - files = port.tests(None) - - path = 'fast/html/keygen.html' - self.assertTrue(port._filesystem.exists(port.abspath_for_test(path))) - self.assertFalse(path in files) - - def _assert_baseline_path(self, port_name, baseline_path): - port = PortFactory(MockSystemHost()).get(port_name) - self.assertEquals(port.name(), port_name) - self.assertEquals(port.baseline_path(), port._webkit_baseline_path(baseline_path)) - - def test_baseline_paths(self): - self._assert_baseline_path('chromium-gpu-win-vista', 'chromium-gpu-win') - self._assert_baseline_path('chromium-gpu-win-xp', 'chromium-gpu-win') - self._assert_baseline_path('chromium-gpu-win-win7', 'chromium-gpu-win') - - def test_graphics_type(self): - port = PortFactory(MockSystemHost()).get('chromium-gpu-mac') - self.assertEquals('gpu', port.graphics_type()) - - def test_default_tests_paths(self): - - def test_paths(port_name): - return chromium_gpu._default_tests_paths(PortFactory(MockSystemHost()).get(port_name)) - - self.assertEqual(test_paths('chromium-gpu-linux'), ['media', 'fast/canvas', 'canvas/philip']) - self.assertEqual(test_paths('chromium-gpu-mac-leopard'), ['fast/canvas', 'canvas/philip']) - - def test_test_files(self): - host = MockSystemHost() - files = { - '/mock-checkout/LayoutTests/canvas/philip/test.html': '', - '/mock-checkout/LayoutTests/fast/canvas/test.html': '', - '/mock-checkout/LayoutTests/fast/html/test.html': '', - '/mock-checkout/LayoutTests/media/test.html': '', - '/mock-checkout/LayoutTests/foo/bar.html': '', - } - host.filesystem = MockFileSystem(files) - - def test_paths(port_name): - return PortFactory(host).get(port_name).tests([]) - - self.assertEqual(test_paths('chromium-gpu-linux'), set(['canvas/philip/test.html', 'fast/canvas/test.html', 'media/test.html'])) - self.assertEqual(test_paths('chromium-gpu-mac-leopard'), set(['canvas/philip/test.html', 'fast/canvas/test.html'])) - - -if __name__ == '__main__': - port_testcase.main() diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py index ac0779574..a46cb5070 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py @@ -138,15 +138,15 @@ class ChromiumDriverTest(unittest.TestCase): def __init__(self): chromium.ChromiumDriver.__init__(self, mock_port, worker_number=0, pixel_tests=False) - def cmd_line(self): + def cmd_line(self, pixel_test, per_test_args): return 'python' # get_option is used to get the timeout (ms) for a process before we kill it. mock_port.get_option = lambda name: 60 * 1000 driver1 = MockDriver() - driver1._start() + driver1._start(False, []) driver2 = MockDriver() - driver2._start() + driver2._start(False, []) # It's possible for driver1 to timeout when stopping if it's sharing stdin with driver2. start_time = time.time() driver1.stop() diff --git a/Tools/Scripts/webkitpy/layout_tests/port/config_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/config_unittest.py index 51a779850..08b9af16c 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/config_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/config_unittest.py @@ -40,6 +40,9 @@ import config class ConfigTest(unittest.TestCase): + def setUp(self): + config.clear_cached_configuration() + def tearDown(self): config.clear_cached_configuration() diff --git a/Tools/Scripts/webkitpy/layout_tests/port/driver.py b/Tools/Scripts/webkitpy/layout_tests/port/driver.py index 92e6992d7..fa6e81b2e 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/driver.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/driver.py @@ -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. +import copy import re import shlex @@ -33,11 +34,12 @@ from webkitpy.common.system import path class DriverInput(object): - def __init__(self, test_name, timeout, image_hash, is_reftest): + def __init__(self, test_name, timeout, image_hash, is_reftest, args=None): self.test_name = test_name self.timeout = timeout # in ms self.image_hash = image_hash self.is_reftest = is_reftest + self.args = args or [] class DriverOutput(object): @@ -162,7 +164,7 @@ class Driver(object): def stop(self): raise NotImplementedError('Driver.stop') - def cmd_line(self): + def cmd_line(self, pixel_tests, per_test_args): raise NotImplementedError('Driver.cmd_line') @@ -172,38 +174,67 @@ class DriverProxy(object): single driver.""" def __init__(self, port, worker_number, driver_instance_constructor, pixel_tests, no_timeout): - self._driver = driver_instance_constructor(port, worker_number, pixel_tests, no_timeout) - if pixel_tests: - self._reftest_driver = self._driver - else: - self._reftest_driver = driver_instance_constructor(port, worker_number, True, no_timeout) + self._port = port + self._worker_number = worker_number + self._driver_instance_constructor = driver_instance_constructor + self._no_timeout = no_timeout + self._pixel_tests = pixel_tests + + # FIXME: We shouldn't need to create a driver until we actually run a test. + self._driver = self._make_driver(pixel_tests) + self._running_drivers = {} + self._running_drivers[self._cmd_line_as_key(pixel_tests, [])] = self._driver + + def _make_driver(self, pixel_tests): + return self._driver_instance_constructor(self._port, self._worker_number, pixel_tests, self._no_timeout) + # FIXME: this should be a @classmethod (or implemented on Port instead). def is_http_test(self, test_name): return self._driver.is_http_test(test_name) + # FIXME: this should be a @classmethod (or implemented on Port instead). def test_to_uri(self, test_name): return self._driver.test_to_uri(test_name) + # FIXME: this should be a @classmethod (or implemented on Port instead). def uri_to_test(self, uri): return self._driver.uri_to_test(uri) def run_test(self, driver_input): - if driver_input.is_reftest: - return self._reftest_driver.run_test(driver_input) - return self._driver.run_test(driver_input) + base = self._port.lookup_virtual_test_base(driver_input.test_name) + if base: + virtual_driver_input = copy.copy(driver_input) + virtual_driver_input.test_name = base + virtual_driver_input.args = self._port.lookup_virtual_test_args(driver_input.test_name) + return self.run_test(virtual_driver_input) - def has_crashed(self): - return self._driver.has_crashed() or self._reftest_driver.has_crashed() + pixel_tests_needed = self._pixel_tests or driver_input.is_reftest + cmd_line_key = self._cmd_line_as_key(pixel_tests_needed, driver_input.args) + if not cmd_line_key in self._running_drivers: + self._running_drivers[cmd_line_key] = self._make_driver(pixel_tests_needed) + + return self._running_drivers[cmd_line_key].run_test(driver_input) def start(self): - self._driver.start() + # FIXME: Callers shouldn't normally call this, since this routine + # may not be specifying the correct combination of pixel test and + # per_test args. + # + # The only reason we have this routine at all is so the perftestrunner + # can pause before running a test; it might be better to push that + # into run_test() directly. + self._driver.start(self._pixel_tests, []) + + def has_crashed(self): + return any(driver.has_crashed() for driver in self._running_drivers.values()) def stop(self): - self._driver.stop() - self._reftest_driver.stop() - - def cmd_line(self): - cmd_line = self._driver.cmd_line() - if self._driver != self._reftest_driver: - cmd_line += ['; '] + self._reftest_driver.cmd_line() - return cmd_line + for driver in self._running_drivers.values(): + driver.stop() + + # FIXME: this should be a @classmethod (or implemented on Port instead). + def cmd_line(self, pixel_tests=None, per_test_args=None): + return self._driver.cmd_line(pixel_tests or self._pixel_tests, per_test_args or []) + + def _cmd_line_as_key(self, pixel_tests, per_test_args): + return ' '.join(self.cmd_line(pixel_tests, per_test_args)) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/driver_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/driver_unittest.py index d0a510f9d..08d4d9882 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/driver_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/driver_unittest.py @@ -91,7 +91,7 @@ class DriverTest(unittest.TestCase): driver = Driver(self.make_port(), None, pixel_tests=False) self.assertVirtual(driver.run_test, None) self.assertVirtual(driver.stop) - self.assertVirtual(driver.cmd_line) + self.assertVirtual(driver.cmd_line, False, []) def test_command_wrapper(self): self._assert_wrapper(None, []) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/factory.py b/Tools/Scripts/webkitpy/layout_tests/port/factory.py index 059186eee..092106019 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/factory.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/factory.py @@ -43,9 +43,6 @@ class BuilderOptions(object): class PortFactory(object): PORT_CLASSES = ( 'chromium_android.ChromiumAndroidPort', - 'chromium_gpu.ChromiumGpuLinuxPort', - 'chromium_gpu.ChromiumGpuMacPort', - 'chromium_gpu.ChromiumGpuWinPort', 'chromium_linux.ChromiumLinuxPort', 'chromium_mac.ChromiumMacPort', 'chromium_win.ChromiumWinPort', @@ -87,10 +84,6 @@ class PortFactory(object): if port_name == 'chromium': port_name = 'chromium-' + self._host.platform.os_name - # FIXME: Remove this when we remove the chromium-gpu ports. - if port_name == 'chromium-gpu': - port_name = port_name + '-' + self._host.platform.os_name - for port_class in self.PORT_CLASSES: module_name, class_name = port_class.rsplit('.', 1) module = __import__(module_name, globals(), locals(), [], -1) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/factory_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/factory_unittest.py index e6478eefc..9fc20582f 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/factory_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/factory_unittest.py @@ -31,7 +31,6 @@ import unittest from webkitpy.tool.mocktool import MockOptions from webkitpy.common.system.systemhost_mock import MockSystemHost -from webkitpy.layout_tests.port import chromium_gpu from webkitpy.layout_tests.port import chromium_linux from webkitpy.layout_tests.port import chromium_mac from webkitpy.layout_tests.port import chromium_win @@ -96,23 +95,6 @@ class FactoryTest(unittest.TestCase): def test_qt(self): self.assert_port(port_name='qt', cls=qt.QtPort) - def test_chromium_gpu(self): - self.assert_port(port_name='chromium-gpu', os_name='mac', os_version='leopard', - cls=chromium_gpu.ChromiumGpuMacPort) - self.assert_port(port_name='chromium-gpu', os_name='win', os_version='xp', - cls=chromium_gpu.ChromiumGpuWinPort) - self.assert_port(port_name='chromium-gpu', os_name='linux', os_version='lucid', - cls=chromium_gpu.ChromiumGpuLinuxPort) - - def test_chromium_gpu_linux(self): - self.assert_port(port_name='chromium-gpu-linux', cls=chromium_gpu.ChromiumGpuLinuxPort) - - def test_chromium_gpu_mac(self): - self.assert_port(port_name='chromium-gpu-mac-leopard', cls=chromium_gpu.ChromiumGpuMacPort) - - def test_chromium_gpu_win(self): - self.assert_port(port_name='chromium-gpu-win-xp', cls=chromium_gpu.ChromiumGpuWinPort) - def test_chromium_mac(self): self.assert_port(port_name='chromium-mac-leopard', cls=chromium_mac.ChromiumMacPort) self.assert_port(port_name='chromium-mac', os_name='mac', os_version='leopard', diff --git a/Tools/Scripts/webkitpy/layout_tests/port/gtk.py b/Tools/Scripts/webkitpy/layout_tests/port/gtk.py index c9ee1cbfe..4f8c01ff2 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/gtk.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/gtk.py @@ -40,7 +40,7 @@ _log = logging.getLogger(__name__) class GtkDriver(WebKitDriver): - def _start(self): + def _start(self, pixel_tests, per_test_args): # Use even displays for pixel tests and odd ones otherwise. When pixel tests are disabled, # DriverProxy creates two drivers, one for normal and the other for ref tests. Both have # the same worker number, so this prevents them from using the same Xvfb instance. @@ -54,7 +54,7 @@ class GtkDriver(WebKitDriver): environment = self._port.setup_environ_for_server(server_name) # We must do this here because the DISPLAY number depends on _worker_number environment['DISPLAY'] = ":%d" % (display_id) - self._server_process = ServerProcess(self._port, server_name, self.cmd_line(), environment) + self._server_process = ServerProcess(self._port, server_name, self.cmd_line(pixel_tests, per_test_args), environment) def stop(self): WebKitDriver.stop(self) @@ -64,9 +64,9 @@ class GtkDriver(WebKitDriver): self._xvfb_process.wait() self._xvfb_process = None - def cmd_line(self): + def cmd_line(self, pixel_tests, per_test_args): wrapper_path = self._port.path_from_webkit_base("Tools", "gtk", "run-with-jhbuild") - return [wrapper_path] + WebKitDriver.cmd_line(self) + return [wrapper_path] + WebKitDriver.cmd_line(self, pixel_tests, per_test_args) class GtkPort(WebKitPort): @@ -81,6 +81,7 @@ class GtkPort(WebKitPort): def setup_environ_for_server(self, server_name=None): environment = WebKitPort.setup_environ_for_server(self, server_name) environment['GTK_MODULES'] = 'gail' + environment['GSETTINGS_BACKEND'] = 'memory' environment['LIBOVERLAY_SCROLLBAR'] = '0' environment['TEST_RUNNER_INJECTED_BUNDLE_FILENAME'] = self._build_path('Libraries', 'libTestRunnerInjectedBundle.la') environment['TEST_RUNNER_TEST_PLUGIN_PATH'] = self._build_path('TestNetscapePlugin', '.libs') diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mock_drt.py b/Tools/Scripts/webkitpy/layout_tests/port/mock_drt.py index cbb6bb6ce..3d41ebdde 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/mock_drt.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/mock_drt.py @@ -93,8 +93,8 @@ class MockDRTPort(object): @staticmethod def _overriding_cmd_line(original_cmd_line, driver_path, python_exe, this_file, port_name): - def new_cmd_line(): - cmd_line = original_cmd_line() + def new_cmd_line(pixel_tests, per_test_args): + cmd_line = original_cmd_line(pixel_tests, per_test_args) index = cmd_line.index(driver_path) cmd_line[index:index + 1] = [python_exe, this_file, '--platform', port_name] return cmd_line @@ -275,6 +275,7 @@ class MockChromiumDRT(MockDRT): self._stdout.write("#URL:%s\n" % self._driver.test_to_uri(test_input.test_name)) if self._options.pixel_tests and (test_input.image_hash or test_input.is_reftest): self._stdout.write("#MD5:%s\n" % output.image_hash) + self._host.filesystem.maybe_make_directory(self._host.filesystem.dirname(self._options.pixel_path)) self._host.filesystem.write_binary_file(self._options.pixel_path, output.image) self._stdout.write(output.text) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test.py b/Tools/Scripts/webkitpy/layout_tests/port/test.py index 199460d57..e1132cbaa 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/test.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/test.py @@ -32,6 +32,7 @@ import sys import time from webkitpy.layout_tests.port import Port, Driver, DriverOutput +from webkitpy.layout_tests.port.base import VirtualTestSuite from webkitpy.layout_tests.models.test_configuration import TestConfiguration from webkitpy.common.system.filesystem_mock import MockFileSystem @@ -159,6 +160,7 @@ layer at (0,0) size 800x34 tests.add('http/tests/passes/text.html') tests.add('http/tests/passes/image.html') tests.add('http/tests/ssl/text.html') + tests.add('passes/args.html') tests.add('passes/error.html', error='stuff going to stderr') tests.add('passes/image.html') tests.add('passes/audio.html', @@ -304,6 +306,7 @@ WONTFIX SKIP : failures/expected/exception.html = CRASH add_file(test, '-expected.txt', test.expected_text) add_file(test, '-expected.png', test.expected_image) + filesystem.write_text_file(filesystem.join(LAYOUT_TEST_DIR, 'virtual', 'passes', 'args-expected.txt'), 'args-txt --virtual-arg') # Clear the list of written files so that we can watch what happens during testing. filesystem.clear_written_files() @@ -352,7 +355,7 @@ class TestPort(Port): def _path_to_driver(self): # This routine shouldn't normally be called, but it is called by # the mock_drt Driver. We return something, but make sure it's useless. - return 'junk' + return 'MOCK _path_to_driver' def baseline_search_path(self): search_paths = { @@ -489,16 +492,22 @@ class TestPort(Port): def all_baseline_variants(self): return self.ALL_BASELINE_VARIANTS + def virtual_test_suites(self): + return [ + VirtualTestSuite('virtual/passes', 'passes', ['--virtual-arg']), + ] class TestDriver(Driver): """Test/Dummy implementation of the DumpRenderTree interface.""" - def cmd_line(self): - return [self._port._path_to_driver()] + self._port.get_option('additional_drt_flag', []) + def cmd_line(self, pixel_tests, per_test_args): + pixel_tests_flag = '-p' if pixel_tests else '' + return [self._port._path_to_driver()] + [pixel_tests_flag] + self._port.get_option('additional_drt_flag', []) + per_test_args def run_test(self, test_input): start_time = time.time() test_name = test_input.test_name + test_args = test_input.args or [] test = self._port._tests[test_name] if test.keyboard: raise KeyboardInterrupt @@ -508,6 +517,10 @@ class TestDriver(Driver): time.sleep((float(test_input.timeout) * 4) / 1000.0) audio = None + actual_text = test.actual_text + if actual_text and test_args and test_name == 'passes/args.html': + actual_text = actual_text + ' ' + ' '.join(test_args) + if test.actual_audio: audio = base64.b64decode(test.actual_audio) crashed_process_name = None @@ -515,12 +528,12 @@ class TestDriver(Driver): crashed_process_name = self._port.driver_name() elif test.web_process_crash: crashed_process_name = 'WebProcess' - return DriverOutput(test.actual_text, test.actual_image, + return DriverOutput(actual_text, test.actual_image, test.actual_checksum, audio, crash=test.crash or test.web_process_crash, crashed_process_name=crashed_process_name, test_time=time.time() - start_time, timeout=test.timeout, error=test.error) - def start(self): + def start(self, pixel_tests, per_test_args): pass def stop(self): diff --git a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py index aeb918ce0..cc3b0c716 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py @@ -464,13 +464,11 @@ class WebKitDriver(Driver): def __del__(self): self._port._filesystem.rmtree(str(self._driver_tempdir)) - def cmd_line(self): + def cmd_line(self, pixel_tests, per_test_args): cmd = self._command_wrapper(self._port.get_option('wrapper')) cmd.append(self._port._path_to_driver()) if self._port.get_option('skip_pixel_test_if_no_baseline'): cmd.append('--skip-pixel-test-if-no-baseline') - if self._pixel_tests: - cmd.append('--pixel-tests') if self._port.get_option('gc_between_tests'): cmd.append('--gc-between-tests') if self._port.get_option('complex_text'): @@ -482,10 +480,15 @@ class WebKitDriver(Driver): # FIXME: We need to pass --timeout=SECONDS to WebKitTestRunner for WebKit2. cmd.extend(self._port.get_option('additional_drt_flag', [])) + + if pixel_tests or self._pixel_tests: + cmd.append('--pixel-tests') + cmd.extend(per_test_args) + cmd.append('-') return cmd - def _start(self): + def _start(self, pixel_tests, per_test_args): server_name = self._port.driver_name() environment = self._port.setup_environ_for_server(server_name) environment['DYLD_FRAMEWORK_PATH'] = self._port._build_path() @@ -493,7 +496,7 @@ class WebKitDriver(Driver): environment['DUMPRENDERTREE_TEMP'] = str(self._driver_tempdir) environment['LOCAL_RESOURCE_ROOT'] = self._port.layout_tests_dir() self._crashed_subprocess_name = None - self._server_process = server_process.ServerProcess(self._port, server_name, self.cmd_line(), environment) + self._server_process = server_process.ServerProcess(self._port, server_name, self.cmd_line(pixel_tests, per_test_args), environment) def has_crashed(self): if self._server_process is None: @@ -553,7 +556,7 @@ class WebKitDriver(Driver): def run_test(self, driver_input): if not self._server_process: - self._start() + self._start(driver_input.is_reftest or self._pixel_tests, []) self.error_from_test = str() self.err_seen_eof = False @@ -645,9 +648,9 @@ class WebKitDriver(Driver): block.decode_content() return block - def start(self): + def start(self, pixel_tests, per_test_args): if not self._server_process: - self._start() + self._start(pixel_tests, per_test_args) def stop(self): if self._server_process: diff --git a/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py index ffaae6eb7..aadbf72fd 100755 --- a/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py @@ -300,4 +300,4 @@ class WebKitDriverTest(unittest.TestCase): def test_no_timeout(self): port = TestWebKitPort() driver = WebKitDriver(port, 0, pixel_tests=True, no_timeout=True) - self.assertEquals(driver.cmd_line(), ['MOCK output of child process/DumpRenderTree', '--pixel-tests', '--no-timeout', '-']) + self.assertEquals(driver.cmd_line(True, []), ['MOCK output of child process/DumpRenderTree', '--no-timeout', '--pixel-tests', '-']) diff --git a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py index 66876cc8c..dc2e1c2b4 100755 --- a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py +++ b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py @@ -273,6 +273,10 @@ class MainTest(unittest.TestCase, StreamTestingMixin): self.assertTrue(passing_run(['--accelerated-2d-canvas'])) self.assertTrue(passing_run(['--no-accelerated-2d-canvas'])) + def test_all(self): + res, out, err, user = logging_run([], tests_included=True) + self.assertEquals(res, unexpected_tests_count) + def test_basic(self): self.assertTrue(passing_run()) @@ -748,6 +752,10 @@ class MainTest(unittest.TestCase, StreamTestingMixin): test_port = get_port_for_run(base_args) self.assertEqual(None, test_port.tolerance_used_for_diff_image) + def test_virtual(self): + self.assertTrue(passing_run(['passes/text.html', 'passes/args.html', + 'virtual/passes/text.html', 'virtual/passes/args.html'])) + def test_worker_model__inline(self): self.assertTrue(passing_run(['--worker-model', 'inline'])) diff --git a/Tools/Scripts/webkitpy/layout_tests/servers/http_server.py b/Tools/Scripts/webkitpy/layout_tests/servers/http_server.py index 1f14e0dad..8def09d0a 100755 --- a/Tools/Scripts/webkitpy/layout_tests/servers/http_server.py +++ b/Tools/Scripts/webkitpy/layout_tests/servers/http_server.py @@ -179,11 +179,11 @@ class Lighttpd(http_server_base.HttpServerBase): # bug that mod_alias.so loads it from the hard coded path. if sys.platform == 'darwin': tmp_module_path = '/tmp/lighttpd/lib' - if not os.path.exists(tmp_module_path): - os.makedirs(tmp_module_path) + if not self._filesystem.exists(tmp_module_path): + self._filesystem.maybe_make_directory(tmp_module_path) lib_file = 'liblightcomp.dylib' - self._filesystem.copyfile(os.path.join(module_path, lib_file), - os.path.join(tmp_module_path, lib_file)) + self._filesystem.copyfile(self._filesystem.join(module_path, lib_file), + self._filesystem.join(tmp_module_path, lib_file)) self._start_cmd = start_cmd self._env = self._port_obj.setup_environ_for_server('lighttpd') diff --git a/Tools/Scripts/webkitpy/layout_tests/views/printing.py b/Tools/Scripts/webkitpy/layout_tests/views/printing.py index bccbb1a7c..750c48df9 100644 --- a/Tools/Scripts/webkitpy/layout_tests/views/printing.py +++ b/Tools/Scripts/webkitpy/layout_tests/views/printing.py @@ -315,18 +315,25 @@ class Printer(object): - actual result - timing info """ - filename = self._port.abspath_for_test(result.test_name) test_name = result.test_name self._write('trace: %s' % test_name) + + base = self._port.lookup_virtual_test_base(test_name) + if base: + args = ' '.join(self._port.lookup_virtual_test_args(test_name)) + self._write(' base: %s' % base) + self._write(' args: %s' % args) + for extension in ('.txt', '.png', '.wav', '.webarchive'): - self._print_baseline(filename, extension) + self._print_baseline(test_name, extension) + self._write(' exp: %s' % exp_str) self._write(' got: %s' % got_str) self._write(' took: %-.3f' % result.test_run_time) self._write('') - def _print_baseline(self, filename, extension): - baseline = self._port.expected_filename(filename, extension) + def _print_baseline(self, test_name, extension): + baseline = self._port.expected_filename(test_name, extension) if self._port._filesystem.exists(baseline): relpath = self._port.relative_test_filename(baseline) else: diff --git a/Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py b/Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py index 189500f6a..8cc0d745e 100644 --- a/Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py +++ b/Tools/Scripts/webkitpy/performance_tests/perftestsrunner.py @@ -99,6 +99,8 @@ class PerfTestsRunner(object): help="Path to a JSON file to be merged into the JSON file when --output-json-path is present"), optparse.make_option("--test-results-server", help="Upload the generated JSON file to the specified server when --output-json-path is present"), + optparse.make_option("--webkit-test-runner", "-2", action="store_true", + help="Use WebKitTestRunner rather than DumpRenderTree."), ] option_list = (perf_option_list + print_options) @@ -302,6 +304,8 @@ class PerfTestsRunner(object): def _run_single_test(self, test, driver, is_chromium_style): test_failed = False + start_time = time.time() + output = driver.run_test(DriverInput(test, self._options.time_out_ms, None, False)) if output.text == None: @@ -325,4 +329,6 @@ class PerfTestsRunner(object): if test_failed: self._printer.write('FAILED') + self._printer.write("Finished: %f s" % (time.time() - start_time)) + return not test_failed diff --git a/Tools/Scripts/webkitpy/performance_tests/perftestsrunner_unittest.py b/Tools/Scripts/webkitpy/performance_tests/perftestsrunner_unittest.py index e194072c3..1a287a7cf 100755 --- a/Tools/Scripts/webkitpy/performance_tests/perftestsrunner_unittest.py +++ b/Tools/Scripts/webkitpy/performance_tests/perftestsrunner_unittest.py @@ -174,7 +174,7 @@ max 1120 unexpected_result_count = runner._run_tests_set(tests, runner._port) self.assertEqual(TestDriverWithStopCount.stop_count, 6) - def test_run_test_set_kills_drt_per_run(self): + def test_run_test_pause_before_testing(self): class TestDriverWithStartCount(MainTest.TestDriver): start_count = 0 @@ -195,7 +195,7 @@ max 1120 finally: _, stderr, logs = output.restore_output() self.assertEqual(stderr, "Ready to run test?\n") - self.assertEqual(logs, "Running inspector/pass.html (1 of 1)\n\n") + self.assertTrue("Running inspector/pass.html (1 of 1)" in logs) def test_run_test_set_for_parser_tests(self): buildbot_output = StringIO.StringIO() @@ -280,6 +280,10 @@ max 1120 self.assertEqual(generated_json['builder-name'], 'builder1') self.assertEqual(generated_json['build-number'], 123) upload_json_returns_true = False + + runner = self.create_runner(args=['--output-json-path=/mock-checkout/output.json', + '--test-results-server', 'some.host', '--platform', 'platform1', '--builder-name', 'builder1', '--build-number', '123']) + runner._upload_json = mock_upload_json self.assertEqual(runner.run(), -3) def test_upload_json(self): diff --git a/Tools/Scripts/webkitpy/style/checkers/changelog.py b/Tools/Scripts/webkitpy/style/checkers/changelog.py index d744bc87d..a096d3f46 100644 --- a/Tools/Scripts/webkitpy/style/checkers/changelog.py +++ b/Tools/Scripts/webkitpy/style/checkers/changelog.py @@ -68,6 +68,14 @@ class ChangeLogChecker(object): "changelog/filechangedescriptionwhitespace", 5, "Need whitespace between colon and description") + # check for a lingering "No new tests. (OOPS!)" left over from prepare-changeLog. + line_no = first_line_checked - 1 + for line in entry_lines: + line_no = line_no + 1 + if re.match('\s*No new tests. \(OOPS!\)$', line): + self.handle_style_error(line_no, + "changelog/nonewtests", 5, + "You should remove the 'No new tests' and either add and list tests, or explain why no new tests were possible.") def check(self, lines): self._tab_checker.check(lines) diff --git a/Tools/Scripts/webkitpy/style/checkers/changelog_unittest.py b/Tools/Scripts/webkitpy/style/checkers/changelog_unittest.py index 842eaa16b..9fe8a60bc 100644 --- a/Tools/Scripts/webkitpy/style/checkers/changelog_unittest.py +++ b/Tools/Scripts/webkitpy/style/checkers/changelog_unittest.py @@ -121,6 +121,14 @@ class ChangeLogCheckerTest(unittest.TestCase): ' * Source/Tools/random-script.py:Fixed\n' ' * Source/Tools/one-morefile:\n') + def test_no_new_tests(self): + self.assert_error(5, range(1, 20), 'changelog/nonewtests', + '2011-01-01 Dmitry Lomov <dslomov@google.com>\n' + ' ExampleBug\n' + ' http://bugs.webkit.org/show_bug.cgi?id=12345\n' + '\n' + ' No new tests. (OOPS!)\n' + ' * Source/Tools/random-script.py: Fixed') def test_no_error(self): self.assert_no_error([], diff --git a/Tools/Scripts/webkitpy/test/main.py b/Tools/Scripts/webkitpy/test/main.py index 78c39db55..76dac0e3b 100644 --- a/Tools/Scripts/webkitpy/test/main.py +++ b/Tools/Scripts/webkitpy/test/main.py @@ -198,7 +198,7 @@ class Tester(object): def _run_tests(self, dirs, args): if self._options.coverage: try: - import coverage + import webkitpy.thirdparty.autoinstalled.coverage as coverage except ImportError, e: _log.error("Failed to import 'coverage'; can't generate coverage numbers.") return False @@ -233,6 +233,7 @@ class Tester(object): if self._options.coverage: cov.stop() cov.save() + cov.report(show_missing=False) return result.wasSuccessful() def _is_module(self, dirs, name): diff --git a/Tools/Scripts/webkitpy/thirdparty/__init__.py b/Tools/Scripts/webkitpy/thirdparty/__init__.py index e7a12e685..2c39de6cc 100644 --- a/Tools/Scripts/webkitpy/thirdparty/__init__.py +++ b/Tools/Scripts/webkitpy/thirdparty/__init__.py @@ -74,6 +74,8 @@ class AutoinstallImportHook(object): self._install_mechanize() elif '.pep8' in fullname: self._install_pep8() + elif '.coverage' in fullname: + self._install_coverage() elif '.eliza' in fullname: self._install_eliza() elif '.irc' in fullname: @@ -108,6 +110,10 @@ class AutoinstallImportHook(object): self._install("http://pypi.python.org/packages/source/b/buildbot/buildbot-0.8.4p2.tar.gz#md5=7597d945724c80c0ab476e833a1026cb", "buildbot-0.8.4p2/buildbot") + def _install_coverage(self): + installer = AutoInstaller(target_dir=_AUTOINSTALLED_DIR) + installer.install(url="http://pypi.python.org/packages/source/c/coverage/coverage-3.5.1.tar.gz#md5=410d4c8155a4dab222f2bc51212d4a24", url_subpath="coverage-3.5.1/coverage") + def _install_eliza(self): installer = AutoInstaller(target_dir=_AUTOINSTALLED_DIR) installer.install(url="http://www.adambarth.com/webkit/eliza", diff --git a/Tools/Scripts/webkitpy/to_be_moved/rebaseline_chromium_webkit_tests.py b/Tools/Scripts/webkitpy/to_be_moved/rebaseline_chromium_webkit_tests.py deleted file mode 100644 index 27db72022..000000000 --- a/Tools/Scripts/webkitpy/to_be_moved/rebaseline_chromium_webkit_tests.py +++ /dev/null @@ -1,1044 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2010 Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * 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. - -"""Rebaselining tool that automatically produces baselines for all platforms. - -The script does the following for each platform specified: - 1. Compile a list of tests that need rebaselining. - 2. Download test result archive from buildbot for the platform. - 3. Extract baselines from the archive file for all identified files. - 4. Add new baselines to SVN repository. - 5. For each test that has been rebaselined, remove this platform option from - the test in test_expectation.txt. If no other platforms remain after - removal, delete the rebaselined test from the file. - -At the end, the script generates a html that compares old and new baselines. -""" - -import copy -import logging -import optparse -import re -import sys -import time - -from webkitpy.common.checkout import scm -from webkitpy.common.system import zipfileset -from webkitpy.common.system import path -from webkitpy.common.system import urlfetcher -from webkitpy.common.system.executive import ScriptError -from webkitpy.common.host import Host - -from webkitpy.layout_tests.port.factory import PortFactory -from webkitpy.layout_tests import read_checksum_from_png -from webkitpy.layout_tests.models import test_expectations - - -_log = logging.getLogger(__name__) - -BASELINE_SUFFIXES = ('.txt', '.png', '.checksum') - -ARCHIVE_DIR_NAME_DICT = { - 'chromium-win-win7': 'Webkit_Win7', - 'chromium-win-vista': 'Webkit_Vista', - 'chromium-win-xp': 'Webkit_Win', - 'chromium-mac-leopard': 'Webkit_Mac10_5', - 'chromium-mac-snowleopard': 'Webkit_Mac10_6', - 'chromium-linux-x86': 'Webkit_Linux_32', - 'chromium-linux-x86_64': 'Webkit_Linux', - 'chromium-gpu-mac-snowleopard': 'Webkit_Mac10_6_-_GPU', - 'chromium-gpu-win-xp': 'Webkit_Win_-_GPU', - 'chromium-gpu-win-win7': 'Webkit_Win7_-_GPU', - 'chromium-gpu-linux-x86_64': 'Webkit_Linux_-_GPU', - 'chromium-gpu-linux-x86': 'Webkit_Linux_32_-_GPU', -} - - -def log_dashed_string(text, platform=None, logging_level=logging.DEBUG): - """Log text message with dashes on both sides.""" - msg = text - if platform: - msg += ': ' + platform - if len(msg) < 78: - dashes = '-' * ((78 - len(msg)) / 2) - msg = '%s %s %s' % (dashes, msg, dashes) - _log.log(logging_level, msg) - - -def setup_html_directory(filesystem, parent_directory): - """Setup the directory to store html results. - - All html related files are stored in the "rebaseline_html" subdirectory of - the parent directory. The path to the created directory is returned. - """ - - if not parent_directory: - parent_directory = str(filesystem.mkdtemp()) - else: - filesystem.maybe_make_directory(parent_directory) - - html_directory = filesystem.join(parent_directory, 'rebaseline_html') - _log.debug('Html directory: "%s"', html_directory) - - if filesystem.exists(html_directory): - filesystem.rmtree(html_directory) - _log.debug('Deleted html directory: "%s"', html_directory) - - filesystem.maybe_make_directory(html_directory) - return html_directory - - -def get_result_file_fullpath(filesystem, html_directory, baseline_filename, platform, - result_type): - """Get full path of the baseline result file. - - Args: - filesystem: wrapper object - html_directory: directory that stores the html related files. - baseline_filename: name of the baseline file. - platform: win, linux or mac - result_type: type of the baseline result: '.txt', '.png'. - - Returns: - Full path of the baseline file for rebaselining result comparison. - """ - - base, ext = filesystem.splitext(baseline_filename) - result_filename = '%s-%s-%s%s' % (base, platform, result_type, ext) - fullpath = filesystem.join(html_directory, result_filename) - _log.debug(' Result file full path: "%s".', fullpath) - return fullpath - - -class Rebaseliner(object): - """Class to produce new baselines for a given platform.""" - - REVISION_REGEX = r'<a href=\"(\d+)/\">' - - def __init__(self, host, running_port, target_port, platform, options, url_fetcher, zip_factory, logged_before=False): - """ - Args: - running_port: the Port the script is running on. - target_port: the Port the script uses to find port-specific - configuration information like the test_expectations.txt - file location and the list of test platforms. - platform: the test platform to rebaseline - options: the command-line options object. - url_fetcher: object that can fetch objects from URLs - zip_factory: optional object that can fetch zip files from URLs - scm: scm object for adding new baselines - logged_before: whether the previous running port logged anything. - """ - self._platform = platform - self._options = options - self._port = running_port - self._filesystem = host.filesystem - self._target_port = target_port - - self._rebaseline_port = host.port_factory.get(platform, options) - self._rebaselining_tests = set() - self._rebaselined_tests = [] - self._logged_before = logged_before - self.did_log = False - - # Create tests and expectations helper which is used to: - # -. compile list of tests that need rebaselining. - # -. update the tests in test_expectations file after rebaseline - # is done. - expectations_str = self._rebaseline_port.test_expectations() - self._test_expectations = test_expectations.TestExpectations( - self._rebaseline_port, None, expectations_str, self._rebaseline_port.test_configuration(), False) - self._url_fetcher = url_fetcher - self._zip_factory = zip_factory - self._scm = host.scm() - - def run(self): - """Run rebaseline process.""" - - log_dashed_string('Compiling rebaselining tests', self._platform, logging.DEBUG) - if not self._compile_rebaselining_tests(): - return False - if not self._rebaselining_tests: - return True - - self.did_log = True - log_dashed_string('Downloading archive', self._platform, logging.DEBUG) - archive_file = self._download_buildbot_archive() - _log.debug('') - if not archive_file: - _log.error('No archive found.') - return False - - log_dashed_string('Extracting and adding new baselines', self._platform, logging.DEBUG) - self._extract_and_add_new_baselines(archive_file) - archive_file.close() - - log_dashed_string('Updating rebaselined tests in file', self._platform) - - if len(self._rebaselining_tests) != len(self._rebaselined_tests): - _log.debug('') - _log.debug('NOT ALL TESTS WERE REBASELINED.') - _log.debug(' Number marked for rebaselining: %d', len(self._rebaselining_tests)) - _log.debug(' Number actually rebaselined: %d', len(self._rebaselined_tests)) - _log.info('') - return False - - _log.debug(' All tests needing rebaselining were successfully rebaselined.') - _log.info('') - return True - - def remove_rebaselining_expectations(self, tests, backup): - """if backup is True, we backup the original test expectations file.""" - new_expectations = self._test_expectations.remove_rebaselined_tests(tests) - path = self._target_port.path_to_test_expectations_file() - if backup: - date_suffix = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())) - backup_file = '%s.orig.%s' % (path, date_suffix) - if self._filesystem.exists(backup_file): - self._filesystem.remove(backup_file) - _log.debug('Saving original file to "%s"', backup_file) - self._filesystem.move(path, backup_file) - - self._filesystem.write_text_file(path, new_expectations) - # self._scm.add(path) - - def get_rebaselined_tests(self): - return self._rebaselined_tests - - def _compile_rebaselining_tests(self): - """Compile list of tests that need rebaselining for the platform. - - Returns: - False if reftests are wrongly marked as 'needs rebaselining' or True - """ - - self._rebaselining_tests = self._test_expectations.get_rebaselining_failures() - if not self._rebaselining_tests: - _log.info('%s: No tests to rebaseline.', self._platform) - return True - - fs = self._target_port._filesystem - for test in self._rebaselining_tests: - if self._target_port.reference_files(test): - _log.error('%s seems to be a reftest. We can not rebase for reftests.', test) - self._rebaselining_tests = set() - return False - - if not self._logged_before: - _log.info('') - _log.info('%s: Rebaselining %d tests:', self._platform, len(self._rebaselining_tests)) - test_no = 1 - for test in self._rebaselining_tests: - _log.debug(' %d: %s', test_no, test) - test_no += 1 - - return True - - def _get_latest_revision(self, url): - """Get the latest layout test revision number from buildbot. - - Args: - url: Url to retrieve layout test revision numbers. - - Returns: - latest revision or - None on failure. - """ - - _log.debug('Url to retrieve revision: "%s"', url) - - content = self._url_fetcher.fetch(url) - - revisions = re.findall(self.REVISION_REGEX, content) - if not revisions: - _log.error('Failed to find revision, content: "%s"', content) - return None - - revisions.sort(key=int) - _log.debug(' Latest revision: %s', revisions[len(revisions) - 1]) - return revisions[len(revisions) - 1] - - def _get_archive_dir_name(self, platform): - """Get name of the layout test archive directory. - - Returns: - Directory name or - None on failure - """ - - if platform in ARCHIVE_DIR_NAME_DICT: - return ARCHIVE_DIR_NAME_DICT[platform] - else: - _log.error('Cannot find platform key %s in archive ' - 'directory name dictionary', platform) - return None - - def _get_archive_url(self): - """Generate the url to download latest layout test archive. - - Returns: - Url to download archive or - None on failure - """ - - if self._options.force_archive_url: - return self._options.force_archive_url - - dir_name = self._get_archive_dir_name(self._platform) - if not dir_name: - return None - - _log.debug('Buildbot platform dir name: "%s"', dir_name) - - url_base = '%s/%s/' % (self._options.archive_url, dir_name) - latest_revision = self._get_latest_revision(url_base) - if latest_revision is None or latest_revision <= 0: - return None - archive_url = '%s%s/layout-test-results.zip' % (url_base, latest_revision) - _log.info(' Using %s', archive_url) - return archive_url - - def _download_buildbot_archive(self): - """Download layout test archive file from buildbot and return a handle to it.""" - url = self._get_archive_url() - if url is None: - return None - - archive_file = zipfileset.ZipFileSet(url, filesystem=self._filesystem, - zip_factory=self._zip_factory) - _log.debug('Archive downloaded') - return archive_file - - def _extract_and_add_new_baselines(self, zip_file): - """Extract new baselines from the zip file and add them to SVN repository. - - Returns: - List of tests that have been rebaselined or None on failure.""" - zip_namelist = zip_file.namelist() - - _log.debug('zip file namelist:') - for name in zip_namelist: - _log.debug(' ' + name) - - _log.debug('Platform dir: "%s"', self._platform) - - self._rebaselined_tests = [] - for test_no, test in enumerate(self._rebaselining_tests): - _log.debug('Test %d: %s', test_no + 1, test) - self._extract_and_add_new_baseline(test, zip_file) - - def _extract_and_add_new_baseline(self, test, zip_file): - found = False - scm_error = False - test_basename = self._filesystem.splitext(test)[0] - for suffix in BASELINE_SUFFIXES: - archive_test_name = 'layout-test-results/%s-actual%s' % (test_basename, suffix) - _log.debug(' Archive test file name: "%s"', archive_test_name) - if not archive_test_name in zip_file.namelist(): - _log.debug(' %s file not in archive.', suffix) - continue - - found = True - _log.debug(' %s file found in archive.', suffix) - - temp_name = self._extract_from_zip_to_tempfile(zip_file, archive_test_name) - - expected_filename = '%s-expected%s' % (test_basename, suffix) - expected_fullpath = self._filesystem.join( - self._rebaseline_port.baseline_path(), expected_filename) - expected_fullpath = self._filesystem.normpath(expected_fullpath) - _log.debug(' Expected file full path: "%s"', expected_fullpath) - - relpath = self._filesystem.relpath(expected_fullpath, self._target_port.layout_tests_dir()) - - # TODO(victorw): for now, the rebaselining tool checks whether - # or not THIS baseline is duplicate and should be skipped. - # We could improve the tool to check all baselines in upper - # and lower levels and remove all duplicated baselines. - if self._is_dup_baseline(temp_name, expected_fullpath, test, suffix, self._platform): - self._filesystem.remove(temp_name) - if self._filesystem.exists(expected_fullpath): - _log.info(' Removing %s' % relpath) - self._delete_baseline(expected_fullpath) - _log.debug(' %s is a duplicate' % relpath) - - # FIXME: We consider a duplicate baseline a success in the normal case. - # FIXME: This may not be what you want sometimes; should this be - # FIXME: controllable? - self._rebaselined_tests.append(test) - continue - - if suffix == '.checksum' and self._png_has_same_checksum(temp_name, test, expected_fullpath): - self._filesystem.remove(temp_name) - # If an old checksum exists, delete it. - self._delete_baseline(expected_fullpath) - continue - - self._filesystem.maybe_make_directory(self._filesystem.dirname(expected_fullpath)) - self._filesystem.move(temp_name, expected_fullpath) - - path_from_base = self._filesystem.relpath(expected_fullpath) - if self._scm.exists(path_from_base): - _log.info(' Updating %s' % relpath) - else: - _log.info(' Adding %s' % relpath) - - if self._scm.add(expected_fullpath, return_exit_code=True): - # FIXME: print detailed diagnose messages - scm_error = True - elif suffix != '.checksum': - self._create_html_baseline_files(expected_fullpath) - - if not found: - _log.warn('No results in archive for %s' % test) - elif scm_error: - _log.warn('Failed to add baselines to your repository.') - else: - _log.debug(' Rebaseline succeeded.') - self._rebaselined_tests.append(test) - - def _extract_from_zip_to_tempfile(self, zip_file, filename): - """Extracts |filename| from |zip_file|, a ZipFileSet. Returns the full - path name to the extracted file.""" - data = zip_file.read(filename) - suffix = self._filesystem.splitext(filename)[1] - tempfile, temp_name = self._filesystem.open_binary_tempfile(suffix) - tempfile.write(data) - tempfile.close() - return temp_name - - def _png_has_same_checksum(self, checksum_path, test, checksum_expected_fullpath): - """Returns True if the fallback png for |checksum_expected_fullpath| - contains the same checksum.""" - fs = self._filesystem - png_fullpath = self._first_fallback_png_for_test(test) - - if not fs.exists(png_fullpath): - _log.error(' Checksum without png file found! Expected %s to exist.' % png_fullpath) - return False - - with fs.open_binary_file_for_reading(png_fullpath) as filehandle: - checksum_in_png = read_checksum_from_png.read_checksum(filehandle) - checksum_in_text_file = fs.read_text_file(checksum_path) - if checksum_in_png and checksum_in_png != checksum_in_text_file: - _log.error(" checksum in %s and %s don't match! Continuing" - " to copy but please investigate." % ( - checksum_expected_fullpath, png_fullpath)) - return checksum_in_text_file == checksum_in_png - - def _first_fallback_png_for_test(self, test): - all_baselines = self._rebaseline_port.expected_baselines(test, '.png', True) - return self._filesystem.join(all_baselines[0][0], all_baselines[0][1]) - - def _is_dup_baseline(self, new_baseline, baseline_path, test, suffix, platform): - """Check whether a baseline is duplicate and can fallback to same - baseline for another platform. For example, if a test has same - baseline on linux and windows, then we only store windows - baseline and linux baseline will fallback to the windows version. - - Args: - new_baseline: temp filename containing the new baseline results - baseline_path: baseline expectation file name. - test: test name. - suffix: file suffix of the expected results, including dot; - e.g. '.txt' or '.png'. - platform: baseline platform 'mac', 'win' or 'linux'. - - Returns: - True if the baseline is unnecessary. - False otherwise. - """ - all_baselines = self._rebaseline_port.expected_baselines(test, suffix, True) - - for fallback_dir, fallback_file in all_baselines: - if not fallback_dir or not fallback_file: - continue - - fallback_fullpath = self._filesystem.normpath( - self._filesystem.join(fallback_dir, fallback_file)) - if fallback_fullpath.lower() == baseline_path.lower(): - continue - fallback_dir_relpath = self._filesystem.relpath(fallback_dir, self._target_port.layout_tests_dir()) - if fallback_dir_relpath == '': - fallback_dir_relpath = '<generic>' - - new_output = self._filesystem.read_binary_file(new_baseline) - fallback_output = self._filesystem.read_binary_file(fallback_fullpath) - is_image = baseline_path.lower().endswith('.png') - if not self._diff_baselines(new_output, fallback_output, is_image): - _log.info(' Skipping %s (matches %s)', test, fallback_dir_relpath) - return True - return False - - return False - - def _diff_baselines(self, output1, output2, is_image): - """Check whether two baselines are different. - - Args: - output1, output2: contents of the baselines to compare. - - Returns: - True if two files are different or have different extensions. - False otherwise. - """ - - if is_image: - return self._port.diff_image(output1, output2)[0] - - return self._port.do_text_results_differ(output1, output2) - - def _delete_baseline(self, filename): - """Remove the file from repository and delete it from disk. - - Args: - filename: full path of the file to delete. - """ - - if not filename or not self._filesystem.isfile(filename): - return - self._scm.delete(filename) - - def _create_html_baseline_files(self, baseline_fullpath): - """Create baseline files (old, new and diff) in html directory. - - The files are used to compare the rebaselining results. - - Args: - baseline_fullpath: full path of the expected baseline file. - """ - - baseline_relpath = self._filesystem.relpath(baseline_fullpath) - _log.debug(' Html: create baselines for "%s"', baseline_relpath) - - if (not baseline_fullpath - or not self._filesystem.exists(baseline_fullpath)): - _log.debug(' Html: Does not exist: "%s"', baseline_fullpath) - return - - if not self._scm.exists(baseline_relpath): - _log.debug(' Html: Does not exist in scm: "%s"', baseline_relpath) - return - - # Copy the new baseline to html directory for result comparison. - baseline_filename = self._filesystem.basename(baseline_fullpath) - new_file = get_result_file_fullpath(self._filesystem, self._options.html_directory, - baseline_filename, self._platform, 'new') - self._filesystem.copyfile(baseline_fullpath, new_file) - _log.debug(' Html: copied new baseline file from "%s" to "%s".', - baseline_fullpath, new_file) - - # Get the old baseline from the repository and save to the html directory. - try: - output = self._scm.show_head(baseline_relpath) - except ScriptError, e: - _log.warning(e) - output = "" - - if (not output) or (output.upper().rstrip().endswith('NO SUCH FILE OR DIRECTORY')): - _log.warning(' No base file: "%s"', baseline_fullpath) - return - base_file = get_result_file_fullpath(self._filesystem, self._options.html_directory, - baseline_filename, self._platform, 'old') - if base_file.upper().endswith('.PNG'): - self._filesystem.write_binary_file(base_file, output) - else: - self._filesystem.write_text_file(base_file, output) - _log.debug(' Html: created old baseline file: "%s".', base_file) - - # Get the diff between old and new baselines and save to the html dir. - diff_file = get_result_file_fullpath(self._filesystem, - self._options.html_directory, - baseline_filename, - self._platform, 'diff') - has_diff = False - if baseline_filename.upper().endswith('.TXT'): - output = self._scm.diff_for_file(baseline_relpath, log=_log) - if output: - self._filesystem.write_text_file(diff_file, output) - has_diff = True - elif baseline_filename.upper().endswith('.PNG'): - old_file = get_result_file_fullpath(self._filesystem, - self._options.html_directory, - baseline_filename, - self._platform, 'old') - new_file = get_result_file_fullpath(self._filesystem, - self._options.html_directory, - baseline_filename, - self._platform, 'new') - _log.debug(' Html: diffing "%s" and "%s"', old_file, new_file) - old_output = self._filesystem.read_binary_file(old_file) - new_output = self._filesystem.read_binary_file(new_file) - image_diff = self._port.diff_image(old_output, new_output)[0] - self._filesystem.write_binary_file(diff_file, image_diff) - - if has_diff: - _log.debug(' Html: created baseline diff file: "%s".', diff_file) - - -class HtmlGenerator(object): - """Class to generate rebaselining result comparison html.""" - - HTML_REBASELINE = ('<html>' - '<head>' - '<style>' - 'body {font-family: sans-serif;}' - '.mainTable {background: #666666;}' - '.mainTable td , .mainTable th {background: white;}' - '.detail {margin-left: 10px; margin-top: 3px;}' - '</style>' - '<title>Rebaselining Result Comparison (%(time)s)' - '</title>' - '</head>' - '<body>' - '<h2>Rebaselining Result Comparison (%(time)s)</h2>' - '%(body)s' - '</body>' - '</html>') - HTML_NO_REBASELINING_TESTS = ( - '<p>No tests found that need rebaselining.</p>') - HTML_TABLE_TEST = ('<table class="mainTable" cellspacing=1 cellpadding=5>' - '%s</table><br>') - HTML_TR_TEST = ('<tr>' - '<th style="background-color: #CDECDE; border-bottom: ' - '1px solid black; font-size: 18pt; font-weight: bold" ' - 'colspan="5">' - '<a href="%s">%s</a>' - '</th>' - '</tr>') - HTML_TEST_DETAIL = ('<div class="detail">' - '<tr>' - '<th width="100">Baseline</th>' - '<th width="100">Platform</th>' - '<th width="200">Old</th>' - '<th width="200">New</th>' - '<th width="150">Difference</th>' - '</tr>' - '%s' - '</div>') - HTML_TD_NOLINK = '<td align=center><a>%s</a></td>' - HTML_TD_LINK = '<td align=center><a href="%(uri)s">%(name)s</a></td>' - HTML_TD_LINK_IMG = ('<td><a href="%(uri)s">' - '<img style="width: 200" src="%(uri)s" /></a></td>') - HTML_TR = '<tr>%s</tr>' - - def __init__(self, host, port, target_port, options, platforms, rebaselining_tests): - self._html_directory = options.html_directory - self._host = host - self._filesystem = host.filesystem - self._port = port - self._target_port = target_port - self._options = options - self._platforms = platforms - self._rebaselining_tests = rebaselining_tests - self._html_file = self._filesystem.join(options.html_directory, - 'rebaseline.html') - - def abspath_to_uri(self, filename): - """Converts an absolute path to a file: URI.""" - return path.abspath_to_uri(filename, self._port._executive) - - def generate_html(self): - """Generate html file for rebaselining result comparison.""" - - _log.debug('Generating html file') - - html_body = '' - if not self._rebaselining_tests: - html_body += self.HTML_NO_REBASELINING_TESTS - else: - tests = list(self._rebaselining_tests) - tests.sort() - - test_no = 1 - for test in tests: - _log.debug('Test %d: %s', test_no, test) - html_body += self._generate_html_for_one_test(test) - - html = self.HTML_REBASELINE % ({'time': time.asctime(), - 'body': html_body}) - _log.debug(html) - - self._filesystem.write_text_file(self._html_file, html) - _log.debug('Baseline comparison html generated at "%s"', self._html_file) - - def show_html(self): - """Launch the rebaselining html in brwoser.""" - - _log.debug('Launching html: "%s"', self._html_file) - self._host.user.open_url(self._html_file) - _log.debug('Html launched.') - - def _generate_baseline_links(self, test_basename, suffix, platform): - """Generate links for baseline results (old, new and diff). - - Args: - test_basename: base filename of the test - suffix: baseline file suffixes: '.txt', '.png' - platform: win, linux or mac - - Returns: - html links for showing baseline results (old, new and diff) - """ - - baseline_filename = '%s-expected%s' % (test_basename, suffix) - _log.debug(' baseline filename: "%s"', baseline_filename) - - new_file = get_result_file_fullpath(self._filesystem, self._html_directory, - baseline_filename, platform, 'new') - _log.debug(' New baseline file: "%s"', new_file) - if not self._filesystem.exists(new_file): - _log.debug(' No new baseline file: "%s"', new_file) - return '' - - old_file = get_result_file_fullpath(self._filesystem, self._html_directory, - baseline_filename, platform, 'old') - _log.debug(' Old baseline file: "%s"', old_file) - if suffix == '.png': - html_td_link = self.HTML_TD_LINK_IMG - else: - html_td_link = self.HTML_TD_LINK - - links = '' - if self._filesystem.exists(old_file): - links += html_td_link % { - 'uri': self.abspath_to_uri(old_file), - 'name': baseline_filename} - else: - _log.debug(' No old baseline file: "%s"', old_file) - links += self.HTML_TD_NOLINK % '' - - links += html_td_link % {'uri': self.abspath_to_uri(new_file), - 'name': baseline_filename} - - diff_file = get_result_file_fullpath(self._filesystem, self._html_directory, - baseline_filename, platform, 'diff') - _log.debug(' Baseline diff file: "%s"', diff_file) - if self._filesystem.exists(diff_file): - links += html_td_link % {'uri': self.abspath_to_uri(diff_file), - 'name': 'Diff'} - else: - _log.debug(' No baseline diff file: "%s"', diff_file) - links += self.HTML_TD_NOLINK % '' - - return links - - def _generate_html_for_one_test(self, test): - """Generate html for one rebaselining test. - - Args: - test: layout test name - - Returns: - html that compares baseline results for the test. - """ - - test_basename = self._filesystem.basename(self._filesystem.splitext(test)[0]) - _log.debug(' basename: "%s"', test_basename) - rows = [] - for suffix in BASELINE_SUFFIXES: - if suffix == '.checksum': - continue - - _log.debug(' Checking %s files', suffix) - for platform in self._platforms: - links = self._generate_baseline_links(test_basename, suffix, platform) - if links: - row = self.HTML_TD_NOLINK % self._get_baseline_result_type(suffix) - row += self.HTML_TD_NOLINK % platform - row += links - _log.debug(' html row: %s', row) - - rows.append(self.HTML_TR % row) - - if rows: - test_path = self._filesystem.join(self._target_port.layout_tests_dir(), test) - html = self.HTML_TR_TEST % (self.abspath_to_uri(test_path), test) - html += self.HTML_TEST_DETAIL % ' '.join(rows) - - _log.debug(' html for test: %s', html) - return self.HTML_TABLE_TEST % html - - return '' - - def _get_baseline_result_type(self, suffix): - """Name of the baseline result type.""" - - if suffix == '.png': - return 'Pixel' - elif suffix == '.txt': - return 'Render Tree' - else: - return 'Other' - - -def get_host_port_object(port_factory, options): - """Return a port object for the platform we're running on.""" - # We want the ImageDiff logic to match that of the chromium bots, so we - # force the use of a Chromium port. We will look for either Debug or - # Release versions. - options.configuration = "Release" - options.chromium = True - port_obj = port_factory.get(options=options) - if not port_obj.check_image_diff(override_step=None, logging=False): - _log.debug('No release version of the image diff binary was found.') - options.configuration = "Debug" - port_obj = port_factory.get(options=options) - if not port_obj.check_image_diff(override_step=None, logging=False): - _log.error('No version of image diff was found. Check your build.') - return None - else: - _log.debug('Found the debug version of the image diff binary.') - else: - _log.debug('Found the release version of the image diff binary.') - return port_obj - - -def parse_options(args): - """Parse options and return a pair of host options and target options.""" - option_parser = optparse.OptionParser() - option_parser.add_option('-v', '--verbose', - action='store_true', - default=False, - help='include debug-level logging.') - - option_parser.add_option('-q', '--quiet', - action='store_true', - help='Suppress result HTML viewing') - - option_parser.add_option('-p', '--platforms', - default=None, - help=('Comma delimited list of platforms ' - 'that need rebaselining.')) - - option_parser.add_option('-u', '--archive_url', - default=('http://build.chromium.org/f/chromium/' - 'layout_test_results'), - help=('Url to find the layout test result archive' - ' file.')) - option_parser.add_option('-U', '--force_archive_url', - help=('Url of result zip file. This option is for debugging ' - 'purposes')) - - option_parser.add_option('-b', '--backup', - action='store_true', - default=False, - help=('Whether or not to backup the original test' - ' expectations file after rebaseline.')) - - option_parser.add_option('-d', '--html_directory', - default='', - help=('The directory that stores the results for ' - 'rebaselining comparison.')) - - option_parser.add_option('', '--use_drt', - action='store_true', - default=False, - help=('Use ImageDiff from DumpRenderTree instead ' - 'of image_diff for pixel tests.')) - - option_parser.add_option('-w', '--webkit_canary', - action='store_true', - default=False, - help=('DEPRECATED. This flag no longer has any effect.' - ' The canaries are always used.')) - - option_parser.add_option('', '--target-platform', - default='chromium', - help=('The target platform to rebaseline ' - '("mac", "chromium", "qt", etc.). Defaults ' - 'to "chromium".')) - - options = option_parser.parse_args(args)[0] - if options.webkit_canary: - print "-w/--webkit-canary is no longer necessary, ignoring." - - target_options = copy.copy(options) - if options.target_platform == 'chromium': - target_options.chromium = True - options.tolerance = 0 - - return (options, target_options) - - -class DebugLogHandler(logging.Handler): - num_failures = 0 - - def __init__(self): - logging.Handler.__init__(self) - self.formatter = logging.Formatter(fmt=('%(asctime)s %(filename)s:%(lineno)-3d ' - '%(levelname)s %(message)s')) - self.setFormatter(self.formatter) - - def emit(self, record): - if record.levelno > logging.INFO: - self.num_failures += 1 - print self.format(record) - - -class NormalLogHandler(logging.Handler): - last_levelno = None - num_failures = 0 - - def emit(self, record): - if record.levelno > logging.INFO: - self.num_failures += 1 - if self.last_levelno != record.levelno: - print - self.last_levelno = record.levelno - prefix = '' - msg = record.getMessage() - if record.levelno > logging.INFO and msg: - prefix = '%s: ' % record.levelname - print '%s%s' % (prefix, msg) - - -def main(args): - """Bootstrap function that sets up the object references we need and calls real_main().""" - options, target_options = parse_options(args) - - logger = logging.getLogger() - logger.setLevel(logging.INFO) - if options.verbose: - log_level = logging.DEBUG - log_handler = DebugLogHandler() - else: - log_level = logging.INFO - log_handler = NormalLogHandler() - - logger = logging.getLogger() - logger.setLevel(log_level) - logger.addHandler(log_handler) - - host = Host() - host._initialize_scm() - target_port_obj = host.port_factory.get(None, target_options) - host_port_obj = get_host_port_object(host.port_factory, options) - if not host_port_obj or not target_port_obj: - return 1 - - url_fetcher = urlfetcher.UrlFetcher(host.filesystem) - - # We use the default zip factory method. - zip_factory = None - - # FIXME: SCM module doesn't handle paths that aren't relative to the checkout_root consistently. - host_port_obj._filesystem.chdir(host.scm().checkout_root) - - ret_code = real_main(host, options, target_options, host_port_obj, target_port_obj, url_fetcher, zip_factory) - if not ret_code and log_handler.num_failures: - ret_code = 1 - print '' - if ret_code: - print 'Rebaselining failed.' - else: - print 'Rebaselining succeeded.' - return ret_code - - -def real_main(host, options, target_options, host_port_obj, target_port_obj, url_fetcher, zip_factory): - """Main function to produce new baselines. The Rebaseliner object uses two - different Port objects - one to represent the machine the object is running - on, and one to represent the port whose expectations are being updated. - E.g., you can run the script on a mac and rebaseline the 'win' port. - - Args: - host: Host object - options: command-line argument used for the host_port_obj (see below) - target_options: command_line argument used for the target_port_obj. - This object may have slightly different values than |options|. - host_port_obj: a Port object for the platform the script is running - on. This is used to produce image and text diffs, mostly, and - is usually acquired from get_host_port_obj(). - target_port_obj: a Port obj representing the port getting rebaselined. - This is used to find the expectations file, the baseline paths, - etc. - url_fetcher: object used to download the build archives from the bots - zip_factory: factory function used to create zip file objects for - the archives. - """ - options.html_directory = setup_html_directory(host_port_obj._filesystem, options.html_directory) - all_platforms = target_port_obj.all_baseline_variants() - if options.platforms: - bail = False - for platform in options.platforms: - if not platform in all_platforms: - _log.error('Invalid platform: "%s"' % (platform)) - bail = True - if bail: - return 1 - rebaseline_platforms = options.platforms - else: - rebaseline_platforms = all_platforms - - # FIXME: These log messages will be wrong if ports store baselines outside - # of layout_tests_dir(), but the code should work correctly. - layout_tests_dir = target_port_obj.layout_tests_dir() - expectations_path = target_port_obj.path_to_test_expectations_file() - _log.info('Using %s' % layout_tests_dir) - _log.info(' and %s' % expectations_path) - - rebaselined_tests = set() - logged_before = False - for platform in rebaseline_platforms: - rebaseliner = Rebaseliner(host, host_port_obj, target_port_obj, - platform, options, url_fetcher, zip_factory, - logged_before) - - _log.debug('') - log_dashed_string('Rebaseline started', platform) - if rebaseliner.run(): - log_dashed_string('Rebaseline done', platform) - else: - log_dashed_string('Rebaseline failed', platform) - - rebaselined_tests |= set(rebaseliner.get_rebaselined_tests()) - logged_before = rebaseliner.did_log - - if rebaselined_tests: - rebaseliner.remove_rebaselining_expectations(rebaselined_tests, - options.backup) - - _log.debug('') - log_dashed_string('Rebaselining result comparison started') - html_generator = HtmlGenerator(host, host_port_obj, - target_port_obj, - options, - rebaseline_platforms, - rebaselined_tests) - html_generator.generate_html() - if not options.quiet: - html_generator.show_html() - log_dashed_string('Rebaselining result comparison done') - - return 0 - - -if '__main__' == __name__: - sys.exit(main(sys.argv[1:])) diff --git a/Tools/Scripts/webkitpy/to_be_moved/rebaseline_chromium_webkit_tests_unittest.py b/Tools/Scripts/webkitpy/to_be_moved/rebaseline_chromium_webkit_tests_unittest.py deleted file mode 100644 index c44dcdf2f..000000000 --- a/Tools/Scripts/webkitpy/to_be_moved/rebaseline_chromium_webkit_tests_unittest.py +++ /dev/null @@ -1,387 +0,0 @@ -#!/usr/bin/python -# Copyright (C) 2010 Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * 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. - -"""Unit tests for rebaseline_chromium_webkit_tests.py.""" - -import unittest - -from webkitpy.tool.mocktool import MockOptions -from webkitpy.common.system import urlfetcher_mock -from webkitpy.common.host_mock import MockHost - -from webkitpy.common.system import zipfileset_mock -from webkitpy.common.system import outputcapture -from webkitpy.common.system.executive import Executive, ScriptError - -from webkitpy.layout_tests import port -from webkitpy.to_be_moved import rebaseline_chromium_webkit_tests - - -class MockPort(object): - def __init__(self, image_diff_exists): - self.image_diff_exists = image_diff_exists - - def check_image_diff(self, override_step, logging): - return self.image_diff_exists - - -class MockPortFactory(object): - def __init__(self, config_expectations): - self.config_expectations = config_expectations - - def get(self, port_name=None, options=None): - return MockPort(self.config_expectations[options.configuration]) - - -ARCHIVE_URL = 'http://localhost/layout_test_results' - - -def test_options(): - return MockOptions(configuration=None, - backup=False, - html_directory='/tmp', - archive_url=ARCHIVE_URL, - force_archive_url=None, - verbose=False, - quiet=False, - platforms=None) - - -def test_host_port_and_filesystem(options, expectations): - host = MockHost() - host_port_obj = host.port_factory.get('test', options) - expectations_path = host_port_obj.path_to_test_expectations_file() - host.filesystem.write_text_file(expectations_path, expectations) - return (host, host_port_obj, host.filesystem) - - -def test_url_fetcher(filesystem): - urls = { - ARCHIVE_URL + '/Webkit_Mac10_6/': '<a href="4/">', - ARCHIVE_URL + '/Webkit_Mac10_5/': '<a href="1/"><a href="2/">', - ARCHIVE_URL + '/Webkit_Win7/': '<a href="1/">', - ARCHIVE_URL + '/Webkit_Vista/': '<a href="1/">', - ARCHIVE_URL + '/Webkit_Win/': '<a href="1/">', - ARCHIVE_URL + '/Webkit_Linux/': '<a href="1/">', - } - return urlfetcher_mock.make_fetcher_cls(urls)(filesystem) - - -def test_zip_factory(): - ziphashes = { - ARCHIVE_URL + '/Webkit_Mac10_5/2/layout-test-results.zip': { - 'layout-test-results/failures/expected/image-actual.txt': 'new-image-txt', - 'layout-test-results/failures/expected/image-actual.checksum': 'new-image-checksum', - 'layout-test-results/failures/expected/image-actual.png': 'new-image-png', - 'layout-test-results/failures/expected/image_checksum-actual.txt': 'png-comment-txt', - 'layout-test-results/failures/expected/image_checksum-actual.checksum': '0123456789', - 'layout-test-results/failures/expected/image_checksum-actual.png': 'tEXtchecksum\x000123456789', - }, - ARCHIVE_URL + '/Webkit_Mac10_6/4/layout-test-results.zip': { - 'layout-test-results/failures/expected/image-actual.txt': 'new-image-txt', - 'layout-test-results/failures/expected/image-actual.checksum': 'new-image-checksum', - 'layout-test-results/failures/expected/image-actual.png': 'new-image-png', - }, - ARCHIVE_URL + '/Webkit_Vista/1/layout-test-results.zip': { - 'layout-test-results/failures/expected/image-actual.txt': 'win-image-txt', - 'layout-test-results/failures/expected/image-actual.checksum': 'win-image-checksum', - 'layout-test-results/failures/expected/image-actual.png': 'win-image-png', - }, - ARCHIVE_URL + '/Webkit_Win7/1/layout-test-results.zip': { - 'layout-test-results/failures/expected/image-actual.txt': 'win-image-txt', - 'layout-test-results/failures/expected/image-actual.checksum': 'win-image-checksum', - 'layout-test-results/failures/expected/image-actual.png': 'win-image-png', - }, - ARCHIVE_URL + '/Webkit_Win/1/layout-test-results.zip': { - 'layout-test-results/failures/expected/image-actual.txt': 'win-image-txt', - 'layout-test-results/failures/expected/image-actual.checksum': 'win-image-checksum', - 'layout-test-results/failures/expected/image-actual.png': 'win-image-png', - }, - ARCHIVE_URL + '/Webkit_Linux/1/layout-test-results.zip': { - 'layout-test-results/failures/expected/image-actual.txt': 'win-image-txt', - 'layout-test-results/failures/expected/image-actual.checksum': 'win-image-checksum', - 'layout-test-results/failures/expected/image-actual.png': 'win-image-png', - }, - } - return zipfileset_mock.make_factory(ziphashes) - - -def test_archive(orig_archive_dict): - new_archive_dict = {} - for platform, dirname in orig_archive_dict.iteritems(): - # This is a giant hack. :( - platform = platform.replace('chromium', 'test') - new_archive_dict[platform] = dirname - return new_archive_dict - - -class TestGetHostPortObject(unittest.TestCase): - def assert_result(self, release_present, debug_present, valid_port_obj): - # Tests whether we get a valid port object returned when we claim - # that Image diff is (or isn't) present in the two configs. - port_factory = MockPortFactory({'Release': release_present, 'Debug': debug_present}) - options = MockOptions(configuration=None, html_directory='/tmp') - port_obj = rebaseline_chromium_webkit_tests.get_host_port_object(port_factory, options) - if valid_port_obj: - self.assertNotEqual(port_obj, None) - else: - self.assertEqual(port_obj, None) - - def test_get_host_port_object(self): - # Test whether we get a valid port object back for the four - # possible cases of having ImageDiffs built. It should work when - # there is at least one binary present. - self.assert_result(False, False, False) - self.assert_result(True, False, True) - self.assert_result(False, True, True) - self.assert_result(True, True, True) - - -class TestOptions(unittest.TestCase): - def test_parse_options(self): - (options, target_options) = rebaseline_chromium_webkit_tests.parse_options([]) - self.assertTrue(target_options.chromium) - self.assertEqual(options.tolerance, 0) - - (options, target_options) = rebaseline_chromium_webkit_tests.parse_options(['--target-platform', 'qt']) - self.assertFalse(hasattr(target_options, 'chromium')) - self.assertEqual(options.tolerance, 0) - - -class TestRebaseliner(unittest.TestCase): - def setUp(self): - if not hasattr(self, '_orig_archive'): - self._orig_archive = rebaseline_chromium_webkit_tests.ARCHIVE_DIR_NAME_DICT - rebaseline_chromium_webkit_tests.ARCHIVE_DIR_NAME_DICT = test_archive(self._orig_archive) - - def tearDown(self): - rebaseline_chromium_webkit_tests.ARCHIVE_DIR_NAME_DICT = self._orig_archive - - def make_rebaseliner(self, expectations): - options = test_options() - host, host_port_obj, filesystem = test_host_port_and_filesystem(options, expectations) - - target_options = options - target_port_obj = host.port_factory.get('test', target_options) - platform = target_port_obj.name() - - url_fetcher = test_url_fetcher(filesystem) - zip_factory = test_zip_factory() - - # FIXME: SCM module doesn't handle paths that aren't relative to the checkout_root consistently. - filesystem.chdir(filesystem.dirname(host_port_obj.layout_tests_dir())) - - rebaseliner = rebaseline_chromium_webkit_tests.Rebaseliner(host, host_port_obj, - target_port_obj, platform, options, url_fetcher, zip_factory) - return rebaseliner, filesystem - - def test_noop(self): - # this method tests that was can at least instantiate an object, even - # if there is nothing to do. - rebaseliner, filesystem = self.make_rebaseliner("") - rebaseliner.run() - self.assertEqual(len(filesystem.written_files), 1) - - def test_rebaselining_tests(self): - rebaseliner, filesystem = self.make_rebaseliner( - "BUGX REBASELINE MAC : failures/expected/image.html = IMAGE") - compile_success = rebaseliner._compile_rebaselining_tests() - self.assertTrue(compile_success) - self.assertEqual(set(['failures/expected/image.html']), rebaseliner._rebaselining_tests) - - def test_rebaselining_tests_should_ignore_reftests(self): - rebaseliner, filesystem = self.make_rebaseliner( - "BUGX REBASELINE : failures/expected/reftest.html = IMAGE") - compile_success = rebaseliner._compile_rebaselining_tests() - self.assertFalse(compile_success) - self.assertFalse(rebaseliner._rebaselining_tests) - - def test_one_platform(self): - rebaseliner, filesystem = self.make_rebaseliner( - "BUGX REBASELINE MAC : failures/expected/image.html = IMAGE") - - rebaseliner.run() - layout_test_dir = rebaseliner._port.layout_tests_dir() - # We expect to have written 13 files over the course of this rebaseline: - # *) 3 files in /__im_tmp for the extracted archive members - # *) 3 new baselines under layout_test_dir - # *) 4 files in /tmp for the new and old baselines in the result file - # (-{old,new}.{txt,png} - # *) 1 text diff in /tmp for the result file (-diff.txt). - # *) 1 image diff in /tmp for the result file (-diff.png). - # *) 1 updated test_expectations file - self.assertEqual(len(filesystem.written_files), 13) - self.assertEqual(filesystem.files[layout_test_dir + '/platform/test-mac-leopard/failures/expected/image-expected.checksum'], 'new-image-checksum') - self.assertEqual(filesystem.files[layout_test_dir + '/platform/test-mac-leopard/failures/expected/image-expected.png'], 'new-image-png') - self.assertEqual(filesystem.files[layout_test_dir + '/platform/test-mac-leopard/failures/expected/image-expected.txt'], 'new-image-txt') - - def test_all_platforms(self): - rebaseliner, filesystem = self.make_rebaseliner( - "BUGX REBASELINE : failures/expected/image.html = IMAGE") - layout_test_dir = rebaseliner._port.layout_tests_dir() - rebaseliner.run() - # See comment in test_one_platform for an explanation of the 13 written tests. - # Note that even though the rebaseline is marked for all platforms, each - # rebaseliner only ever does one. - self.assertEqual(len(filesystem.written_files), 13) - self.assertEqual(filesystem.files[layout_test_dir + '/platform/test-mac-leopard/failures/expected/image-expected.checksum'], 'new-image-checksum') - self.assertEqual(filesystem.files[layout_test_dir + '/platform/test-mac-leopard/failures/expected/image-expected.png'], 'new-image-png') - self.assertEqual(filesystem.files[layout_test_dir + '/platform/test-mac-leopard/failures/expected/image-expected.txt'], 'new-image-txt') - - def test_png_file_with_comment(self): - rebaseliner, filesystem = self.make_rebaseliner( - "BUGX REBASELINE MAC : failures/expected/image_checksum.html = IMAGE") - layout_test_dir = rebaseliner._port.layout_tests_dir() - compile_success = rebaseliner._compile_rebaselining_tests() - self.assertTrue(compile_success) - self.assertEqual(set(['failures/expected/image_checksum.html']), rebaseliner._rebaselining_tests) - rebaseliner.run() - # There is one less file written than |test_one_platform| because we only - # write 2 expectations (the png and the txt file). - self.assertEqual(len(filesystem.written_files), 12) - self.assertEqual(filesystem.files[layout_test_dir + '/platform/test-mac-leopard/failures/expected/image_checksum-expected.png'], 'tEXtchecksum\x000123456789') - self.assertEqual(filesystem.files[layout_test_dir + '/platform/test-mac-leopard/failures/expected/image_checksum-expected.txt'], 'png-comment-txt') - self.assertFalse(filesystem.files.get(layout_test_dir + '/platform/test-mac-leopard/failures/expected/image_checksum-expected.checksum', None)) - - def test_png_file_with_comment_remove_old_checksum(self): - rebaseliner, filesystem = self.make_rebaseliner( - "BUGX REBASELINE MAC : failures/expected/image_checksum.html = IMAGE") - layout_test_dir = rebaseliner._port.layout_tests_dir() - filesystem.files[layout_test_dir + '/platform/test-mac-leopard/failures/expected/image_checksum-expected.png'] = 'old' - filesystem.files[layout_test_dir + '/platform/test-mac-leopard/failures/expected/image_checksum-expected.checksum'] = 'old' - filesystem.files[layout_test_dir + '/platform/test-mac-leopard/failures/expected/image_checksum-expected.txt'] = 'old' - - compile_success = rebaseliner._compile_rebaselining_tests() - self.assertTrue(compile_success) - self.assertEqual(set(['failures/expected/image_checksum.html']), rebaseliner._rebaselining_tests) - rebaseliner.run() - # There is one more file written than |test_png_file_with_comment_remove_old_checksum| - # because we also delete the old checksum. - self.assertEqual(len(filesystem.written_files), 13) - self.assertEqual(filesystem.files[layout_test_dir + '/platform/test-mac-leopard/failures/expected/image_checksum-expected.png'], 'tEXtchecksum\x000123456789') - self.assertEqual(filesystem.files[layout_test_dir + '/platform/test-mac-leopard/failures/expected/image_checksum-expected.txt'], 'png-comment-txt') - self.assertEqual(filesystem.files.get(layout_test_dir + '/platform/test-mac-leopard/failures/expected/image_checksum-expected.checksum', None), None) - - def test_png_file_with_comment_as_duplicate(self): - rebaseliner, filesystem = self.make_rebaseliner( - "BUGX REBASELINE MAC : failures/expected/image_checksum.html = IMAGE") - layout_test_dir = rebaseliner._port.layout_tests_dir() - filesystem.files[layout_test_dir + '/platform/test-mac-snowleopard/failures/expected/image_checksum-expected.png'] = 'tEXtchecksum\x000123456789' - filesystem.files[layout_test_dir + '/platform/test-mac-snowleopard/failures/expected/image_checksum-expected.txt'] = 'png-comment-txt' - - compile_success = rebaseliner._compile_rebaselining_tests() - self.assertTrue(compile_success) - self.assertEqual(set(['failures/expected/image_checksum.html']), rebaseliner._rebaselining_tests) - rebaseliner.run() - self.assertEqual(filesystem.files.get(layout_test_dir + '/platform/test-mac-leopard/failures/expected/image_checksum-expected.png', None), None) - self.assertEqual(filesystem.files.get(layout_test_dir + '/platform/test-mac-leopard/failures/expected/image_checksum-expected.txt', None), None) - self.assertEqual(filesystem.files.get(layout_test_dir + '/platform/test-mac-leopard/failures/expected/image_checksum-expected.checksum', None), None) - - def test_diff_baselines_txt(self): - rebaseliner, filesystem = self.make_rebaseliner("") - port = rebaseliner._port - output = port.expected_text('passes/text.html') - self.assertFalse(rebaseliner._diff_baselines(output, output, - is_image=False)) - - def test_diff_baselines_png(self): - rebaseliner, filesystem = self.make_rebaseliner('') - port = rebaseliner._port - image = port.expected_image('passes/image.html') - self.assertFalse(rebaseliner._diff_baselines(image, image, - is_image=True)) - - -class TestRealMain(unittest.TestCase): - def setUp(self): - if not hasattr(self, '_orig_archive'): - self._orig_archive = rebaseline_chromium_webkit_tests.ARCHIVE_DIR_NAME_DICT - rebaseline_chromium_webkit_tests.ARCHIVE_DIR_NAME_DICT = test_archive(self._orig_archive) - - def tearDown(self): - rebaseline_chromium_webkit_tests.ARCHIVE_DIR_NAME_DICT = self._orig_archive - - def test_all_platforms(self): - expectations = "BUGX REBASELINE : failures/expected/image.html = IMAGE" - - options = test_options() - host, host_port_obj, filesystem = test_host_port_and_filesystem(options, expectations) - url_fetcher = test_url_fetcher(filesystem) - zip_factory = test_zip_factory() - - # FIXME: SCM module doesn't handle paths that aren't relative to the checkout_root consistently. - filesystem.chdir(filesystem.dirname(host_port_obj.layout_tests_dir())) - - oc = outputcapture.OutputCapture() - oc.capture_output() - res = rebaseline_chromium_webkit_tests.real_main(host, options, options, - host_port_obj, host_port_obj, url_fetcher, zip_factory) - oc.restore_output() - - # We expect to have written 38 files over the course of this rebaseline: - # *) 6*3 files in /__im_tmp/ for the archived members of the 6 ports - # *) 2*3 files in /test.checkout for actually differing baselines - # *) 1 file in /test.checkout for the updated test_expectations file - # *) 2*4 files in /tmp for the old/new baselines for the two actual ports - # *) 2 files in /tmp for the text diffs for the two ports - # *) 2 files in /tmp for the image diffs for the two ports - # *) 1 file in /tmp for the rebaseline results html file - # FIXME: These numbers depend on MockSCM.exists() returning True for all files. - self.assertEqual(res, 0) - self.assertEqual(len(filesystem.written_files), 38) - - -class TestHtmlGenerator(unittest.TestCase): - def make_generator(self, files, tests): - options = MockOptions(configuration=None, html_directory='/tmp') - host = MockHost() - fs = host.filesystem - for filename, contents in files.iteritems(): - fs.maybe_make_directory(fs.dirname(filename)) - fs.write_binary_file(filename, contents) - host_port = host.port_factory.get('test', options) - generator = rebaseline_chromium_webkit_tests.HtmlGenerator(host, host_port, - target_port=None, options=options, platforms=['test-mac-leopard'], rebaselining_tests=tests) - return generator, host_port - - def test_generate_baseline_links(self): - files = { - "/tmp/foo-expected-mac-old.txt": "", - "/tmp/foo-expected-mac-new.txt": "", - "/tmp/foo-expected-mac-diff.txt": "", - } - tests = ["foo.txt"] - generator, host_port = self.make_generator(files, tests) - links = generator._generate_baseline_links("foo", ".txt", "mac") - expected_links = '<td align=center><a href="file:///tmp/foo-expected-mac-old.txt">foo-expected.txt</a></td><td align=center><a href="file:///tmp/foo-expected-mac-new.txt">foo-expected.txt</a></td><td align=center><a href="file:///tmp/foo-expected-mac-diff.txt">Diff</a></td>' - self.assertEqual(links, expected_links) - - -if __name__ == '__main__': - unittest.main() diff --git a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py index 4085e366a..37bc4b72e 100644 --- a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py +++ b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py @@ -160,6 +160,11 @@ class QtEWS(AbstractEarlyWarningSystem): port_name = "qt" +class QtWK2EWS(AbstractEarlyWarningSystem): + name = "qt-wk2-ews" + port_name = "qt" + + class WinEWS(AbstractEarlyWarningSystem): name = "win-ews" port_name = "win" diff --git a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py index cb349412c..3adad4c58 100644 --- a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py +++ b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py @@ -83,6 +83,7 @@ class EarlyWarningSytemTest(QueuesTest): self._test_builder_ews(MacEWS()) self._test_builder_ews(ChromiumWindowsEWS()) self._test_builder_ews(QtEWS()) + self._test_builder_ews(QtWK2EWS()) self._test_builder_ews(GtkEWS()) self._test_builder_ews(EflEWS()) diff --git a/Tools/Scripts/webkitpy/tool/commands/rebaseline.py b/Tools/Scripts/webkitpy/tool/commands/rebaseline.py index 515ff7dfa..f47494acd 100644 --- a/Tools/Scripts/webkitpy/tool/commands/rebaseline.py +++ b/Tools/Scripts/webkitpy/tool/commands/rebaseline.py @@ -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. +import optparse import os.path import re import shutil @@ -56,7 +57,7 @@ def _baseline_name(fs, test_name, suffix): class RebaselineTest(AbstractDeclarativeCommand): name = "rebaseline-test" help_text = "Rebaseline a single test from a buildbot. (Currently works only with build.chromium.org buildbots.)" - argument_names = "BUILDER_NAME TEST_NAME" + argument_names = "BUILDER_NAME TEST_NAME [PLATFORM_TO_MOVE_EXISTING_BASELINES_TO]" def _results_url(self, builder_name): # FIXME: Generalize this command to work with non-build.chromium.org builders. @@ -67,6 +68,23 @@ class RebaselineTest(AbstractDeclarativeCommand): port = self._tool.port_factory.get_from_builder_name(builder_name) return port.baseline_path() + def _copy_existing_baseline(self, platform_to_move_existing_baselines_to, test_name, suffix): + port = self._tool.port_factory.get(platform_to_move_existing_baselines_to) + old_baseline = port.expected_filename(test_name, "." + suffix) + if not self._tool.filesystem.exists(old_baseline): + print("No existing baseline for %s." % test_name) + return + + new_baseline = self._tool.filesystem.join(port.baseline_path(), self._file_name_for_expected_result(test_name, suffix)) + if self._tool.filesystem.exists(new_baseline): + print("Existing baseline at %s, not copying over it." % new_baseline) + else: + print("Copying baseline from %s to %s." % (old_baseline, new_baseline)) + self._tool.filesystem.maybe_make_directory(self._tool.filesystem.dirname(new_baseline)) + self._tool.filesystem.copyfile(old_baseline, new_baseline) + if not self._tool.scm().exists(new_baseline): + self._tool.scm().add(new_baseline) + def _save_baseline(self, data, target_baseline): if not data: return @@ -85,19 +103,27 @@ class RebaselineTest(AbstractDeclarativeCommand): def _file_name_for_expected_result(self, test_name, suffix): return "%s-expected.%s" % (self._test_root(test_name), suffix) - def _rebaseline_test(self, builder_name, test_name, suffix): + def _rebaseline_test(self, builder_name, test_name, platform_to_move_existing_baselines_to, suffix): results_url = self._results_url(builder_name) baseline_directory = self._baseline_directory(builder_name) source_baseline = "%s/%s" % (results_url, self._file_name_for_actual_result(test_name, suffix)) - target_baseline = os.path.join(baseline_directory, self._file_name_for_expected_result(test_name, suffix)) + target_baseline = self._tool.filesystem.join(baseline_directory, self._file_name_for_expected_result(test_name, suffix)) + + if platform_to_move_existing_baselines_to: + self._copy_existing_baseline(platform_to_move_existing_baselines_to, test_name, suffix) print "Retrieving %s." % source_baseline self._save_baseline(self._tool.web.get_binary(source_baseline, convert_404_to_None=True), target_baseline) def execute(self, options, args, tool): for suffix in _baseline_suffix_list: - self._rebaseline_test(args[0], args[1], suffix) + if len(args) > 2: + platform_to_move_existing_baselines_to = args[2] + else: + platform_to_move_existing_baselines_to = None + + self._rebaseline_test(args[0], args[1], platform_to_move_existing_baselines_to, suffix) class OptimizeBaselines(AbstractDeclarativeCommand): @@ -150,6 +176,15 @@ class RebaselineExpectations(AbstractDeclarativeCommand): name = "rebaseline-expectations" help_text = "Rebaselines the tests indicated in test_expectations.txt." + def __init__(self): + options = [ + optparse.make_option('--no-optimize', dest='optimize', action='store_false', default=True, + help=('Do not optimize/de-dup the expectations after rebaselining ' + '(default is to de-dup automatically). ' + 'You can use "webkit-patch optimize-baselines" to optimize separately.')), + ] + AbstractDeclarativeCommand.__init__(self, options=options) + def _run_webkit_patch(self, args): try: self._tool.executive.run_command([self._tool.path()] + args, cwd=self._tool.scm().checkout_root) @@ -192,6 +227,8 @@ class RebaselineExpectations(AbstractDeclarativeCommand): self._rebaseline_port(port_name) for port_name in tool.port_factory.all_port_names(): self._update_expectations_file(port_name) + if not options.optimize: + return for test_name in self._touched_test_names: print "Optimizing baselines for %s." % test_name self._run_webkit_patch(['optimize-baselines', test_name]) diff --git a/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py b/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py index 52724308d..37e8a391b 100644 --- a/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py +++ b/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py @@ -31,7 +31,7 @@ import unittest from webkitpy.common.system.outputcapture import OutputCapture from webkitpy.thirdparty.mock import Mock from webkitpy.tool.commands.rebaseline import * -from webkitpy.tool.mocktool import MockTool +from webkitpy.tool.mocktool import MockTool, MockOptions from webkitpy.common.system.executive_mock import MockExecutive @@ -46,7 +46,59 @@ class TestRebaseline(unittest.TestCase): command = RebaselineTest() command.bind_to_tool(MockTool()) expected_stdout = "Retrieving http://example.com/f/builders/Webkit Linux/results/layout-test-results/userscripts/another-test-actual.txt.\n" - OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Linux", "userscripts/another-test.html", "txt"], expected_stdout=expected_stdout) + OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Linux", "userscripts/another-test.html", None, "txt"], expected_stdout=expected_stdout) + + def test_rebaseline_and_copy_test(self): + command = RebaselineTest() + tool = MockTool() + command.bind_to_tool(tool) + + lion_port = tool.port_factory.get_from_builder_name("Webkit Mac10.7") + tool.filesystem.write_text_file(os.path.join(lion_port.layout_tests_dir(), "userscripts/another-test-expected.txt"), "Dummy expected result") + + expected_stdout = """Copying baseline from /mock-checkout/LayoutTests/userscripts/another-test-expected.txt to /mock-checkout/LayoutTests/platform/chromium-mac-snowleopard/userscripts/another-test-expected.txt. +Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.txt. +""" + OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Mac10.7", "userscripts/another-test.html", "chromium-mac-snowleopard", "txt"], expected_stdout=expected_stdout) + + def test_rebaseline_and_copy_test_no_existing_result(self): + command = RebaselineTest() + tool = MockTool() + command.bind_to_tool(tool) + + expected_stdout = """No existing baseline for userscripts/another-test.html. +Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.txt. +""" + OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Mac10.7", "userscripts/another-test.html", "chromium-mac-snowleopard", "txt"], expected_stdout=expected_stdout) + + def test_rebaseline_and_copy_test_with_lion_result(self): + command = RebaselineTest() + tool = MockTool() + command.bind_to_tool(tool) + + lion_port = tool.port_factory.get_from_builder_name("Webkit Mac10.7") + tool.filesystem.write_text_file(os.path.join(lion_port.baseline_path(), "userscripts/another-test-expected.txt"), "Dummy expected result") + + expected_stdout = """Copying baseline from /mock-checkout/LayoutTests/platform/chromium-mac/userscripts/another-test-expected.txt to /mock-checkout/LayoutTests/platform/chromium-mac-snowleopard/userscripts/another-test-expected.txt. +Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.txt. +""" + OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Mac10.7", "userscripts/another-test.html", "chromium-mac-snowleopard", "txt"], expected_stdout=expected_stdout) + + def test_rebaseline_and_copy_no_overwrite_test(self): + command = RebaselineTest() + tool = MockTool() + command.bind_to_tool(tool) + + lion_port = tool.port_factory.get_from_builder_name("Webkit Mac10.7") + tool.filesystem.write_text_file(os.path.join(lion_port.baseline_path(), "userscripts/another-test-expected.txt"), "Dummy expected result") + + snowleopard_port = tool.port_factory.get_from_builder_name("Webkit Mac10.6") + tool.filesystem.write_text_file(os.path.join(snowleopard_port.baseline_path(), "userscripts/another-test-expected.txt"), "Dummy expected result") + + expected_stdout = """Existing baseline at /mock-checkout/LayoutTests/platform/chromium-mac-snowleopard/userscripts/another-test-expected.txt, not copying over it. +Retrieving http://example.com/f/builders/Webkit Mac10.7/results/layout-test-results/userscripts/another-test-actual.txt. +""" + OutputCapture().assert_outputs(self, command._rebaseline_test, ["Webkit Mac10.7", "userscripts/another-test.html", "chromium-mac-snowleopard", "txt"], expected_stdout=expected_stdout) def test_rebaseline_expectations(self): command = RebaselineExpectations() @@ -60,10 +112,7 @@ class TestRebaseline(unittest.TestCase): # Don't enable logging until after we create the mock expectation files as some Port.__init__'s run subcommands. tool.executive = MockExecutive(should_log=True) - expected_stdout = """Retrieving results for chromium-gpu-mac-snowleopard from Webkit Mac10.6 - GPU. -Retrieving results for chromium-gpu-win-win7 from Webkit Win7 - GPU. -Retrieving results for chromium-gpu-win-xp from Webkit Win - GPU. -Retrieving results for chromium-linux-x86 from Webkit Linux 32. + expected_stdout = """Retrieving results for chromium-linux-x86 from Webkit Linux 32. userscripts/another-test.html userscripts/images.svg Retrieving results for chromium-linux-x86_64 from Webkit Linux. @@ -72,6 +121,9 @@ Retrieving results for chromium-linux-x86_64 from Webkit Linux. Retrieving results for chromium-mac-leopard from Webkit Mac10.5. userscripts/another-test.html userscripts/images.svg +Retrieving results for chromium-mac-lion from Webkit Mac10.7. + userscripts/another-test.html + userscripts/images.svg Retrieving results for chromium-mac-snowleopard from Webkit Mac10.6. userscripts/another-test.html userscripts/images.svg @@ -84,15 +136,16 @@ Retrieving results for chromium-win-win7 from Webkit Win7. Retrieving results for chromium-win-xp from Webkit Win. userscripts/another-test.html userscripts/images.svg -Optimizing baselines for userscripts/another-test.html. -Optimizing baselines for userscripts/images.svg. """ + expected_stderr = """MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Linux 32', 'userscripts/another-test.html'], cwd=/mock-checkout MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Linux 32', 'userscripts/images.svg'], cwd=/mock-checkout MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Linux', 'userscripts/another-test.html'], cwd=/mock-checkout MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Linux', 'userscripts/images.svg'], cwd=/mock-checkout MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Mac10.5', 'userscripts/another-test.html'], cwd=/mock-checkout MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Mac10.5', 'userscripts/images.svg'], cwd=/mock-checkout +MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Mac10.7', 'userscripts/another-test.html'], cwd=/mock-checkout +MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Mac10.7', 'userscripts/images.svg'], cwd=/mock-checkout MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Mac10.6', 'userscripts/another-test.html'], cwd=/mock-checkout MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Mac10.6', 'userscripts/images.svg'], cwd=/mock-checkout MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Vista', 'userscripts/another-test.html'], cwd=/mock-checkout @@ -101,8 +154,17 @@ MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Win7', 'userscripts/anothe MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Win7', 'userscripts/images.svg'], cwd=/mock-checkout MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Win', 'userscripts/another-test.html'], cwd=/mock-checkout MOCK run_command: ['echo', 'rebaseline-test', 'Webkit Win', 'userscripts/images.svg'], cwd=/mock-checkout -MOCK run_command: ['echo', 'optimize-baselines', 'userscripts/another-test.html'], cwd=/mock-checkout -MOCK run_command: ['echo', 'optimize-baselines', 'userscripts/images.svg'], cwd=/mock-checkout """ + + command._tests_to_rebaseline = lambda port: ['userscripts/another-test.html', 'userscripts/images.svg'] + OutputCapture().assert_outputs(self, command.execute, [MockOptions(optimize=False), [], tool], expected_stdout=expected_stdout, expected_stderr=expected_stderr) + + expected_stdout_with_optimize = expected_stdout + ( + "Optimizing baselines for userscripts/another-test.html.\n" + "Optimizing baselines for userscripts/images.svg.\n") + expected_stderr_with_optimize = expected_stderr + ( + "MOCK run_command: ['echo', 'optimize-baselines', 'userscripts/another-test.html'], cwd=/mock-checkout\n" + "MOCK run_command: ['echo', 'optimize-baselines', 'userscripts/images.svg'], cwd=/mock-checkout\n") + command._tests_to_rebaseline = lambda port: [] if not port.name().find('-gpu-') == -1 else ['userscripts/another-test.html', 'userscripts/images.svg'] - OutputCapture().assert_outputs(self, command.execute, [None, [], tool], expected_stdout=expected_stdout, expected_stderr=expected_stderr) + OutputCapture().assert_outputs(self, command.execute, [MockOptions(optimize=True), [], tool], expected_stdout=expected_stdout_with_optimize, expected_stderr=expected_stderr_with_optimize) diff --git a/Tools/Scripts/webkitpy/tool/servers/gardeningserver.py b/Tools/Scripts/webkitpy/tool/servers/gardeningserver.py index b090af912..17e543780 100644 --- a/Tools/Scripts/webkitpy/tool/servers/gardeningserver.py +++ b/Tools/Scripts/webkitpy/tool/servers/gardeningserver.py @@ -137,12 +137,15 @@ class GardeningHTTPRequestHandler(ReflectionHandler): def rebaseline(self): builder = self.query['builder'][0] - test = self.query['test'][0] - self._run_webkit_patch([ + command = [ 'rebaseline-test', builder, - test, - ]) + self.query['test'][0], + ] + fallback_port = builders.fallback_port_name_for_new_port(builder) + if fallback_port: + command.append(fallback_port) + self._run_webkit_patch(command) self._serve_text('success') def optimizebaselines(self): diff --git a/Tools/Scripts/webkitpy/tool/servers/gardeningserver_unittest.py b/Tools/Scripts/webkitpy/tool/servers/gardeningserver_unittest.py index 9d99835f1..f41a38a78 100644 --- a/Tools/Scripts/webkitpy/tool/servers/gardeningserver_unittest.py +++ b/Tools/Scripts/webkitpy/tool/servers/gardeningserver_unittest.py @@ -31,6 +31,7 @@ import unittest from webkitpy.common.system.outputcapture import OutputCapture from webkitpy.layout_tests.models.test_configuration import * +from webkitpy.layout_tests.port import builders from webkitpy.thirdparty.mock import Mock from webkitpy.tool.mocktool import MockTool from webkitpy.common.system.executive_mock import MockExecutive @@ -182,10 +183,17 @@ class GardeningServerTest(unittest.TestCase): self._post_to_path("/rollout?revision=2314&reason=MOCK+rollout+reason", expected_stderr=expected_stderr, expected_stdout=expected_stdout) def test_rebaseline(self): + builders._exact_matches = {"MOCK builder": {"port_name": "mock-port-name", "specifiers": set(["mock-specifier"])}} expected_stderr = "MOCK run_command: ['echo', 'rebaseline-test', 'MOCK builder', 'user-scripts/another-test.html'], cwd=/mock-checkout\n" expected_stdout = "== Begin Response ==\nsuccess\n== End Response ==\n" self._post_to_path("/rebaseline?builder=MOCK+builder&test=user-scripts/another-test.html", expected_stderr=expected_stderr, expected_stdout=expected_stdout) + def test_rebaseline_new_port(self): + builders._exact_matches = {"MOCK builder": {"port_name": "mock-port-name", "specifiers": set(["mock-specifier"]), "move_overwritten_baselines_to": "mock-port-fallback"}} + expected_stderr = "MOCK run_command: ['echo', 'rebaseline-test', 'MOCK builder', 'user-scripts/another-test.html', 'mock-port-fallback'], cwd=/mock-checkout\n" + expected_stdout = "== Begin Response ==\nsuccess\n== End Response ==\n" + self._post_to_path("/rebaseline?builder=MOCK+builder&test=user-scripts/another-test.html", expected_stderr=expected_stderr, expected_stdout=expected_stdout) + def test_optimizebaselines(self): expected_stderr = "MOCK run_command: ['echo', 'optimize-baselines', 'user-scripts/another-test.html'], cwd=/mock-checkout\n" expected_stdout = "== Begin Response ==\nsuccess\n== End Response ==\n" diff --git a/Tools/Scripts/webkitpy/tool/steps/options.py b/Tools/Scripts/webkitpy/tool/steps/options.py index 1141df7e4..c29e59d9c 100644 --- a/Tools/Scripts/webkitpy/tool/steps/options.py +++ b/Tools/Scripts/webkitpy/tool/steps/options.py @@ -1,9 +1,9 @@ # 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 @@ -13,7 +13,7 @@ # * 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 @@ -44,7 +44,7 @@ class Options(object): description = make_option("-m", "--description", action="store", type="string", dest="description", help="Description string for the attachment") email = make_option("--email", action="store", type="string", dest="email", help="Email address to use in ChangeLogs.") force_clean = make_option("--force-clean", action="store_true", dest="force_clean", default=False, help="Clean working directory before applying patches (removes local changes and commits)") - git_commit = make_option("-g", "--git-commit", action="store", dest="git_commit", help="Operate on a local commit. If a range, the commits are squashed into one. HEAD.. operates on working copy changes only.") + git_commit = make_option("-g", "--git-commit", action="store", dest="git_commit", help="Operate on a local commit. If a range, the commits are squashed into one. <ref>.... includes the working copy changes. UPSTREAM can be used for the upstream/tracking branch.") local_commit = make_option("--local-commit", action="store_true", dest="local_commit", default=False, help="Make a local commit for each applied patch") non_interactive = make_option("--non-interactive", action="store_true", dest="non_interactive", default=False, help="Never prompt the user, fail as fast as possible.") obsolete_patches = make_option("--no-obsolete", action="store_false", dest="obsolete_patches", default=True, help="Do not obsolete old patches before posting this one.") |
