diff options
author | Ben Murdoch <benm@google.com> | 2011-05-16 16:25:10 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2011-05-23 18:54:14 +0100 |
commit | ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb (patch) | |
tree | db769fadd053248f85db67434a5b275224defef7 /Tools | |
parent | 52e2557aeb8477967e97fd24f20f8f407a10fa15 (diff) | |
download | external_webkit-ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb.zip external_webkit-ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb.tar.gz external_webkit-ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddb.tar.bz2 |
Merge WebKit at r76408: Initial merge by git.
Change-Id: I5b91decbd693ccbf5c1b8354b37cd68cc9a1ea53
Diffstat (limited to 'Tools')
89 files changed, 2136 insertions, 945 deletions
diff --git a/Tools/ChangeLog b/Tools/ChangeLog index 9c81c47..3ef3b4a 100644 --- a/Tools/ChangeLog +++ b/Tools/ChangeLog @@ -1,3 +1,739 @@ +2011-01-21 Sam Weinig <sam@webkit.org> + + Reviewed by Geoffrey Sean Garen and Mark Rowe. + + WebKitTestRunner needs the HOME environment variable to be set. + <rdar://problem/8896573> + + * Scripts/old-run-webkit-tests: Set the HOME environment variable if + it exists. + +2011-01-21 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Eric Seidel. + + Suppress a few remaining integration tests so that none of the + layout_test unit tests ever read from the filesystem or launch + subprocesses that aren't part of the unit tests. + + Also fix a minor bug in the printing unit tests that was + incorrectly relying on sys.argv. + + https://bugs.webkit.org/show_bug.cgi?id=52863 + + * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py: + * Scripts/webkitpy/layout_tests/port/port_testcase.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2011-01-21 Darin Adler <darin@apple.com> + + Fix Mac build. + + * MiniBrowser/mac/BrowserWindowController.m: + (-[BrowserWindowController awakeFromNib]): Pass 0 for runModal function. + +2011-01-20 Darin Adler <darin@apple.com> + + Reviewed by Dan Bernstein. + + WebKit2: Implement showModalDialog + https://bugs.webkit.org/show_bug.cgi?id=52855 + + This fixes WebKitTestRunner to compile, but more work is probably + needed to get it to pass the tests. + + * WebKitTestRunner/TestController.cpp: + (WTR::TestController::runModal): Added. Calls through to the + platform-specific version of runModal. + (WTR::TestController::createOtherPage): Changed to be a private + static member function so it can refer to runModal, which is + a private static member function. + (WTR::TestController::initialize): Pass 0 for the runModal + function since we don't need to run the main window modal. + I suspect this is wrong and will need to change. + * WebKitTestRunner/TestController.h: Added declarations for + the functions added above. + * WebKitTestRunner/mac/TestControllerMac.mm: + (WTR::TestController::runModal): Added. Untested implementation. + * WebKitTestRunner/qt/TestControllerQt.cpp: + (WTR::TestController::runModal): Added. + * WebKitTestRunner/win/TestControllerWin.cpp: + (WTR::TestController::runModal): Added. + +2011-01-21 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + Split Host object off from WebKitPatch for easier re-use + https://bugs.webkit.org/show_bug.cgi?id=52284 + + new-run-webkit-tests and other tools are eventually going to want one of these. + Basically you need to inherit from this class if you want to pretend to be a + self.tool object for Steps/Commands. + + * Scripts/webkitpy/common/host.py: Added. + * Scripts/webkitpy/tool/main.py: + +2011-01-20 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Adam Barth. + + Disable the tests that start and stop the http server and web + server, so that we don't have to worry about port collisions on + the bots. + + https://bugs.webkit.org/show_bug.cgi?id=52861 + + * Scripts/webkitpy/layout_tests/port/port_testcase.py: + +2011-01-20 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Eric Seidel. + + nrwt: rewrite google_chrome_unittest to use mock filesystem. + + https://bugs.webkit.org/show_bug.cgi?id=52772 + + * Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py: + +2011-01-20 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Eric Siedel. + + nrwt: clean up almost all remaining port references, remove + unnecessary import clauses. The only remaining references are + in places where a mock filesystem makes no sense or can't be + used, and in one routine in port/google_chrome_unittest that + I'll rewrite in a separate patch. + + https://bugs.webkit.org/show_bug.cgi?id=52771 + + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + * Scripts/webkitpy/layout_tests/port/chromium_gpu.py: + * Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py: + * Scripts/webkitpy/layout_tests/port/chromium_linux.py: + * Scripts/webkitpy/layout_tests/port/chromium_mac.py: + * Scripts/webkitpy/layout_tests/port/chromium_unittest.py: + * Scripts/webkitpy/layout_tests/port/chromium_win.py: + * Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py: + * Scripts/webkitpy/layout_tests/port/google_chrome.py: + * Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py: + * Scripts/webkitpy/layout_tests/port/gtk.py: + * Scripts/webkitpy/layout_tests/port/mac.py: + * Scripts/webkitpy/layout_tests/port/port_testcase.py: + * Scripts/webkitpy/layout_tests/port/qt.py: + * Scripts/webkitpy/layout_tests/port/webkit.py: + * Scripts/webkitpy/layout_tests/port/win.py: + * Scripts/webkitpy/layout_tests/test_types/image_diff.py: + +2011-01-20 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Mihai Parparita. + + remove fs refs from run_webkit_tests, rebaseline_chromium_webkit_tests + + https://bugs.webkit.org/show_bug.cgi?id=52762 + + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2011-01-20 Tony Chang <tony@chromium.org> + + Reviewed by Ojan Vafai. + + [chromium] fix the paths used for the rebaseline tool + https://bugs.webkit.org/show_bug.cgi?id=52857 + + Some of the bots were renamed so the path to grab the results zip + file has changed. + + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: + +2011-01-20 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Tony Chang. + + Fix bug introduced in r72688 / bug 52768 that broke the + generation of the output filename links in the results.html + output. Apparently none of the unit tests actually checked to + make sure the generated links were correct :( + + https://bugs.webkit.org/show_bug.cgi?id=52854 + + * Scripts/webkitpy/layout_tests/layout_package/test_failures.py: + * Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py: + +2011-01-20 Alexey Proskuryakov <ap@apple.com> + + Reviewed by Darin Adler. + + https://bugs.webkit.org/show_bug.cgi?id=52849 + Make window.print work with WebKit2 + + * MiniBrowser/mac/BrowserWindowController.m: + (-[BrowserWindowController awakeFromNib]): + * WebKitTestRunner/TestController.cpp: + (WTR::createOtherPage): + (WTR::TestController::initialize): + Added zeroes to WKPageUIClient structures to avoid build failures. + +2011-01-20 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Eric Seidel. + + nrwt: remove fs refs from printing, test_failures, test_expectations, text_diff + + https://bugs.webkit.org/show_bug.cgi?id=52756 + + * Scripts/webkitpy/layout_tests/layout_package/printing.py: + * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py: + * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py: + * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py: + * Scripts/webkitpy/layout_tests/layout_package/test_failures.py: + * Scripts/webkitpy/layout_tests/test_types/text_diff.py: + +2011-01-20 Mansi Mithal <mansi.mithal@nokia.com> + + Reviewed by Antonio Gomes. + + QtTestBrowser should have a seperate menu for Settings + https://bugs.webkit.org/show_bug.cgi?id=52817 + + Added a new menu item named "Settings" + and moved the "Enable interrupting js scripts" and "Enable js pop up windows" under the "Settings" menu + + * QtTestBrowser/launcherwindow.cpp: + (LauncherWindow::createChrome): + +2011-01-20 Sam Weinig <sam@webkit.org> + + Reviewed by John Sullivan. + + Update update-webkit-localizable-strings with new path to WebKit. + + * Scripts/update-webkit-localizable-strings: + +2011-01-20 James Robinson <jamesr@chromium.org> + + Reviewed by Darin Fisher. + + Implement mozilla's requestAnimationFrame API + https://bugs.webkit.org/show_bug.cgi?id=51218 + + Chromium DumpRenderTree support for window.webkitRequestAnimationFrame. + + * DumpRenderTree/chromium/WebViewHost.cpp: + (invokeScheduleComposite): + (WebViewHost::scheduleAnimation): + (WebViewHost::paintInvalidatedRegion): + * DumpRenderTree/chromium/WebViewHost.h: + +2011-01-20 Maciej Stachowiak <mjs@apple.com> + + Reviewed by Adam Roben. + + WebKitTestRunner needs to support layoutTestController.evaluateScriptInIsolatedWorld + https://bugs.webkit.org/show_bug.cgi?id=42327 + + * WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm: Add support + for methods that take their normal arguments but also a JSContextRef. + * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: IDL definition + for evaluateScriptInIsolatedWorld. + * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp: + (WTR::InjectedBundlePage::didClearWindowForFrame): Set a magic variable only if + this call is for an isolated world. + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::worldMap): Helper to create a world map. + (WTR::LayoutTestController::worldIDForWorld): Map from an ID to a world. + (WTR::LayoutTestController::evaluateScriptInIsolatedWorld): The newly + added LayoutTestController API. + * WebKitTestRunner/InjectedBundle/LayoutTestController.h: + +2011-01-19 Adam Roben <aroben@apple.com> + + Convert paths in environment variables back to msys-style inside commit-log-editor + + When this script gets run from inside git commit, msys-style paths in the environment will + have been turned into Windows-style paths with forward slashes. This screws up functions + like File::Spec->rel2abs, which seem to rely on $PWD having an msys-style path. We convert + the paths back to msys-style before doing anything else. + + Fixes <http://webkit.org/b/48527> commit-log-editor uses full paths for section headers when + using msysgit's Perl and multiple ChangeLogs have been edited + + Reviewed by David Kilzer. + + * Scripts/commit-log-editor: Call fixEnvironment before doing anything else. + (fixEnvironment): Added. When run in msys in conjunction with git (i.e., when invoked from + inside git commit), convert Windows-style paths in the environment back to msys-style paths. + +2011-01-20 Zoltan Horvath <zoltan@webkit.org> + + [Win] Unreviewed build fix after r76248. + + * DumpRenderTree/ForwardingHeaders/wtf/FastAllocBase.h: Added. + +2011-01-20 Zoltan Horvath <zoltan@webkit.org> + + Reviewed by Csaba Osztrogonác. + + Refactoring of the custom allocation framework + https://bugs.webkit.org/show_bug.cgi?id=49897 + + Inheriting from FastAllocBase can result in objects getting larger (bug #33896, #46589). + The modification replaces Noncopyable and FastAllocBase classes and these inherits with their + equivalent macro implementation at the necessary places. +2011-01-20 Yi Shen <yi.4.shen@nokia.com> + + Unreviewed. + + Adding myself to committers.py. + + * Scripts/webkitpy/common/config/committers.py: + +2011-01-20 Adam Barth <abarth@webkit.org> + + Reviewed by Tony Chang. + + Chromium builders don't delete unversioned directories when DEPS change + https://bugs.webkit.org/show_bug.cgi?id=52745 + + If we pass this option to gclient sync, gclient will delete directories + that are no longer part of DEPS instead of leaving them around to + confuse us later. Apparently, the downstream buildbots use this option + already. + + * Scripts/update-webkit-chromium: + +2011-01-19 Dirk Pranke <dpranke@chromium.org> + + Unreviewed, build fix - I pulled this patch in to fix an issue + revealed by r76195 running on some new bots). Also fix a couple + of other issues revealed in testing. + + nrwt: remove fs refs from layout_package/json* + + https://bugs.webkit.org/show_bug.cgi?id=52754 + + * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py: + * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py: + * Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py: + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + * Scripts/webkitpy/layout_tests/port/base.py: + +2011-01-19 Dirk Pranke <dpranke@chromium.org> + + Unreviewed, build fix. + + Fix a couple of minor bugs discovered while bringing up new bots + for testing. + + * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + +2011-01-19 James Robinson <jamesr@chromium.org> + + Unreviewed, rolling out r76194. + http://trac.webkit.org/changeset/76194 + https://bugs.webkit.org/show_bug.cgi?id=51218 + + Caused mysterious compile failure on the chromium win + build.webkit.org bots + + * DumpRenderTree/chromium/WebViewHost.cpp: + (WebViewHost::paintInvalidatedRegion): + * DumpRenderTree/chromium/WebViewHost.h: + +2011-01-19 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Mihai Parparita. + + remove fs refs from test_runner, dump_render_tree_thread + + https://bugs.webkit.org/show_bug.cgi?id=52753 + + * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py: + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + * Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2011-01-19 James Robinson <jamesr@chromium.org> + + Reviewed by Darin Fisher. + + Implement mozilla's requestAnimationFrame API + https://bugs.webkit.org/show_bug.cgi?id=51218 + + Chromium DumpRenderTree support for window.webkitRequestAnimationFrame. + + * DumpRenderTree/chromium/WebViewHost.cpp: + (invokeScheduleComposite): + (WebViewHost::scheduleAnimation): + (WebViewHost::paintInvalidatedRegion): + * DumpRenderTree/chromium/WebViewHost.h: + +2011-01-19 Dirk Pranke <dpranke@chromium.org> + + Unreviewed, build fix. + + Fix a few incorrect "self._filesystem" references introduced in + r76184. + + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/chromium_linux.py: + +2011-01-19 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Mihai Parparita. + + add a .sep property, abspath(), isabs(), mtime(), and + open_text_file_for_writing() to filesystem modules. Some of + these properties are not needed in this patch but will be needed + in subsequent patches (I'm doing this to avoid having to track + multiple versions of a single file). + + Also, change most of the port/* modules to use the filesystem + objects instead of referencing the filesystem directly. + + https://bugs.webkit.org/show_bug.cgi?id=52748 + + * Scripts/webkitpy/common/system/filesystem.py: + * Scripts/webkitpy/common/system/filesystem_mock.py: + * Scripts/webkitpy/layout_tests/port/__init__.py: + * Scripts/webkitpy/layout_tests/port/base.py: + * Scripts/webkitpy/layout_tests/port/base_unittest.py: + * Scripts/webkitpy/layout_tests/port/chromium.py: + * Scripts/webkitpy/layout_tests/port/chromium_unittest.py: + * Scripts/webkitpy/layout_tests/port/config.py: + * Scripts/webkitpy/layout_tests/port/test.py: + * Scripts/webkitpy/layout_tests/port/test_files_unittest.py: + +2011-01-19 Maciej Stachowiak <mjs@apple.com> + + Reviewed by Anders Carlsson. + + If resetting between tests times out, treat it as a WebProcess crash + https://bugs.webkit.org/show_bug.cgi?id=52757 + + * WebKitTestRunner/TestController.cpp: + (WTR::TestController::runTest): + +2011-01-19 Alexey Proskuryakov <ap@apple.com> + + Reviewed by Darin Adler. + + https://bugs.webkit.org/show_bug.cgi?id=52739 + Make it possible for a WebKit2 client to print headers and footers + + Added dummy implementations for new printing UIClient calls. + + * MiniBrowser/mac/BrowserWindowController.m: + (-[BrowserWindowController awakeFromNib]): + * WebKitTestRunner/TestController.cpp: + (WTR::createOtherPage): + (WTR::TestController::initialize): + +2011-01-19 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Ojan Vafai. + + Change webkitpy/layout_tests/port/test.py to use the + in-memory filesystem for cleaner unit testing. This + change allows us to kill a lot of code that was + specific to the test port, at the cost of being a + little less clear about how things would work if + you didn't have a filesystem. + + https://bugs.webkit.org/show_bug.cgi?id=52605 + + * Scripts/webkitpy/layout_tests/port/test.py: + +2011-01-19 Dirk Pranke <dpranke@chromium.org> + + Unreviewed, build fix. + + Fix test failure caused by committing attachment 79368 instead + of attachment 79461 on bug 52604. + + * Scripts/webkitpy/common/system/filesystem_mock.py: + +2011-01-19 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Mihai Parparita. + + new-run-webkit-tests: remove use of os.walk, use mock filesystem for better + unit testing. os.walk() is too much of a hassle to implement on + top of the in-memory mock filesystem and adding the necessary + interface to files_under() gives clients a cleaner API anyway + (for this particular usage model). + + https://bugs.webkit.org/show_bug.cgi?id=52691 + + * Scripts/webkitpy/common/system/filesystem.py: + * Scripts/webkitpy/common/system/filesystem_mock.py: + * Scripts/webkitpy/layout_tests/port/test_files.py: + * Scripts/webkitpy/layout_tests/port/test_files_unittest.py: + +2011-01-19 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Tony Chang. + + Change more modules in the layout-tests code to use the + filesystem wrapper for cleaner unit testing. + + This patch also adds the glob() wrapper to the filesystem + abstraction. + + https://bugs.webkit.org/show_bug.cgi?id=52604 + + * Scripts/webkitpy/layout_tests/port/test_files.py: + * Scripts/webkitpy/layout_tests/port/test_files_unittest.py: + * Scripts/webkitpy/layout_tests/test_types/test_type_base.py: + * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py: + * Scripts/webkitpy/common/system/filesystem.py: + * Scripts/webkitpy/common/system/filesystem_mock.py: + +2011-01-19 Levi Weintraub <leviw@chromium.org> + + Unreviewed. + + Updating my email addresses and irc nick. + + * Scripts/webkitpy/common/config/committers.py: + +2011-01-19 Tony Chang <tony@chromium.org> + + Reviewed by Mihai Parparita. + + [chromium] [linux] if check-sys-deps fails, output the failure reason + https://bugs.webkit.org/show_bug.cgi?id=52671 + + * Scripts/webkitpy/common/system/executive_mock.py: Add support for + error handler functions. + * Scripts/webkitpy/layout_tests/port/chromium.py: + output the error text from --check-sys-deps + * Scripts/webkitpy/layout_tests/port/chromium_unittest.py: + +2011-01-19 Aparna Nandyal <aparna.nand@wipro.com> + + Reviewed by Andreas Kling. + + [Qt] QtTestBrowser crashes when closing if Facebook is opened + https://bugs.webkit.org/show_bug.cgi?id=52554 + + QtNetworkAccessManager is created in a thread and set as + member variable in QWebPage. When the thread is destroyed + the object is still used. So fix will set the object to + NULL once the thread is destroyed. + + * QtTestBrowser/launcherwindow.cpp: + (LauncherWindow::~LauncherWindow): + +2011-01-18 Maciej Stachowiak <mjs@apple.com> + + Rubber stamped by Csaba Osztrogonac + + * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp: Removed unncessary inculde of WKStringCF.h + +2011-01-18 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Tony Chang. + + new-run-webkit-tests: add a --build-directory command line argument + + Official Google Chrome builds use a non-standard build directory + location. This patch adds a --build-directory argument that + allows that location to be specified on the command line. Only + Chromium-based builds will use this flag for now, but anyone can + in the future. + + There are no unit tests for this since it's difficult to test + until mock filesystems are fully supported in the code. This was + tested by hand for now. + + https://bugs.webkit.org/show_bug.cgi?id=52694 + + * Scripts/webkitpy/layout_tests/port/chromium_linux.py: + * Scripts/webkitpy/layout_tests/port/chromium_mac.py: + * Scripts/webkitpy/layout_tests/port/chromium_win.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests.py: + +2011-01-18 Maciej Stachowiak <mjs@apple.com> + + Not reviewed. Bot fix. + + Remove an inadvertently committed debugging print. + + * DumpRenderTree/mac/LayoutTestControllerMac.mm: + (LayoutTestController::notifyDone): + +2011-01-18 Maciej Stachowiak <mjs@apple.com> + + Reviewed by Sam Weinig. + + WebKitTestRunner should track loading more like DumpRenderTree + https://bugs.webkit.org/show_bug.cgi?id=52692 + + Change load tracking to track the current top loading frame, in the manner of DumpRenderTree. + This makes some tests that call notifyDone multiple times pass. + + * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp: + (WTR::InjectedBundle::InjectedBundle): + (WTR::InjectedBundle::done): + * WebKitTestRunner/InjectedBundle/InjectedBundle.h: + (WTR::InjectedBundle::topLoadingFrame): + (WTR::InjectedBundle::setTopLoadingFrame): + * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp: + (WTR::InjectedBundlePage::InjectedBundlePage): + (WTR::InjectedBundlePage::stopLoading): + (WTR::InjectedBundlePage::didStartProvisionalLoadForFrame): + (WTR::InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame): + (WTR::InjectedBundlePage::didFinishLoadForFrame): + (WTR::InjectedBundlePage::didFailLoadWithErrorForFrame): + * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h: + * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: + (WTR::LayoutTestController::notifyDone): + * WebKitTestRunner/TestController.cpp: + (WTR::TestController::didReceiveMessageFromInjectedBundle): + +2011-01-18 Mihai Parparita <mihaip@chromium.org> + + Reviewed by Kent Tamura. + + [Chromium] NRWT looking for DRT binary in the wrong path on Mac + https://bugs.webkit.org/show_bug.cgi?id=52678 + + Update path now that WebKit is inside Source. + + * Scripts/webkitpy/layout_tests/port/chromium_mac.py: + +2011-01-18 Robert Hogan <robert@webkit.org> + + Reviewed by Simon Hausmann. + + [Qt] http/tests/incremental/slow-utf8-text.pl fails + https://bugs.webkit.org/show_bug.cgi?id=44282 + + * DumpRenderTree/qt/DumpRenderTreeQt.cpp: + (WebCore::DumpRenderTree::dump): + +2011-01-18 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Mihai Parparita. + + Fix a small race condition that could cause the unit tests for + new-run-webkit-tests to fail in a multithreaded environment. + There was a small window in the code where one thread would + check to see if a thread had raised an exception, do something, + and then check to see if the thread was alive. If the other + thread raised an exception and exited in between these two + steps, the exception would be lost. Flipping the order of the + two checks fixes the race, since we will now always check for an + exception on the thread before exiting. + + https://bugs.webkit.org/show_bug.cgi?id=51579 + + * Scripts/webkitpy/layout_tests/layout_package/message_broker.py: + +2011-01-18 Eric Seidel <eric@webkit.org> + + Reviewed by Adam Barth. + + commit-queue dies when test archiving fails + https://bugs.webkit.org/show_bug.cgi?id=52617 + + I looked at the machine and it had 10 archives already + thus find_unused_name was returning None. I've upped + the limit to 100 (per bug) and tested the case where + find_unused_name returns None (making archive return None). + + * Scripts/webkitpy/common/system/workspace.py: + * Scripts/webkitpy/common/system/workspace_unittest.py: + * Scripts/webkitpy/tool/bot/commitqueuetask.py: + * Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py: + * Scripts/webkitpy/tool/commands/queues.py: + +2011-01-18 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Ojan Vafai. + + Update rebaseline-chromium-webkit-tests unit tests to use a mock + filesystem. Also fix a couple of "with" statements missed by + r76050. + + https://bugs.webkit.org/show_bug.cgi?id=52487 + + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py: + +2011-01-18 Sergio Villar Senin <svillar@igalia.com> + + Reviewed by Martin Robinson. + + [Gtk] Build fixes for gtk3 build + https://bugs.webkit.org/show_bug.cgi?id=52648 + + * DumpRenderTree/gtk/EventSender.cpp: + (beginDragWithFilesCallback): + +2011-01-18 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Mihai Parparita. + + Update rebaseline-chromium-webkit-tests to use filesystem objects + instead of direct references to os.path, shutil, tempfile, etc. + + This patch doesn't change anything, but will allow subsequent + patches to change the unit tests to no longer use the real + filesystem. + + This patch adds a bunch more methods to the filesystem object as + well. + + https://bugs.webkit.org/show_bug.cgi?id=52482 + + * Scripts/webkitpy/common/system/filesystem.py: + * Scripts/webkitpy/common/system/filesystem_mock.py: + * Scripts/webkitpy/tool/commands/queues.py: + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: + * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py: + +2011-01-18 Dirk Pranke <dpranke@chromium.org> + + Reviewed by Mihai Parparita. + + new-run-webkit-tests shouldn't crash when you try to run a + directory containing only skipped files. + + https://bugs.webkit.org/show_bug.cgi?id=52478 + + * Scripts/webkitpy/layout_tests/layout_package/test_runner.py: + * Scripts/webkitpy/layout_tests/port/test.py: + * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: + +2011-01-18 Adam Bergkvist <adam.bergkvist@ericsson.com> and Martin Robinson <mrobinson@igalia.com> + + Reviewed by Gustavo Noronha Silva. + + [GTK] The GTK+ EventSender needs support for beginDragWithFiles + https://bugs.webkit.org/show_bug.cgi?id=40833 + + * DumpRenderTree/gtk/EventSender.cpp: Add a beginDragWithFiles implementation for the + GTK+ event sender. + (dragWithFilesDragDataGetCallback): Added. + (dragWithFilesDragEndCallback): Added. + (beginDragWithFilesCallback): Added. + +2011-01-18 Gyuyoung Kim <gyuyoung.kim@samsung.com> + + Reviewed by Adam Barth. + + ews: Add additional watcher to efl ews + https://bugs.webkit.org/show_bug.cgi?id=52613 + + Add gyuyoung.kim@samsung.com to watcher list of efl-ews. + + * Scripts/webkitpy/tool/commands/earlywarningsystem.py: + 2011-01-17 Tony Gentilcore <tonyg@chromium.org> Reviewed by Alexey Proskuryakov. diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastAllocBase.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastAllocBase.h new file mode 100644 index 0000000..421c040 --- /dev/null +++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastAllocBase.h @@ -0,0 +1 @@ +#include <JavaScriptCore/FastAllocBase.h> diff --git a/Tools/DumpRenderTree/chromium/CppBoundClass.h b/Tools/DumpRenderTree/chromium/CppBoundClass.h index 6cb638e..6151a9c 100644 --- a/Tools/DumpRenderTree/chromium/CppBoundClass.h +++ b/Tools/DumpRenderTree/chromium/CppBoundClass.h @@ -58,7 +58,8 @@ typedef Vector<CppVariant> CppArgumentList; // CppBoundClass lets you map Javascript method calls and property accesses // directly to C++ method calls and CppVariant* variable access. -class CppBoundClass : public Noncopyable { +class CppBoundClass { + WTF_MAKE_NONCOPYABLE(CppBoundClass); public: class PropertyCallback { public: diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h index e1478d0..665435c 100644 --- a/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h +++ b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h @@ -49,8 +49,8 @@ struct WebDevToolsMessageData; class DRTDevToolsClient; -class DRTDevToolsAgent : public WebKit::WebDevToolsAgentClient - , public Noncopyable { +class DRTDevToolsAgent : public WebKit::WebDevToolsAgentClient { + WTF_MAKE_NONCOPYABLE(DRTDevToolsAgent); public: DRTDevToolsAgent(); virtual ~DRTDevToolsAgent() {} diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h index 9ca1402..0cba51c 100644 --- a/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h +++ b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h @@ -48,8 +48,8 @@ class WebView; class DRTDevToolsAgent; -class DRTDevToolsClient : public WebKit::WebDevToolsFrontendClient - , public Noncopyable { +class DRTDevToolsClient : public WebKit::WebDevToolsFrontendClient { + WTF_MAKE_NONCOPYABLE(DRTDevToolsClient); public: DRTDevToolsClient(DRTDevToolsAgent*, WebKit::WebView*); virtual ~DRTDevToolsClient(); diff --git a/Tools/DumpRenderTree/chromium/TestNavigationController.h b/Tools/DumpRenderTree/chromium/TestNavigationController.h index b671489..8502a96 100644 --- a/Tools/DumpRenderTree/chromium/TestNavigationController.h +++ b/Tools/DumpRenderTree/chromium/TestNavigationController.h @@ -111,7 +111,8 @@ public: // Test shell's NavigationController. The goal is to be as close to the Chrome // version as possible. -class TestNavigationController: public Noncopyable { +class TestNavigationController { + WTF_MAKE_NONCOPYABLE(TestNavigationController); public: TestNavigationController(NavigationHost*); ~TestNavigationController(); diff --git a/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h index 4e22461..ede1458 100644 --- a/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h +++ b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h @@ -46,7 +46,8 @@ // Skia forward declarations struct SkIRect; -class WebThemeControlDRTWin : public Noncopyable { +class WebThemeControlDRTWin { + WTF_MAKE_NONCOPYABLE(WebThemeControlDRTWin); public: // This list of states mostly mirrors the list in WebCore/platform/ThemeTypes.h // but is maintained separately since that isn't public and also to minimize diff --git a/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h index 2e15cf8..9b1e817 100644 --- a/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h +++ b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h @@ -50,7 +50,8 @@ #include "win/WebThemeEngine.h" #include <wtf/Noncopyable.h> -class WebThemeEngineDRTWin : public WebKit::WebThemeEngine, public Noncopyable { +class WebThemeEngineDRTWin : public WebKit::WebThemeEngine { + WTF_MAKE_NONCOPYABLE(WebThemeEngineDRTWin); public: WebThemeEngineDRTWin() {} diff --git a/Tools/DumpRenderTree/chromium/WebViewHost.cpp b/Tools/DumpRenderTree/chromium/WebViewHost.cpp index 62df390..18b107f 100644 --- a/Tools/DumpRenderTree/chromium/WebViewHost.cpp +++ b/Tools/DumpRenderTree/chromium/WebViewHost.cpp @@ -624,6 +624,19 @@ void WebViewHost::scheduleComposite() didInvalidateRect(clientRect); } +#if ENABLE(REQUEST_ANIMATION_FRAME) +static void invokeScheduleComposite(void* context) +{ + WebViewHost* wvh = static_cast<WebViewHost*>(context); + wvh->scheduleComposite(); +} + +void WebViewHost::scheduleAnimation() +{ + webkit_support::PostDelayedTask(invokeScheduleComposite, this, 0); +} +#endif + void WebViewHost::didFocus() { m_shell->setFocus(webWidget(), true); @@ -1438,6 +1451,9 @@ void WebViewHost::paintRect(const WebRect& rect) void WebViewHost::paintInvalidatedRegion() { +#if ENABLE(REQUEST_ANIMATION_FRAME) + webWidget()->animate(); +#endif webWidget()->layout(); WebSize widgetSize = webWidget()->size(); WebRect clientRect(0, 0, widgetSize.width, widgetSize.height); diff --git a/Tools/DumpRenderTree/chromium/WebViewHost.h b/Tools/DumpRenderTree/chromium/WebViewHost.h index 0a36aec..83d21dc 100644 --- a/Tools/DumpRenderTree/chromium/WebViewHost.h +++ b/Tools/DumpRenderTree/chromium/WebViewHost.h @@ -147,6 +147,9 @@ class WebViewHost : public WebKit::WebViewClient, public WebKit::WebFrameClient, virtual void didInvalidateRect(const WebKit::WebRect&); virtual void didScrollRect(int dx, int dy, const WebKit::WebRect&); virtual void scheduleComposite(); +#if ENABLE(REQUEST_ANIMATION_FRAME) + virtual void scheduleAnimation(); +#endif virtual void didFocus(); virtual void didBlur(); virtual void didChangeCursor(const WebKit::WebCursorInfo&); diff --git a/Tools/DumpRenderTree/gtk/EventSender.cpp b/Tools/DumpRenderTree/gtk/EventSender.cpp index b844558..923a4ba 100644 --- a/Tools/DumpRenderTree/gtk/EventSender.cpp +++ b/Tools/DumpRenderTree/gtk/EventSender.cpp @@ -34,21 +34,21 @@ #include "DumpRenderTree.h" #include "WebCoreSupport/DumpRenderTreeSupportGtk.h" - +#include <GOwnPtrGtk.h> +#include <GRefPtrGtk.h> #include <GtkVersioning.h> #include <JavaScriptCore/JSObjectRef.h> #include <JavaScriptCore/JSRetainPtr.h> #include <JavaScriptCore/JSStringRef.h> +#include <cstring> +#include <gdk/gdk.h> +#include <gdk/gdkkeysyms.h> #include <webkit/webkitwebframe.h> #include <webkit/webkitwebview.h> #include <wtf/ASCIICType.h> #include <wtf/Platform.h> #include <wtf/text/CString.h> -#include <gdk/gdk.h> -#include <gdk/gdkkeysyms.h> -#include <string.h> - extern "C" { extern GtkMenu* webkit_web_view_get_context_menu(WebKitWebView*); } @@ -416,12 +416,85 @@ static JSValueRef continuousMouseScrollByCallback(JSContextRef context, JSObject return JSValueMakeUndefined(context); } +static void dragWithFilesDragDataGetCallback(GtkWidget*, GdkDragContext*, GtkSelectionData *data, guint, guint, gpointer userData) +{ + gtk_selection_data_set_uris(data, static_cast<gchar**>(userData)); +} + +static void dragWithFilesDragEndCallback(GtkWidget* widget, GdkDragContext*, gpointer userData) +{ + g_signal_handlers_disconnect_by_func(widget, reinterpret_cast<void*>(dragWithFilesDragEndCallback), userData); + g_signal_handlers_disconnect_by_func(widget, reinterpret_cast<void*>(dragWithFilesDragDataGetCallback), userData); + g_strfreev(static_cast<gchar**>(userData)); +} + static JSValueRef beginDragWithFilesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { if (argumentCount < 1) return JSValueMakeUndefined(context); - // FIXME: Implement this completely once WebCore has complete drag and drop support + JSObjectRef filesArray = JSValueToObject(context, arguments[0], exception); + ASSERT(!exception || !*exception); + + const gchar* mainFrameURI = webkit_web_frame_get_uri(mainFrame); + GRefPtr<GFile> testFile(adoptGRef(g_file_new_for_uri(mainFrameURI))); + GRefPtr<GFile> parentDirectory(g_file_get_parent(testFile.get())); + if (!parentDirectory) + return JSValueMakeUndefined(context); + + // If this is an HTTP test, we still need to pass a local file path + // to WebCore. Even though the file doesn't exist, this should be fine + // for most tests. + GOwnPtr<gchar> scheme(g_file_get_uri_scheme(parentDirectory.get())); + if (g_str_equal(scheme.get(), "http") || g_str_equal(scheme.get(), "https")) { + GOwnPtr<gchar> currentDirectory(g_get_current_dir()); + parentDirectory = g_file_new_for_path(currentDirectory.get()); + } + + JSStringRef lengthProperty = JSStringCreateWithUTF8CString("length"); + int filesArrayLength = JSValueToNumber(context, JSObjectGetProperty(context, filesArray, lengthProperty, 0), 0); + JSStringRelease(lengthProperty); + + gchar** draggedFilesURIList = g_new0(gchar*, filesArrayLength + 1); + for (int i = 0; i < filesArrayLength; ++i) { + JSStringRef filenameString = JSValueToStringCopy(context, + JSObjectGetPropertyAtIndex(context, filesArray, i, 0), 0); + size_t bufferSize = JSStringGetMaximumUTF8CStringSize(filenameString); + GOwnPtr<gchar> filenameBuffer(static_cast<gchar*>(g_malloc(bufferSize))); + JSStringGetUTF8CString(filenameString, filenameBuffer.get(), bufferSize); + JSStringRelease(filenameString); + + GRefPtr<GFile> dragFile(g_file_get_child(parentDirectory.get(), filenameBuffer.get())); + draggedFilesURIList[i] = g_file_get_uri(dragFile.get()); + } + + GtkWidget* view = GTK_WIDGET(webkit_web_frame_get_web_view(mainFrame)); + g_object_connect(G_OBJECT(view), + "signal::drag-end", dragWithFilesDragEndCallback, draggedFilesURIList, + "signal::drag-data-get", dragWithFilesDragDataGetCallback, draggedFilesURIList, + NULL); + + GdkEvent event; + GdkWindow* viewGDKWindow = gtk_widget_get_window(view); + memset(&event, 0, sizeof(event)); + event.type = GDK_MOTION_NOTIFY; + event.motion.x = lastMousePositionX; + event.motion.y = lastMousePositionY; + event.motion.time = GDK_CURRENT_TIME; + event.motion.window = viewGDKWindow; + event.motion.device = getDefaultGDKPointerDevice(viewGDKWindow); + event.motion.state = GDK_BUTTON1_MASK; + + int xRoot, yRoot; + gdk_window_get_root_coords(viewGDKWindow, lastMousePositionX, lastMousePositionY, &xRoot, &yRoot); + event.motion.x_root = xRoot; + event.motion.y_root = yRoot; + + GtkTargetList* targetList = gtk_target_list_new(0, 0); + gtk_target_list_add_uri_targets(targetList, 0); + gtk_drag_begin(view, targetList, GDK_ACTION_COPY, 1, &event); + gtk_target_list_unref(targetList); + return JSValueMakeUndefined(context); } diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp index fe37958..ce608cc 100644 --- a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp +++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp @@ -915,6 +915,10 @@ void DumpRenderTree::dump() fprintf(stdout, "Source:\n\n%s\n", markup.toUtf8().constData()); } + QString mimeType = DumpRenderTreeSupportQt::responseMimeType(mainFrame); + if (mimeType == "text/plain") + m_controller->dumpAsText(); + // Dump render text... QString resultString; if (m_controller->shouldDumpAsText()) diff --git a/Tools/MiniBrowser/mac/BrowserWindowController.m b/Tools/MiniBrowser/mac/BrowserWindowController.m index e761624..3a1ffbd 100644 --- a/Tools/MiniBrowser/mac/BrowserWindowController.m +++ b/Tools/MiniBrowser/mac/BrowserWindowController.m @@ -639,6 +639,12 @@ static void runOpenPanel(WKPageRef page, WKFrameRef frame, WKOpenPanelParameters 0, /* exceededDatabaseQuota */ runOpenPanel, 0, /* decidePolicyForGeolocationPermissionRequest */ + 0, // headerHeight + 0, // footerHeight + 0, // drawHeader + 0, // drawFooter + 0, // printFrame + 0, // showModal }; WKPageSetPageUIClient(_webView.pageRef, &uiClient); } diff --git a/Tools/QtTestBrowser/launcherwindow.cpp b/Tools/QtTestBrowser/launcherwindow.cpp index 8a4b884..067b146 100644 --- a/Tools/QtTestBrowser/launcherwindow.cpp +++ b/Tools/QtTestBrowser/launcherwindow.cpp @@ -56,6 +56,9 @@ LauncherWindow::LauncherWindow(WindowOptions* data, QGraphicsScene* sharedScene) LauncherWindow::~LauncherWindow() { grabZoomKeys(false); + + if (page()) + page()->setQnamThreaded(false); } void LauncherWindow::init() @@ -256,16 +259,6 @@ void LauncherWindow::createChrome() toolsMenu->addSeparator(); - QAction* toggleInterruptingJavaScripteEnabled = toolsMenu->addAction("Enable interrupting js scripts", this, SLOT(toggleInterruptingJavaScriptEnabled(bool))); - toggleInterruptingJavaScripteEnabled->setCheckable(true); - toggleInterruptingJavaScripteEnabled->setChecked(false); - - QAction* toggleJavascriptCanOpenWindows = toolsMenu->addAction("Enable js popup windows", this, SLOT(toggleJavascriptCanOpenWindows(bool))); - toggleJavascriptCanOpenWindows->setCheckable(true); - toggleJavascriptCanOpenWindows->setChecked(false); - - toolsMenu->addSeparator(); - QAction* userAgentAction = toolsMenu->addAction("Change User Agent", this, SLOT(showUserAgentDialog())); userAgentAction->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_U)); @@ -371,6 +364,17 @@ void LauncherWindow::createChrome() showFPS->setEnabled(isGraphicsBased()); showFPS->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool))); showFPS->setChecked(m_windowOptions.showFrameRate); + + QMenu* settingsMenu = menuBar()->addMenu("&Settings"); + + QAction* toggleInterruptingJavaScripteEnabled = settingsMenu->addAction("Enable interrupting js scripts", this, SLOT(toggleInterruptingJavaScriptEnabled(bool))); + toggleInterruptingJavaScripteEnabled->setCheckable(true); + toggleInterruptingJavaScripteEnabled->setChecked(false); + + QAction* toggleJavascriptCanOpenWindows = settingsMenu->addAction("Enable js popup windows", this, SLOT(toggleJavascriptCanOpenWindows(bool))); + toggleJavascriptCanOpenWindows->setCheckable(true); + toggleJavascriptCanOpenWindows->setChecked(false); + #endif } diff --git a/Tools/Scripts/commit-log-editor b/Tools/Scripts/commit-log-editor index f40295d..2dda7e2 100755 --- a/Tools/Scripts/commit-log-editor +++ b/Tools/Scripts/commit-log-editor @@ -38,6 +38,7 @@ use Term::ReadKey; use VCSUtils; use webkitdirs; +sub fixEnvironment(); sub normalizeLineEndings($$); sub removeLongestCommonPrefixEndingInDoubleNewline(\%); sub isCommitLogEditor($); @@ -59,6 +60,8 @@ if (!$log) { usage(); } +fixEnvironment(); + my $baseDir = baseProductDir(); my $editor = $ENV{SVN_LOG_EDITOR}; @@ -282,6 +285,21 @@ if ($foundComment) { unlink "$log.edit"; +sub fixEnvironment() +{ + return unless isMsys() && isGit(); + + # When this script gets run from inside git commit, msys-style paths in the + # environment will have been turned into Windows-style paths with forward + # slashes. This screws up functions like File::Spec->rel2abs, which seem to + # rely on $PWD having an msys-style path. We convert the paths back to + # msys-style here by transforming "c:/foo" to "/c/foo" (e.g.). See + # <http://webkit.org/b/48527>. + foreach my $key (keys %ENV) { + $ENV{$key} =~ s#^([[:alpha:]]):/#/$1/#; + } +} + sub normalizeLineEndings($$) { my ($string, $endl) = @_; diff --git a/Tools/Scripts/old-run-webkit-tests b/Tools/Scripts/old-run-webkit-tests index 892b5a4..79e2d9e 100755 --- a/Tools/Scripts/old-run-webkit-tests +++ b/Tools/Scripts/old-run-webkit-tests @@ -1465,6 +1465,9 @@ sub openDumpTool() if (defined $ENV{'DYLD_LIBRARY_PATH'}) { $CLEAN_ENV{DYLD_LIBRARY_PATH} = $ENV{'DYLD_LIBRARY_PATH'}; } + if (defined $ENV{'HOME'}) { + $CLEAN_ENV{HOME} = $ENV{'HOME'}; + } $CLEAN_ENV{DYLD_FRAMEWORK_PATH} = $productDir; $CLEAN_ENV{DYLD_INSERT_LIBRARIES} = "/usr/lib/libgmalloc.dylib" if $guardMalloc; diff --git a/Tools/Scripts/update-webkit-chromium b/Tools/Scripts/update-webkit-chromium index 5610487..b3f0ae3 100755 --- a/Tools/Scripts/update-webkit-chromium +++ b/Tools/Scripts/update-webkit-chromium @@ -65,4 +65,5 @@ GetOptions( print "Updating chromium port dependencies using gclient...\n"; my @gclientArgs = ($gclientPath, "sync"); push @gclientArgs, "--force" if $force; +push @gclientArgs, "--delete_unversioned_trees" if $force; system(@gclientArgs) == 0 or die $!; diff --git a/Tools/Scripts/update-webkit-localizable-strings b/Tools/Scripts/update-webkit-localizable-strings index 20e39e9..4baa8d6 100755 --- a/Tools/Scripts/update-webkit-localizable-strings +++ b/Tools/Scripts/update-webkit-localizable-strings @@ -34,9 +34,9 @@ use FindBin; use lib $FindBin::Bin; use webkitdirs; -my @directoriesToScan = ("WebKit/mac", "WebKit/win", "-Source/WebCore/icu", "-WebKit/mac/icu"); -my $fileToUpdate = "WebKit/English.lproj/Localizable.strings"; -my $exceptionsFile = "WebKit/StringsNotToBeLocalized.txt"; +my @directoriesToScan = ("Source/WebKit/mac", "Source/WebKit/win", "-Source/WebCore/icu", "-Source/WebKit/mac/icu"); +my $fileToUpdate = "Source/WebKit/English.lproj/Localizable.strings"; +my $exceptionsFile = "Source/WebKit/StringsNotToBeLocalized.txt"; @ARGV == 0 or die "Usage: " . basename($0) . "\n"; diff --git a/Tools/Scripts/webkitpy/common/config/committers.py b/Tools/Scripts/webkitpy/common/config/committers.py index 6a235f5..f7d59fe 100644 --- a/Tools/Scripts/webkitpy/common/config/committers.py +++ b/Tools/Scripts/webkitpy/common/config/committers.py @@ -150,7 +150,7 @@ committers_unable_to_review = [ Committer("Krzysztof Kowalczyk", "kkowalczyk@gmail.com"), Committer("Kwang Yul Seo", ["kwangyul.seo@gmail.com", "skyul@company100.net", "kseo@webkit.org"], "kwangseo"), Committer("Leandro Pereira", ["leandro@profusion.mobi", "leandro@webkit.org"], "acidx"), - Committer("Levi Weintraub", "lweintraub@apple.com"), + Committer("Levi Weintraub", ["leviw@chromium.org", "leviw@google.com", "lweintraub@apple.com"], "leviw"), Committer("Lucas De Marchi", ["lucas.demarchi@profusion.mobi", "demarchi@webkit.org"], "demarchi"), Committer("Luiz Agostini", ["luiz@webkit.org", "luiz.agostini@openbossa.org"], "lca"), Committer("Mads Ager", "ager@chromium.org"), @@ -198,6 +198,7 @@ committers_unable_to_review = [ Committer("Yaar Schnitman", ["yaar@chromium.org", "yaar@google.com"]), Committer("Yong Li", ["yong.li.webkit@gmail.com", "yong.li@torchmobile.com"], "yong"), Committer("Yongjun Zhang", "yongjun.zhang@nokia.com"), + Committer("Yi Shen", ["yi.4.shen@nokia.com", "shenyi2006@gmail.com"]), Committer("Yuta Kitamura", "yutak@chromium.org", "yutak"), Committer("Yuzo Fujishima", "yuzo@google.com", "yuzo"), Committer("Zhenyao Mo", "zmo@google.com", "zhenyao"), diff --git a/Tools/Scripts/webkitpy/common/host.py b/Tools/Scripts/webkitpy/common/host.py new file mode 100644 index 0000000..8ec271e --- /dev/null +++ b/Tools/Scripts/webkitpy/common/host.py @@ -0,0 +1,80 @@ +# Copyright (c) 2010 Google Inc. All rights reserved. +# Copyright (c) 2009 Apple 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. + + +from webkitpy.common.checkout.api import Checkout +from webkitpy.common.checkout.scm import default_scm +from webkitpy.common.config.ports import WebKitPort +from webkitpy.common.net import bugzilla, buildbot, irc, statusserver +from webkitpy.common.system import executive, filesystem, platforminfo, user, workspace +from webkitpy.layout_tests import port + + +class Host(object): + def __init__(self): + self.bugs = bugzilla.Bugzilla() + self.buildbot = buildbot.BuildBot() + self.executive = executive.Executive() + self._irc = None + self.filesystem = filesystem.FileSystem() + self.workspace = workspace.Workspace(self.filesystem, self.executive) + self._port = None + self.user = user.User() + self._scm = None + self._checkout = None + self.status_server = statusserver.StatusServer() + self.port_factory = port.factory + self.platform = platforminfo.PlatformInfo() + + def _initialize_scm(self, patch_directories=None): + self._scm = default_scm(patch_directories) + self._checkout = Checkout(self.scm()) + + def scm(self): + return self._scm + + def checkout(self): + return self._checkout + + def port(self): + return self._port + + def ensure_irc_connected(self, irc_delegate): + if not self._irc: + self._irc = irc.ircproxy.IRCProxy(irc_delegate) + + def irc(self): + # We don't automatically construct IRCProxy here because constructing + # IRCProxy actually connects to IRC. We want clients to explicitly + # connect to IRC. + return self._irc + + def command_completed(self): + if self._irc: + self._irc.disconnect() diff --git a/Tools/Scripts/webkitpy/common/system/executive_mock.py b/Tools/Scripts/webkitpy/common/system/executive_mock.py index c1cf999..943b70c 100644 --- a/Tools/Scripts/webkitpy/common/system/executive_mock.py +++ b/Tools/Scripts/webkitpy/common/system/executive_mock.py @@ -30,6 +30,8 @@ # FIXME: Unify with tool/mocktool.MockExecutive. +from webkitpy.common.system import executive + class MockExecutive2(object): def __init__(self, output='', exit_code=0, exception=None, @@ -48,7 +50,7 @@ class MockExecutive2(object): def kill_process(self, pid): pass - def run_command(self, arg_list, return_exit_code=False, + def run_command(self, arg_list, error_handler=None, return_exit_code=False, decode_output=False): if self._exception: raise self._exception @@ -56,4 +58,10 @@ class MockExecutive2(object): return self._exit_code if self._run_command_fn: return self._run_command_fn(arg_list) + if self._exit_code and error_handler: + script_error = executive.ScriptError(script_args=arg_list, + exit_code=self._exit_code, + output=self._output) + error_handler(script_error) + return self._output diff --git a/Tools/Scripts/webkitpy/common/system/filesystem.py b/Tools/Scripts/webkitpy/common/system/filesystem.py index 527b6bd..05513a9 100644 --- a/Tools/Scripts/webkitpy/common/system/filesystem.py +++ b/Tools/Scripts/webkitpy/common/system/filesystem.py @@ -33,6 +33,7 @@ from __future__ import with_statement import codecs import errno import exceptions +import glob import os import shutil import tempfile @@ -43,11 +44,71 @@ class FileSystem(object): Unless otherwise noted, all paths are allowed to be either absolute or relative.""" + def __init__(self): + self.sep = os.sep + + def abspath(self, path): + return os.path.abspath(path) + + def basename(self, path): + """Wraps os.path.basename().""" + return os.path.basename(path) + + def copyfile(self, source, destination): + """Copies the contents of the file at the given path to the destination + path.""" + shutil.copyfile(source, destination) + + def dirname(self, path): + """Wraps os.path.dirname().""" + return os.path.dirname(path) def exists(self, path): """Return whether the path exists in the filesystem.""" return os.path.exists(path) + def files_under(self, path, dirs_to_skip=[], file_filter=None): + """Return the list of all files under the given path in topdown order. + + Args: + dirs_to_skip: a list of directories to skip over during the + traversal (e.g., .svn, resources, etc.) + file_filter: if not None, the filter will be invoked + with the filesystem object and the dirname and basename of + each file found. The file is included in the result if the + callback returns True. + """ + def filter_all(fs, dirpath, basename): + return True + + file_filter = file_filter or filter_all + files = [] + if self.isfile(path): + if file_filter(self, self.dirname(path), self.basename(path)): + files.append(path) + return files + + if self.basename(path) in dirs_to_skip: + return [] + + for (dirpath, dirnames, filenames) in os.walk(path): + for d in dirs_to_skip: + if d in dirnames: + dirnames.remove(d) + + for filename in filenames: + if file_filter(self, dirpath, filename): + files.append(self.join(dirpath, filename)) + return files + + def glob(self, path): + """Wraps glob.glob().""" + return glob.glob(path) + + def isabs(self, path): + """Return whether the path is an absolute path.""" + return os.path.isabs(path) + def isfile(self, path): """Return whether the path refers to a file.""" return os.path.isfile(path) @@ -71,14 +132,20 @@ class FileSystem(object): the directory will self-delete at the end of the block (if the directory is empty; non-empty directories raise errors). The directory can be safely deleted inside the block as well, if so - desired.""" + desired. + + Note that the object returned is not a string and does not support all of the string + methods. If you need a string, coerce the object to a string and go from there. + """ class TemporaryDirectory(object): def __init__(self, **kwargs): self._kwargs = kwargs - self._directory_path = None + self._directory_path = tempfile.mkdtemp(**self._kwargs) + + def __str__(self): + return self._directory_path def __enter__(self): - self._directory_path = tempfile.mkdtemp(**self._kwargs) return self._directory_path def __exit__(self, type, value, traceback): @@ -98,6 +165,41 @@ class FileSystem(object): if e.errno != errno.EEXIST: raise + def move(self, src, dest): + shutil.move(src, dest) + + def mtime(self, path): + return os.stat(path).st_mtime + + def normpath(self, path): + """Wraps os.path.normpath().""" + return os.path.normpath(path) + + def open_binary_tempfile(self, suffix): + """Create, open, and return a binary temp file. Returns a tuple of the file and the name.""" + temp_fd, temp_name = tempfile.mkstemp(suffix) + f = os.fdopen(temp_fd, 'wb') + return f, temp_name + + def open_text_file_for_writing(self, path, append=False): + """Returns a file handle suitable for writing to.""" + mode = 'w' + if append: + mode = 'a' + return codecs.open(path, mode, 'utf8') + + def read_binary_file(self, path): + """Return the contents of the file at the given path as a byte string.""" + with file(path, 'rb') as f: + return f.read() + + def read_text_file(self, path): + """Return the contents of the file at the given path as a Unicode string. + + The file is read assuming it is a UTF-8 encoded file with no BOM.""" + with codecs.open(path, 'r', 'utf8') as f: + return f.read() + class _WindowsError(exceptions.OSError): """Fake exception for Linux and Mac.""" pass @@ -124,8 +226,9 @@ class FileSystem(object): if retry_timeout_sec < 0: raise e - def remove_tree(self, path, ignore_errors=False): - shutil.rmtree(path, ignore_errors) + def rmtree(self, path): + """Delete the directory rooted at path, empty or no.""" + shutil.rmtree(path, ignore_errors=True) def read_binary_file(self, path): """Return the contents of the file at the given path as a byte string.""" @@ -139,6 +242,10 @@ class FileSystem(object): with codecs.open(path, 'r', 'utf8') as f: return f.read() + def splitext(self, path): + """Return (dirname + os.sep + basename, '.' + ext)""" + return os.path.splitext(path) + def write_binary_file(self, path, contents): """Write the contents to the file at the given location.""" with file(path, 'wb') as f: @@ -150,14 +257,3 @@ class FileSystem(object): The file is written encoded as UTF-8 with no BOM.""" with codecs.open(path, 'w', 'utf8') as f: f.write(contents) - - def copyfile(self, source, destination): - """Copies the contents of the file at the given path to the destination - path.""" - shutil.copyfile(source, destination) - - def files_under(self, path): - """Return the list of all files under the given path.""" - return [self.join(path_to_file, filename) - for (path_to_file, _, filenames) in os.walk(path) - for filename in filenames] diff --git a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py index 809c4c6..0004944 100644 --- a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py +++ b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py @@ -43,10 +43,82 @@ class MockFileSystem(object): not exist. """ self.files = files or {} + self.written_files = {} + self.sep = '/' + self.current_tmpno = 0 + + def _raise_not_found(self, path): + raise IOError(errno.ENOENT, path, os.strerror(errno.ENOENT)) + + def _split(self, path): + idx = path.rfind('/') + return (path[0:idx], path[idx + 1:]) + + def abspath(self, path): + return path + + def basename(self, path): + return self._split(path)[1] + + def copyfile(self, source, destination): + if not self.exists(source): + self._raise_not_found(source) + if self.isdir(source): + raise IOError(errno.EISDIR, source, os.strerror(errno.ISDIR)) + if self.isdir(destination): + raise IOError(errno.EISDIR, destination, os.strerror(errno.ISDIR)) + + self.files[destination] = self.files[source] + + def dirname(self, path): + return self._split(path)[0] def exists(self, path): return self.isfile(path) or self.isdir(path) + def files_under(self, path, dirs_to_skip=[], file_filter=None): + def filter_all(fs, dirpath, basename): + return True + + file_filter = file_filter or filter_all + files = [] + if self.isfile(path): + if file_filter(self, self.dirname(path), self.basename(path)): + files.append(path) + return files + + if self.basename(path) in dirs_to_skip: + return [] + + if not path.endswith('/'): + path += '/' + + dir_substrings = ['/' + d + '/' for d in dirs_to_skip] + for filename in self.files: + if not filename.startswith(path): + continue + + suffix = filename[len(path) - 1:] + if any(dir_substring in suffix for dir_substring in dir_substrings): + continue + + dirpath, basename = self._split(filename) + if file_filter(self, dirpath, basename): + files.append(filename) + + return files + + def glob(self, path): + # FIXME: This only handles a wildcard '*' at the end of the path. + # Maybe it should handle more? + if path[-1] == '*': + return [f for f in self.files if f.startswith(path[:-1])] + else: + return [f for f in self.files if f == path] + + def isabs(self, path): + return path.startswith('/') + def isfile(self, path): return path in self.files and self.files[path] is not None @@ -55,7 +127,12 @@ class MockFileSystem(object): return False if not path.endswith('/'): path += '/' - return any(f.startswith(path) for f in self.files) + + # We need to use a copy of the keys here in order to avoid switching + # to a different thread and potentially modifying the dict in + # mid-iteration. + files = self.files.keys()[:] + return any(f.startswith(path) for f in files) def join(self, *comps): return re.sub(re.escape(os.path.sep), '/', os.path.join(*comps)) @@ -80,42 +157,114 @@ class MockFileSystem(object): files.append(remaining) return dirs + files + def mtime(self, path): + if self.exists(path): + return 0 + self._raise_not_found(path) + + def _mktemp(self, suffix='', prefix='tmp', dir=None, **kwargs): + if dir is None: + dir = '/__im_tmp' + curno = self.current_tmpno + self.current_tmpno += 1 + return self.join(dir, "%s_%u_%s" % (prefix, curno, suffix)) + + def mkdtemp(self, **kwargs): + class TemporaryDirectory(object): + def __init__(self, fs, **kwargs): + self._kwargs = kwargs + self._filesystem = fs + self._directory_path = fs._mktemp(**kwargs) + fs.maybe_make_directory(self._directory_path) + + def __str__(self): + return self._directory_path + + def __enter__(self): + return self._directory_path + + def __exit__(self, type, value, traceback): + # Only self-delete if necessary. + + # FIXME: Should we delete non-empty directories? + if self._filesystem.exists(self._directory_path): + self._filesystem.rmtree(self._directory_path) + + return TemporaryDirectory(fs=self, **kwargs) + def maybe_make_directory(self, *path): # FIXME: Implement such that subsequent calls to isdir() work? pass + def move(self, src, dst): + if self.files[src] is None: + self._raise_not_found(src) + self.files[dst] = self.files[src] + self.files[src] = None + + def normpath(self, path): + return path + + def open_binary_tempfile(self, suffix): + path = self._mktemp(suffix) + return WritableFileObject(self, path), path + + def open_text_file_for_writing(self, path, append=False): + return WritableFileObject(self, path, append) + def read_text_file(self, path): return self.read_binary_file(path) def read_binary_file(self, path): - if path in self.files: - if self.files[path] is None: - raise IOError(errno.ENOENT, path, os.strerror(errno.ENOENT)) - return self.files[path] + # Intentionally raises KeyError if we don't recognize the path. + if self.files[path] is None: + self._raise_not_found(path) + return self.files[path] + + def remove(self, path): + if self.files[path] is None: + self._raise_not_found(path) + self.files[path] = None + + def rmtree(self, path): + if not path.endswith('/'): + path += '/' + + for f in self.files: + if f.startswith(path): + self.files[f] = None + + def splitext(self, path): + idx = path.rfind('.') + if idx == -1: + idx = 0 + return (path[0:idx], path[idx:]) def write_text_file(self, path, contents): return self.write_binary_file(path, contents) def write_binary_file(self, path, contents): self.files[path] = contents + self.written_files[path] = contents - def copyfile(self, source, destination): - if not self.exists(source): - raise IOError(errno.ENOENT, source, os.strerror(errno.ENOENT)) - if self.isdir(source): - raise IOError(errno.EISDIR, source, os.strerror(errno.ISDIR)) - if self.isdir(destination): - raise IOError(errno.EISDIR, destination, os.strerror(errno.ISDIR)) - self.files[destination] = self.files[source] +class WritableFileObject(object): + def __init__(self, fs, path, append=False, encoding=None): + self.fs = fs + self.path = path + self.closed = False + if path not in self.fs.files or not append: + self.fs.files[path] = "" - def files_under(self, path): - if not path.endswith('/'): - path += '/' - return [file for file in self.files if file.startswith(path)] + def __enter__(self): + return self - def remove(self, path): - del self.files[path] + def __exit__(self, type, value, traceback): + self.close() + + def close(self): + self.closed = True - def remove_tree(self, path, ignore_errors=False): - self.files = [file for file in self.files if not file.startswith(path)] + def write(self, str): + self.fs.files[self.path] += str + self.fs.written_files[self.path] = self.fs.files[self.path] diff --git a/Tools/Scripts/webkitpy/common/system/workspace.py b/Tools/Scripts/webkitpy/common/system/workspace.py index 3b755ad..afb0009 100644 --- a/Tools/Scripts/webkitpy/common/system/workspace.py +++ b/Tools/Scripts/webkitpy/common/system/workspace.py @@ -36,7 +36,7 @@ class Workspace(object): self._filesystem = filesystem self._executive = executive # FIXME: Remove if create_zip is moved to python. - def find_unused_filename(self, directory, name, extension, search_limit=10): + def find_unused_filename(self, directory, name, extension, search_limit=100): for count in range(search_limit): if count: target_name = "%s-%s.%s" % (name, count, extension) diff --git a/Tools/Scripts/webkitpy/common/system/workspace_unittest.py b/Tools/Scripts/webkitpy/common/system/workspace_unittest.py index e5fbb26..6be7664 100644 --- a/Tools/Scripts/webkitpy/common/system/workspace_unittest.py +++ b/Tools/Scripts/webkitpy/common/system/workspace_unittest.py @@ -40,10 +40,13 @@ class WorkspaceTest(unittest.TestCase): filesystem = MockFileSystem({ "dir/foo.jpg": "", "dir/foo-1.jpg": "", + "dir/foo-2.jpg": "", }) workspace = Workspace(filesystem, None) self.assertEqual(workspace.find_unused_filename("bar", "bar", "bar"), "bar/bar.bar") - self.assertEqual(workspace.find_unused_filename("dir", "foo", "jpg"), "dir/foo-2.jpg") + self.assertEqual(workspace.find_unused_filename("dir", "foo", "jpg", search_limit=1), None) + self.assertEqual(workspace.find_unused_filename("dir", "foo", "jpg", search_limit=2), None) + self.assertEqual(workspace.find_unused_filename("dir", "foo", "jpg"), "dir/foo-3.jpg") def test_create_zip(self): workspace = Workspace(None, MockExecutive(should_log=True)) diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py index 2bb2d02..050eefa 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py @@ -36,9 +36,6 @@ the output. When there are no more URLs to process in the shared queue, the thread exits. """ -from __future__ import with_statement - -import codecs import copy import logging import os @@ -86,6 +83,7 @@ def _process_output(port, options, test_input, test_types, test_args, Returns: a TestResult object """ failures = [] + fs = port._filesystem if test_output.crash: failures.append(test_failures.FailureCrash()) @@ -96,11 +94,10 @@ def _process_output(port, options, test_input, test_types, test_args, if test_output.crash: _log.debug("%s Stacktrace for %s:\n%s" % (worker_name, test_name, test_output.error)) - filename = os.path.join(options.results_directory, test_name) - filename = os.path.splitext(filename)[0] + "-stack.txt" - port.maybe_make_directory(os.path.split(filename)[0]) - with codecs.open(filename, "wb", "utf-8") as file: - file.write(test_output.error) + filename = fs.join(options.results_directory, test_name) + filename = fs.splitext(filename)[0] + "-stack.txt" + fs.maybe_make_directory(fs.dirname(filename)) + fs.write_text_file(filename, test_output.error) elif test_output.error: _log.debug("%s %s output stderr lines:\n%s" % (worker_name, test_name, test_output.error)) @@ -385,10 +382,9 @@ class TestShellThread(WatchableThread): # Append tests we're running to the existing tests_run.txt file. # This is created in run_webkit_tests.py:_PrepareListsAndPrintOutput. - tests_run_filename = os.path.join(self._options.results_directory, + tests_run_filename = self._port._filesystem.join(self._options.results_directory, "tests_run.txt") - tests_run_file = codecs.open(tests_run_filename, "a", "utf-8") - + tests_run_file = self._port._filesystem.open_text_file_for_writing(tests_run_filename, append=False) while True: if self._canceled: _log.debug('Testing cancelled') diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py index b054c5b..3267fb7 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py @@ -27,7 +27,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import logging -import os from webkitpy.layout_tests.layout_package import json_results_generator from webkitpy.layout_tests.layout_package import test_expectations @@ -66,12 +65,11 @@ class JSONLayoutResultsGenerator(json_results_generator.JSONResultsGeneratorBase results. """ super(JSONLayoutResultsGenerator, self).__init__( - builder_name, build_name, build_number, results_file_base_path, + port, builder_name, build_name, build_number, results_file_base_path, builder_base_url, {}, port.test_repository_paths(), generate_incremental_results, test_results_server, test_type, master_name) - self._port = port self._expectations = expectations # We want relative paths to LayoutTest root for JSON output. @@ -181,9 +179,9 @@ class JSONLayoutResultsGenerator(json_results_generator.JSONResultsGeneratorBase test, test_name, tests) # Remove tests that don't exist anymore. - full_path = os.path.join(self._port.layout_tests_dir(), test_name) - full_path = os.path.normpath(full_path) - if not os.path.exists(full_path): + full_path = self._fs.join(self._port.layout_tests_dir(), test_name) + full_path = self._fs.normpath(full_path) + if not self._fs.exists(full_path): del tests[test_name] def _get_failure_summary_entry(self, timeline): diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py index 12e65b2..32ffd71 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py @@ -26,11 +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. -from __future__ import with_statement - -import codecs import logging -import os import subprocess import sys import time @@ -118,7 +114,7 @@ class JSONResultsGeneratorBase(object): URL_FOR_TEST_LIST_JSON = \ "http://%s/testfile?builder=%s&name=%s&testlistjson=1&testtype=%s" - def __init__(self, builder_name, build_name, build_number, + def __init__(self, port, builder_name, build_name, build_number, results_file_base_path, builder_base_url, test_results_map, svn_repositories=None, generate_incremental_results=False, @@ -129,6 +125,7 @@ class JSONResultsGeneratorBase(object): if it is not found locally. Args + port: port-specific wrapper builder_name: the builder name (e.g. Webkit). build_name: the build name (e.g. webkit-rel). build_number: the build number. @@ -146,14 +143,16 @@ class JSONResultsGeneratorBase(object): test_type: test type string (e.g. 'layout-tests'). master_name: the name of the buildbot master. """ + self._port = port + self._fs = port._filesystem self._builder_name = builder_name self._build_name = build_name self._build_number = build_number self._builder_base_url = builder_base_url self._results_directory = results_file_base_path - self._results_file_path = os.path.join(results_file_base_path, + self._results_file_path = self._fs.join(results_file_base_path, self.RESULTS_FILENAME) - self._incremental_results_file_path = os.path.join( + self._incremental_results_file_path = self._fs.join( results_file_base_path, self.INCREMENTAL_RESULTS_FILENAME) self._test_results_map = test_results_map @@ -254,7 +253,7 @@ class JSONResultsGeneratorBase(object): ("testtype", self._test_type), ("master", self._master_name)] - files = [(file, os.path.join(self._results_directory, file)) + files = [(file, self._fs.join(self._results_directory, file)) for file in json_files] uploader = test_results_uploader.TestResultsUploader( @@ -273,10 +272,7 @@ class JSONResultsGeneratorBase(object): # Specify separators in order to get compact encoding. json_data = simplejson.dumps(json, separators=(',', ':')) json_string = self.JSON_PREFIX + json_data + self.JSON_SUFFIX - - results_file = codecs.open(file_path, "w", "utf-8") - results_file.write(json_string) - results_file.close() + self._fs.write_text_file(file_path, json_string) def _get_test_timing(self, test_name): """Returns test timing data (elapsed time) in second @@ -330,7 +326,7 @@ class JSONResultsGeneratorBase(object): Args: in_directory: The directory where svn is to be run. """ - if os.path.exists(os.path.join(in_directory, '.svn')): + if self._fs.exists(self._fs.join(in_directory, '.svn')): # Note: Not thread safe: http://bugs.python.org/issue2320 output = subprocess.Popen(["svn", "info", "--xml"], cwd=in_directory, @@ -358,9 +354,8 @@ class JSONResultsGeneratorBase(object): old_results = None error = None - if os.path.exists(self._results_file_path) and not for_incremental: - with codecs.open(self._results_file_path, "r", "utf-8") as file: - old_results = file.read() + if self._fs.exists(self._results_file_path) and not for_incremental: + old_results = self._fs.read_text_file(self._results_file_path) elif self._builder_base_url or for_incremental: if for_incremental: if not self._test_results_server: diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py index dad549a..ce99765 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py @@ -31,11 +31,11 @@ import unittest import optparse import random -import shutil -import tempfile +from webkitpy.common.system import filesystem_mock from webkitpy.layout_tests.layout_package import json_results_generator from webkitpy.layout_tests.layout_package import test_expectations +from webkitpy.thirdparty.mock import Mock class JSONGeneratorTest(unittest.TestCase): @@ -83,7 +83,9 @@ class JSONGeneratorTest(unittest.TestCase): failed=(test in failed_tests), elapsed_time=test_timings[test]) - generator = json_results_generator.JSONResultsGeneratorBase( + port = Mock() + port._filesystem = filesystem_mock.MockFileSystem() + generator = json_results_generator.JSONResultsGeneratorBase(port, self.builder_name, self.build_name, self.build_number, '', None, # don't fetch past json results archive diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py index e0ca8db..481c617 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py @@ -144,6 +144,13 @@ class MultiThreadedBroker(WorkerMessageBroker): some_thread_is_alive = False t = time.time() for thread in threads: + if thread.isAlive(): + some_thread_is_alive = True + next_timeout = thread.next_timeout() + if next_timeout and t > next_timeout: + log_wedged_worker(thread.getName(), thread.id()) + thread.clear_next_timeout() + exception_info = thread.exception_info() if exception_info is not None: # Re-raise the thread's exception here to make it @@ -152,13 +159,6 @@ class MultiThreadedBroker(WorkerMessageBroker): # to have passed. raise exception_info[0], exception_info[1], exception_info[2] - if thread.isAlive(): - some_thread_is_alive = True - next_timeout = thread.next_timeout() - if next_timeout and t > next_timeout: - log_wedged_worker(thread.getName(), thread.id()) - thread.clear_next_timeout() - self._test_runner.update() if some_thread_is_alive: diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py index 7a6aad1..e10ad99 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py @@ -31,8 +31,6 @@ import logging import optparse -import os -import pdb from webkitpy.layout_tests.layout_package import metered_stream from webkitpy.layout_tests.layout_package import test_expectations @@ -411,7 +409,7 @@ class Printer(object): return next_test = test_list[self._current_test_number] - next_dir = os.path.dirname( + next_dir = self._port._filesystem.dirname( self._port.relative_test_filename(next_test)) if self._current_progress_str == "": self._current_progress_str = "%s: " % (next_dir) @@ -437,7 +435,7 @@ class Printer(object): break next_test = test_list[self._current_test_number] - next_dir = os.path.dirname( + next_dir = self._port._filesystem.dirname( self._port.relative_test_filename(next_test)) if result_summary.remaining: diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py index 9280b02..12a786e 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py @@ -29,10 +29,7 @@ """Unit tests for printing.py.""" -import os import optparse -import pdb -import sys import unittest import logging @@ -117,6 +114,7 @@ class TestUtilityFunctions(unittest.TestCase): class Testprinter(unittest.TestCase): def get_printer(self, args=None, single_threaded=False, is_fully_parallel=False): + args = args or [] printing_options = printing.print_options() option_parser = optparse.OptionParser(option_list=printing_options) options, args = option_parser.parse_args(args) @@ -138,11 +136,11 @@ class Testprinter(unittest.TestCase): failures = [test_failures.FailureTimeout()] elif result_type == test_expectations.CRASH: failures = [test_failures.FailureCrash()] - path = os.path.join(self._port.layout_tests_dir(), test) + path = self._port._filesystem.join(self._port.layout_tests_dir(), test) return test_results.TestResult(path, failures=failures, test_run_time=run_time) def get_result_summary(self, tests, expectations_str): - test_paths = [os.path.join(self._port.layout_tests_dir(), test) for + test_paths = [self._port._filesystem.join(self._port.layout_tests_dir(), test) for test in tests] expectations = test_expectations.TestExpectations( self._port, test_paths, expectations_str, diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py index 8645fc1..806b663 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py @@ -32,9 +32,7 @@ for layout tests. """ import logging -import os import re -import sys import webkitpy.thirdparty.simplejson as simplejson @@ -322,6 +320,7 @@ class TestExpectationsFile: """ self._port = port + self._fs = port._filesystem self._expectations = expectations self._full_test_list = full_test_list self._test_platform_name = test_platform_name @@ -690,9 +689,9 @@ class TestExpectationsFile: 'indefinitely, then it should be just timeout.', test_list_path) - full_path = os.path.join(self._port.layout_tests_dir(), - test_list_path) - full_path = os.path.normpath(full_path) + full_path = self._fs.join(self._port.layout_tests_dir(), + test_list_path) + full_path = self._fs.normpath(full_path) # WebKit's way of skipping tests is to add a -disabled suffix. # So we should consider the path existing if the path or the # -disabled version exists. @@ -736,11 +735,11 @@ class TestExpectationsFile: # lists to represent the tree of tests, leaves being test # files and nodes being categories. - path = os.path.join(self._port.layout_tests_dir(), test_list_path) - path = os.path.normpath(path) - if self._port.path_isdir(path): + path = self._fs.join(self._port.layout_tests_dir(), test_list_path) + path = self._fs.normpath(path) + if self._fs.isdir(path): # this is a test category, return all the tests of the category. - path = os.path.join(path, '') + path = self._fs.join(path, '') return [test for test in self._full_test_list if test.startswith(path)] @@ -817,7 +816,7 @@ class TestExpectationsFile: self._remove_from_sets(test, self._timeline_to_tests) self._remove_from_sets(test, self._result_type_to_tests) - self._test_list_paths[test] = os.path.normpath(test_list_path) + self._test_list_paths[test] = self._fs.normpath(test_list_path) def _remove_from_sets(self, test, dict): """Removes the given test from the sets in the dictionary. @@ -838,7 +837,7 @@ class TestExpectationsFile: return False prev_base_path = self._test_list_paths[test] - if (prev_base_path == os.path.normpath(test_list_path)): + if (prev_base_path == self._fs.normpath(test_list_path)): if (not allow_overrides or test in self._overridding_tests): if allow_overrides: expectation_source = "override" @@ -854,7 +853,7 @@ class TestExpectationsFile: return False # Check if we've already seen a more precise path. - return prev_base_path.startswith(os.path.normpath(test_list_path)) + return prev_base_path.startswith(self._fs.normpath(test_list_path)) def _add_error(self, lineno, msg, path): """Reports an error that will prevent running the tests. Does not diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py index 34771f3..8f9e5dd 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py @@ -29,8 +29,6 @@ """Unit tests for test_expectations.py.""" -import os -import sys import unittest from webkitpy.layout_tests import port @@ -82,11 +80,12 @@ class FunctionsTest(unittest.TestCase): class Base(unittest.TestCase): def __init__(self, testFunc, setUp=None, tearDown=None, description=None): self._port = port.get('test', None) + self._fs = self._port._filesystem self._exp = None unittest.TestCase.__init__(self, testFunc) def get_test(self, test_name): - return os.path.join(self._port.layout_tests_dir(), test_name) + return self._fs.join(self._port.layout_tests_dir(), test_name) def get_basic_tests(self): return [self.get_test('failures/expected/text.html'), diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py index 2b8190b..eb59d36 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py @@ -29,7 +29,6 @@ """Classes for failures that occur during tests.""" -import os import test_expectations import cPickle @@ -121,7 +120,10 @@ class TestFailure(object): Return: The relative windows path to the output filename """ - return os.path.splitext(filename)[0] + modifier + # FIXME: technically this breaks if files don't use ".ext" to indicate + # the extension, but passing in a Filesystem object here is a huge + # hassle. + return filename[:filename.rfind('.')] + modifier class FailureWithType(TestFailure): diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py index b2698d1..c5aa2d6 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py @@ -89,6 +89,12 @@ class Test(unittest.TestCase): crash_set = set([FailureCrash(), "FailureCrash"]) self.assertEqual(len(crash_set), 2) + def test_relative_output_filename(self): + # This could be any Failure* object, since we're testing a method + # on the base class. + failure_obj = FailureTextMismatch() + actual_filename = failure_obj.relative_output_filename("fast/html/article-element.html", "-actual.txt") + self.assertEquals(actual_filename, "fast/html/article-element-actual.txt") if __name__ == '__main__': unittest.main() diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py index 5b02a00..6c07850 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py @@ -37,14 +37,11 @@ create a final report. from __future__ import with_statement -import codecs import errno import logging import math -import os import Queue import random -import shutil import sys import time @@ -68,8 +65,6 @@ _log = logging.getLogger("webkitpy.layout_tests.run_webkit_tests") # Builder base URL where we have the archived test results. BUILDER_BASE_URL = "http://build.chromium.org/buildbot/layout_test_results/" -LAYOUT_TESTS_DIRECTORY = "LayoutTests" + os.sep - TestExpectationsFile = test_expectations.TestExpectationsFile @@ -160,8 +155,6 @@ class TestRunner: """A class for managing running a series of tests on a series of layout test files.""" - HTTP_SUBDIR = os.sep.join(['', 'http', '']) - WEBSOCKET_SUBDIR = os.sep.join(['', 'websocket', '']) # The per-test timeout in milliseconds, if no --time-out-ms option was # given to run_webkit_tests. This should correspond to the default timeout @@ -177,10 +170,16 @@ class TestRunner: printer: a Printer object to record updates to. """ self._port = port + self._fs = port._filesystem self._options = options self._printer = printer self._message_broker = None + self.HTTP_SUBDIR = self._fs.join('', 'http', '') + self.WEBSOCKET_SUBDIR = self._fs.join('', 'websocket', '') + self.LAYOUT_TESTS_DIRECTORY = "LayoutTests" + self._fs.sep + + # disable wss server. need to install pyOpenSSL on buildbots. # self._websocket_secure_server = websocket_server.PyWebSocket( # options.results_directory, use_tls=True, port=9323) @@ -199,15 +198,18 @@ class TestRunner: last_unexpected_results: list of unexpected results to retest, if any """ - paths = [self._strip_test_dir_prefix(arg) for arg in args if arg and arg != ''] + paths = self._strip_test_dir_prefixes(args) paths += last_unexpected_results if self._options.test_list: - paths += read_test_files(self._options.test_list) + paths += self._strip_test_dir_prefixes(read_test_files(self._fs, self._options.test_list)) self._test_files = self._port.tests(paths) + def _strip_test_dir_prefixes(self, paths): + return [self._strip_test_dir_prefix(path) for path in paths if path] + def _strip_test_dir_prefix(self, path): - if path.startswith(LAYOUT_TESTS_DIRECTORY): - return path[len(LAYOUT_TESTS_DIRECTORY):] + if path.startswith(self.LAYOUT_TESTS_DIRECTORY): + return path[len(self.LAYOUT_TESTS_DIRECTORY):] return path def lint(self): @@ -339,10 +341,9 @@ class TestRunner: self._printer.print_expected(extra_msg) tests_run_msg += "\n" + extra_msg files.extend(test_files[0:extra]) - tests_run_filename = os.path.join(self._options.results_directory, + tests_run_filename = self._fs.join(self._options.results_directory, "tests_run.txt") - with codecs.open(tests_run_filename, "w", "utf-8") as file: - file.write(tests_run_msg + "\n") + self._fs.write_text_file(tests_run_filename, tests_run_msg) len_skip_chunk = int(len(files) * len(skipped) / float(len(self._test_files))) @@ -390,15 +391,20 @@ class TestRunner: result_summary.add(result, expected=True) self._printer.print_expected('') + # Check to make sure we didn't filter out all of the tests. + if not len(self._test_files): + _log.info("All tests are being skipped") + return None + return result_summary def _get_dir_for_test_file(self, test_file): """Returns the highest-level directory by which to shard the given test file.""" - index = test_file.rfind(os.sep + LAYOUT_TESTS_DIRECTORY) + index = test_file.rfind(self._fs.sep + self.LAYOUT_TESTS_DIRECTORY) - test_file = test_file[index + len(LAYOUT_TESTS_DIRECTORY):] - test_file_parts = test_file.split(os.sep, 1) + test_file = test_file[index + len(self.LAYOUT_TESTS_DIRECTORY):] + test_file_parts = test_file.split(self._fs.sep, 1) directory = test_file_parts[0] test_file = test_file_parts[1] @@ -408,10 +414,10 @@ class TestRunner: # what made them stable on linux/mac. return_value = directory while ((directory != 'http' or sys.platform in ('darwin', 'linux2')) - and test_file.find(os.sep) >= 0): - test_file_parts = test_file.split(os.sep, 1) + and test_file.find(self._fs.sep) >= 0): + test_file_parts = test_file.split(self._fs.sep, 1) directory = test_file_parts[0] - return_value = os.path.join(return_value, directory) + return_value = self._fs.join(return_value, directory) test_file = test_file_parts[1] return return_value @@ -427,7 +433,7 @@ class TestRunner: def _test_requires_lock(self, test_file): """Return True if the test needs to be locked when running multiple copies of NRWTs.""" - split_path = test_file.split(os.sep) + split_path = test_file.split(self._port._filesystem.sep) return 'http' in split_path or 'websocket' in split_path def _test_is_slow(self, test_file): @@ -757,10 +763,9 @@ class TestRunner: layout_tests_dir = self._port.layout_tests_dir() possible_dirs = self._port.test_dirs() for dirname in possible_dirs: - if os.path.isdir(os.path.join(layout_tests_dir, dirname)): - shutil.rmtree(os.path.join(self._options.results_directory, - dirname), - ignore_errors=True) + if self._fs.isdir(self._fs.join(layout_tests_dir, dirname)): + self._fs.rmtree(self._fs.join(self._options.results_directory, + dirname)) def _get_failures(self, result_summary, include_crashes): """Filters a dict of results and returns only the failures. @@ -803,17 +808,17 @@ class TestRunner: """ results_directory = self._options.results_directory _log.debug("Writing JSON files in %s." % results_directory) - unexpected_json_path = os.path.join(results_directory, "unexpected_results.json") - with codecs.open(unexpected_json_path, "w", "utf-8") as file: + unexpected_json_path = self._fs.join(results_directory, "unexpected_results.json") + with self._fs.open_text_file_for_writing(unexpected_json_path) as file: simplejson.dump(unexpected_results, file, sort_keys=True, indent=2) # Write a json file of the test_expectations.txt file for the layout # tests dashboard. - expectations_path = os.path.join(results_directory, "expectations.json") + expectations_path = self._fs.join(results_directory, "expectations.json") expectations_json = \ self._expectations.get_expectations_json_for_all_platforms() - with codecs.open(expectations_path, "w", "utf-8") as file: - file.write(u"ADD_EXPECTATIONS(%s);" % expectations_json) + self._fs.write_text_file(expectations_path, + u"ADD_EXPECTATIONS(%s);" % expectations_json) generator = json_layout_results_generator.JSONLayoutResultsGenerator( self._port, self._options.builder_name, self._options.build_name, @@ -1184,9 +1189,9 @@ class TestRunner: if not len(test_files): return False - out_filename = os.path.join(self._options.results_directory, - "results.html") - with codecs.open(out_filename, "w", "utf-8") as results_file: + out_filename = self._fs.join(self._options.results_directory, + "results.html") + with self._fs.open_text_file_for_writing(out_filename) as results_file: html = self._results_html(test_files, result_summary.failures, results_title) results_file.write(html) @@ -1194,21 +1199,20 @@ class TestRunner: def _show_results_html_file(self): """Shows the results.html page.""" - results_filename = os.path.join(self._options.results_directory, - "results.html") + results_filename = self._fs.join(self._options.results_directory, + "results.html") self._port.show_results_html_file(results_filename) -def read_test_files(files): +def read_test_files(fs, files): tests = [] for file in files: try: - with codecs.open(file, 'r', 'utf-8') as file_contents: - # FIXME: This could be cleaner using a list comprehension. - for line in file_contents: - line = test_expectations.strip_comments(line) - if line: - tests.append(line) + file_contents = fs.read_text_file(file).split('\n') + for line in file_contents: + line = test_expectations.strip_comments(line) + if line: + tests.append(line) except IOError, e: if e.errno == errno.ENOENT: _log.critical('') diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py index 3c564ae..97f8630 100644 --- a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py @@ -32,6 +32,7 @@ import unittest +from webkitpy.common.system import filesystem_mock from webkitpy.thirdparty.mock import Mock import test_runner @@ -45,6 +46,7 @@ class TestRunnerWrapper(test_runner.TestRunner): class TestRunnerTest(unittest.TestCase): def test_results_html(self): mock_port = Mock() + mock_port._filesystem = filesystem_mock.MockFileSystem() mock_port.relative_test_filename = lambda name: name mock_port.filename_to_uri = lambda name: name @@ -66,7 +68,9 @@ class TestRunnerTest(unittest.TestCase): def test_shard_tests(self): # Test that _shard_tests in test_runner.TestRunner really # put the http tests first in the queue. - runner = TestRunnerWrapper(port=Mock(), options=Mock(), + port = Mock() + port._filesystem = filesystem_mock.MockFileSystem() + runner = TestRunnerWrapper(port=port, options=Mock(), printer=Mock()) test_list = [ diff --git a/Tools/Scripts/webkitpy/layout_tests/port/__init__.py b/Tools/Scripts/webkitpy/layout_tests/port/__init__.py index e3ad6f4..59ab2ef 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/__init__.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/__init__.py @@ -30,3 +30,5 @@ """Port-specific entrypoints for the layout tests test infrastructure.""" from factory import get + +from test import unit_test_filesystem diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base.py b/Tools/Scripts/webkitpy/layout_tests/port/base.py index 97b54c9..6e5fabc 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/base.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/base.py @@ -117,7 +117,10 @@ class Port(object): self._pretty_patch_path = self.path_from_webkit_base("Websites", "bugs.webkit.org", "PrettyPatch", "prettify.rb") - self._pretty_patch_available = True + # If we're running on a mocked-out filesystem, this file almost + # certainly won't be available, so it's a good test to keep us + # from erroring out later. + self._pretty_patch_available = self._filesystem.exists(self._pretty_patch_path) self.set_option_default('configuration', None) if self._options.configuration is None: self._options.configuration = self.default_configuration() @@ -244,7 +247,7 @@ class Port(object): tree) results_filename - relative path from top of tree to the results file - (os.path.join of the two gives you the full path to the file, + (port.join() of the two gives you the full path to the file, unless None was returned.) Return values will be in the format appropriate for the current platform (e.g., "\\" for path separators on Windows). If the results @@ -255,7 +258,7 @@ class Port(object): conjunction with the other baseline and filename routines that are platform specific. """ - testname = os.path.splitext(self.relative_test_filename(filename))[0] + testname = self._filesystem.splitext(self.relative_test_filename(filename))[0] baseline_filename = testname + '-expected' + suffix @@ -360,7 +363,7 @@ class Port(object): protocol = "http" return "%s://127.0.0.1:%u/%s" % (protocol, port, relative_path) - return path.abspath_to_uri(os.path.abspath(filename)) + return path.abspath_to_uri(self._filesystem.abspath(filename)) def tests(self, paths): """Return the list of tests found (relative to layout_tests_dir().""" @@ -702,7 +705,7 @@ class Port(object): def pretty_patch_text(self, diff_path): if not self._pretty_patch_available: return self._pretty_patch_error_html - command = ("ruby", "-I", os.path.dirname(self._pretty_patch_path), + command = ("ruby", "-I", self._filesystem.dirname(self._pretty_patch_path), self._pretty_patch_path, diff_path) try: # Diffs are treated as binary (we pass decode_output=False) as they diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py index 8d586e3..72f2d05 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py @@ -27,7 +27,6 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import optparse -import os import sys import tempfile import unittest @@ -194,7 +193,7 @@ class PortTest(unittest.TestCase): def test_filename_to_uri(self): port = base.Port() layout_test_dir = port.layout_tests_dir() - test_file = os.path.join(layout_test_dir, "foo", "bar.html") + test_file = port._filesystem.join(layout_test_dir, "foo", "bar.html") # On Windows, absolute paths are of the form "c:\foo.txt". However, # all current browsers (except for Opera) normalize file URLs by diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py index 7e934a8..ad1bea6 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py @@ -29,21 +29,16 @@ """Chromium implementations of the Port interface.""" -from __future__ import with_statement - -import codecs import errno import logging -import os import re -import shutil import signal import subprocess import sys -import tempfile import time import webbrowser +from webkitpy.common.system import executive from webkitpy.common.system.path import cygpath from webkitpy.layout_tests.layout_package import test_expectations from webkitpy.layout_tests.layout_package import test_output @@ -61,26 +56,6 @@ _log = logging.getLogger("webkitpy.layout_tests.port.chromium") # FIXME: This function doesn't belong in this package. -def check_file_exists(path_to_file, file_description, override_step=None, - logging=True): - """Verify the file is present where expected or log an error. - - Args: - file_name: The (human friendly) name or description of the file - you're looking for (e.g., "HTTP Server"). Used for error logging. - override_step: An optional string to be logged if the check fails. - logging: Whether or not log the error messages.""" - if not os.path.exists(path_to_file): - if logging: - _log.error('Unable to find %s' % file_description) - _log.error(' at %s' % path_to_file) - if override_step: - _log.error(' %s' % override_step) - _log.error('') - return False - return True - - class ChromiumPort(base.Port): """Abstract base class for Chromium implementations of the Port class.""" @@ -88,6 +63,26 @@ class ChromiumPort(base.Port): base.Port.__init__(self, **kwargs) self._chromium_base_dir = None + def _check_file_exists(self, path_to_file, file_description, + override_step=None, logging=True): + """Verify the file is present where expected or log an error. + + Args: + file_name: The (human friendly) name or description of the file + you're looking for (e.g., "HTTP Server"). Used for error logging. + override_step: An optional string to be logged if the check fails. + logging: Whether or not log the error messages.""" + if not self._filesystem.exists(path_to_file): + if logging: + _log.error('Unable to find %s' % file_description) + _log.error(' at %s' % path_to_file) + if override_step: + _log.error(' %s' % override_step) + _log.error('') + return False + return True + + def baseline_path(self): return self._webkit_baseline_path(self._name) @@ -95,8 +90,8 @@ class ChromiumPort(base.Port): result = True dump_render_tree_binary_path = self._path_to_driver() - result = check_file_exists(dump_render_tree_binary_path, - 'test driver') and result + result = self._check_file_exists(dump_render_tree_binary_path, + 'test driver') and result if result and self.get_option('build'): result = self._check_driver_build_up_to_date( self.get_option('configuration')) @@ -105,8 +100,8 @@ class ChromiumPort(base.Port): helper_path = self._path_to_helper() if helper_path: - result = check_file_exists(helper_path, - 'layout test helper') and result + result = self._check_file_exists(helper_path, + 'layout test helper') and result if self.get_option('pixel_tests'): result = self.check_image_diff( @@ -120,29 +115,35 @@ class ChromiumPort(base.Port): def check_sys_deps(self, needs_http): cmd = [self._path_to_driver(), '--check-layout-test-sys-deps'] - if self._executive.run_command(cmd, return_exit_code=True): + + local_error = executive.ScriptError() + + def error_handler(script_error): + local_error.exit_code = script_error.exit_code + + output = self._executive.run_command(cmd, error_handler=error_handler) + if local_error.exit_code: _log.error('System dependencies check failed.') _log.error('To override, invoke with --nocheck-sys-deps') _log.error('') + _log.error(output) return False return True def check_image_diff(self, override_step=None, logging=True): image_diff_path = self._path_to_image_diff() - return check_file_exists(image_diff_path, 'image diff exe', - override_step, logging) + return self._check_file_exists(image_diff_path, 'image diff exe', + override_step, logging) def diff_image(self, expected_contents, actual_contents, diff_filename=None): executable = self._path_to_image_diff() - tempdir = tempfile.mkdtemp() - expected_filename = os.path.join(tempdir, "expected.png") - with open(expected_filename, 'w+b') as file: - file.write(expected_contents) - actual_filename = os.path.join(tempdir, "actual.png") - with open(actual_filename, 'w+b') as file: - file.write(actual_contents) + tempdir = self._filesystem.mkdtemp() + expected_filename = self._filesystem.join(str(tempdir), "expected.png") + self._filesystem.write_binary_file(expected_filename, expected_contents) + actual_filename = self._filesystem.join(str(tempdir), "actual.png") + self._filesystem.write_binary_file(actual_filename, actual_contents) if diff_filename: cmd = [executable, '--diff', expected_filename, @@ -171,7 +172,7 @@ class ChromiumPort(base.Port): else: raise e finally: - shutil.rmtree(tempdir, ignore_errors=True) + self._filesystem.rmtree(str(tempdir)) return result def driver_name(self): @@ -183,15 +184,15 @@ class ChromiumPort(base.Port): """Returns the full path to path made by joining the top of the Chromium source tree and the list of path components in |*comps|.""" if not self._chromium_base_dir: - abspath = os.path.abspath(__file__) + abspath = self._filesystem.abspath(__file__) offset = abspath.find('third_party') if offset == -1: - self._chromium_base_dir = os.path.join( + self._chromium_base_dir = self._filesystem.join( abspath[0:abspath.find('Tools')], 'WebKit', 'chromium') else: self._chromium_base_dir = abspath[0:offset] - return os.path.join(self._chromium_base_dir, *comps) + return self._filesystem.join(self._chromium_base_dir, *comps) def path_to_test_expectations_file(self): return self.path_from_webkit_base('LayoutTests', 'platform', @@ -209,10 +210,10 @@ class ChromiumPort(base.Port): def setup_test_run(self): # Delete the disk cache if any to ensure a clean test run. dump_render_tree_binary_path = self._path_to_driver() - cachedir = os.path.split(dump_render_tree_binary_path)[0] - cachedir = os.path.join(cachedir, "cache") - if os.path.exists(cachedir): - shutil.rmtree(cachedir) + cachedir = self._filesystem.dirname(dump_render_tree_binary_path) + cachedir = self._filesystem.join(cachedir, "cache") + if self._filesystem.exists(cachedir): + self._filesystem.rmtree(cachedir) def create_driver(self, worker_number): """Starts a new Driver and returns a handle to it.""" @@ -249,8 +250,7 @@ class ChromiumPort(base.Port): Basically this string should contain the equivalent of a test_expectations file. See test_expectations.py for more details.""" expectations_path = self.path_to_test_expectations_file() - with codecs.open(expectations_path, "r", "utf-8") as file: - return file.read() + return self._filesystem.read_text_file(expectations_path) def test_expectations_overrides(self): try: @@ -258,10 +258,9 @@ class ChromiumPort(base.Port): 'layout_tests', 'test_expectations.txt') except AssertionError: return None - if not os.path.exists(overrides_path): + if not self._filesystem.exists(overrides_path): return None - with codecs.open(overrides_path, "r", "utf-8") as file: - return file.read() + return self._filesystem.read_text_file(overrides_path) def skipped_layout_tests(self, extra_test_files=None): expectations_str = self.test_expectations() @@ -310,8 +309,8 @@ class ChromiumPort(base.Port): debug_path = self._path_to_driver('Debug') release_path = self._path_to_driver('Release') - debug_mtime = os.stat(debug_path).st_mtime - release_mtime = os.stat(release_path).st_mtime + debug_mtime = self._filesystem.mtime(debug_path) + release_mtime = self._filesystem.mtime(release_path) if (debug_mtime > release_mtime and configuration == 'Release' or release_mtime > debug_mtime and configuration == 'Debug'): @@ -354,7 +353,7 @@ class ChromiumDriver(base.Driver): self._worker_number = worker_number self._image_path = None if self._port.get_option('pixel_tests'): - self._image_path = os.path.join( + self._image_path = self._port._filesystem.join( self._port.get_option('results_directory'), 'png_result%s.png' % self._worker_number) @@ -446,9 +445,8 @@ class ChromiumDriver(base.Driver): def _output_image(self): """Returns the image output which driver generated.""" png_path = self._image_path - if png_path and os.path.isfile(png_path): - with open(png_path, 'rb') as image_file: - return image_file.read() + if png_path and self._port._filesystem.isfile(png_path): + return self._port._filesystem.read_binary_file(png_path) else: return None diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py index c1f5c8d..b88d8aa 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py @@ -24,10 +24,6 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from __future__ import with_statement - -import codecs -import os import sys import chromium_linux @@ -82,10 +78,9 @@ def _gpu_overrides(port): 'layout_tests', 'test_expectations_gpu.txt') except AssertionError: return None - if not os.path.exists(overrides_path): + if not port._filesystem.exists(overrides_path): return None - with codecs.open(overrides_path, "r", "utf-8") as file: - return file.read() + return port._filesystem.read_text_file(overrides_path) class ChromiumGpuLinuxPort(chromium_linux.ChromiumLinuxPort): diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py index ad0404c..0bfb127 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py @@ -24,7 +24,6 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import os import unittest from webkitpy.tool import mocktool diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py index 5d9dd87..c1c85f8 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py @@ -78,20 +78,24 @@ class ChromiumLinuxPort(chromium.ChromiumPort): # def _build_path(self, *comps): + if self.get_option('build_directory'): + return self._filesystem.join(self.get_option('build_directory'), + *comps) + base = self.path_from_chromium_base() - if os.path.exists(os.path.join(base, 'sconsbuild')): - return os.path.join(base, 'sconsbuild', *comps) - if os.path.exists(os.path.join(base, 'out', *comps)) or self.get_option('use_test_shell'): - return os.path.join(base, 'out', *comps) + if self._filesystem.exists(self._filesystem.join(base, 'sconsbuild')): + return self._filesystem.join(base, 'sconsbuild', *comps) + if self._filesystem.exists(self._filesystem.join(base, 'out', *comps)) or self.get_option('use_test_shell'): + return self._filesystem.join(base, 'out', *comps) base = self.path_from_webkit_base() - if os.path.exists(os.path.join(base, 'sconsbuild')): - return os.path.join(base, 'sconsbuild', *comps) - return os.path.join(base, 'out', *comps) + if self._filesystem.exists(self._filesystem.join(base, 'sconsbuild')): + return self._filesystem.join(base, 'sconsbuild', *comps) + return self._filesystem.join(base, 'out', *comps) def _check_apache_install(self): - result = chromium.check_file_exists(self._path_to_apache(), + result = self._check_file_exists(self._path_to_apache(), "apache2") - result = chromium.check_file_exists(self._path_to_apache_config_file(), + result = self._check_file_exists(self._path_to_apache_config_file(), "apache2 config file") and result if not result: _log.error(' Please install using: "sudo apt-get install ' @@ -100,11 +104,11 @@ class ChromiumLinuxPort(chromium.ChromiumPort): return result def _check_lighttpd_install(self): - result = chromium.check_file_exists( + result = self._check_file_exists( self._path_to_lighttpd(), "LigHTTPd executable") - result = chromium.check_file_exists(self._path_to_lighttpd_php(), + result = self._check_file_exists(self._path_to_lighttpd_php(), "PHP CGI executable") and result - result = chromium.check_file_exists(self._path_to_lighttpd_modules(), + result = self._check_file_exists(self._path_to_lighttpd_modules(), "LigHTTPd modules") and result if not result: _log.error(' Please install using: "sudo apt-get install ' @@ -113,7 +117,7 @@ class ChromiumLinuxPort(chromium.ChromiumPort): return result def _check_wdiff_install(self): - result = chromium.check_file_exists(self._path_to_wdiff(), 'wdiff') + result = self._check_file_exists(self._path_to_wdiff(), 'wdiff') if not result: _log.error(' Please install using: "sudo apt-get install ' 'wdiff"') @@ -133,7 +137,7 @@ class ChromiumLinuxPort(chromium.ChromiumPort): else: config_name = 'apache2-debian-httpd.conf' - return os.path.join(self.layout_tests_dir(), 'http', 'conf', + return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', config_name) def _path_to_lighttpd(self): @@ -163,7 +167,7 @@ class ChromiumLinuxPort(chromium.ChromiumPort): return '/usr/bin/wdiff' def _is_redhat_based(self): - return os.path.exists(os.path.join('/etc', 'redhat-release')) + return self._filesystem.exists(self._filesystem.join('/etc', 'redhat-release')) def _shut_down_http_server(self, server_pid): """Shut down the lighttpd web server. Blocks until it's fully diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py index f638e01..5360ab3 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py @@ -105,11 +105,15 @@ class ChromiumMacPort(chromium.ChromiumPort): # def _build_path(self, *comps): + if self.get_option('build_directory'): + return self._filesystem.join(self.get_option('build_directory'), + *comps) + path = self.path_from_chromium_base('xcodebuild', *comps) - if os.path.exists(path) or self.get_option('use_test_shell'): + if self._filesystem.exists(path) or self.get_option('use_test_shell'): return path - return self.path_from_webkit_base('WebKit', 'chromium', 'xcodebuild', - *comps) + return self.path_from_webkit_base( + 'Source', 'WebKit', 'chromium', 'xcodebuild', *comps) def _check_wdiff_install(self): try: @@ -128,8 +132,8 @@ class ChromiumMacPort(chromium.ChromiumPort): return '/usr/sbin/httpd' def _path_to_apache_config_file(self): - return os.path.join(self.layout_tests_dir(), 'http', 'conf', - 'apache2-httpd.conf') + return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', + 'apache2-httpd.conf') def _path_to_lighttpd(self): return self._lighttpd_path('bin', 'lighttpd') diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py index c87984f..6c8987b 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py @@ -26,13 +26,16 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import os import unittest import StringIO +from webkitpy.common.system import logtesting +from webkitpy.common.system import executive_mock +from webkitpy.common.system import filesystem_mock from webkitpy.tool import mocktool from webkitpy.thirdparty.mock import Mock + import chromium import chromium_linux import chromium_mac @@ -98,7 +101,8 @@ class ChromiumPortTest(unittest.TestCase): def __init__(self, options): chromium_linux.ChromiumLinuxPort.__init__(self, port_name='test-port', - options=options) + options=options, + filesystem=filesystem_mock.MockFileSystem()) def default_configuration(self): self.default_configuration_called = True @@ -126,7 +130,7 @@ class ChromiumPortTest(unittest.TestCase): mock_options = mocktool.MockOptions() port = ChromiumPortTest.TestLinuxPort(options=mock_options) - fake_test = os.path.join(port.layout_tests_dir(), "fast/js/not-good.js") + fake_test = port._filesystem.join(port.layout_tests_dir(), "fast/js/not-good.js") port.test_expectations = lambda: """BUG_TEST SKIP : fast/js/not-good.js = TEXT LINUX WIN : fast/js/very-good.js = TIMEOUT PASS""" @@ -153,35 +157,19 @@ LINUX WIN : fast/js/very-good.js = TIMEOUT PASS""" def _path_to_image_diff(self): return "/path/to/image_diff" - class MockExecute: - def __init__(self, result): - self._result = result - - def run_command(self, - args, - cwd=None, - input=None, - error_handler=None, - return_exit_code=False, - return_stderr=True, - decode_output=False): - if return_exit_code: - return self._result - return '' - mock_options = mocktool.MockOptions() port = ChromiumPortTest.TestLinuxPort(mock_options) # Images are different. - port._executive = MockExecute(0) + port._executive = executive_mock.MockExecutive2(exit_code=0) self.assertEquals(False, port.diff_image("EXPECTED", "ACTUAL")) # Images are the same. - port._executive = MockExecute(1) + port._executive = executive_mock.MockExecutive2(exit_code=1) self.assertEquals(True, port.diff_image("EXPECTED", "ACTUAL")) # There was some error running image_diff. - port._executive = MockExecute(2) + port._executive = executive_mock.MockExecutive2(exit_code=2) exception_raised = False try: port.diff_image("EXPECTED", "ACTUAL") @@ -189,5 +177,25 @@ LINUX WIN : fast/js/very-good.js = TIMEOUT PASS""" exception_raised = True self.assertFalse(exception_raised) + +class ChromiumPortLoggingTest(logtesting.LoggingTestCase): + def test_check_sys_deps(self): + mock_options = mocktool.MockOptions() + port = ChromiumPortTest.TestLinuxPort(options=mock_options) + + # Success + port._executive = executive_mock.MockExecutive2(exit_code=0) + self.assertTrue(port.check_sys_deps(needs_http=False)) + + # Failure + port._executive = executive_mock.MockExecutive2(exit_code=1, + output='testing output failure') + self.assertFalse(port.check_sys_deps(needs_http=False)) + self.assertLog([ + 'ERROR: System dependencies check failed.\n', + 'ERROR: To override, invoke with --nocheck-sys-deps\n', + 'ERROR: \n', + 'ERROR: testing output failure\n']) + if __name__ == '__main__': unittest.main() diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py index d080f82..14f2777 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py @@ -30,7 +30,6 @@ """Chromium Win implementation of the Port interface.""" import logging -import os import sys import chromium @@ -106,14 +105,17 @@ class ChromiumWinPort(chromium.ChromiumPort): # PROTECTED ROUTINES # def _build_path(self, *comps): + if self.get_option('build_directory'): + return self._filesystem.join(self.get_option('build_directory'), + *comps) + p = self.path_from_chromium_base('webkit', *comps) - if os.path.exists(p): + if self._filesystem.exists(p): return p p = self.path_from_chromium_base('chrome', *comps) - if os.path.exists(p) or self.get_option('use_test_shell'): + if self._filesystem.exists(p) or self.get_option('use_test_shell'): return p - return os.path.join(self.path_from_webkit_base(), 'WebKit', 'chromium', - *comps) + return self._filesystem.join(self.path_from_webkit_base(), 'WebKit', 'chromium', *comps) def _lighttpd_path(self, *comps): return self.path_from_chromium_base('third_party', 'lighttpd', 'win', @@ -124,8 +126,7 @@ class ChromiumWinPort(chromium.ChromiumPort): 'sbin', 'httpd') def _path_to_apache_config_file(self): - return os.path.join(self.layout_tests_dir(), 'http', 'conf', - 'cygwin-httpd.conf') + return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', 'cygwin-httpd.conf') def _path_to_lighttpd(self): return self._lighttpd_path('LightTPD.exe') diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py index 36f3c6b..d677589 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py @@ -45,13 +45,15 @@ class ChromiumWinTest(unittest.TestCase): def tearDown(self): sys.platform = self.orig_platform + self._port = None def _mock_path_from_chromium_base(self, *comps): - return os.path.join("/chromium/src", *comps) + return self._port._filesystem.join("/chromium/src", *comps) def test_setup_environ_for_server(self): port = chromium_win.ChromiumWinPort() port._executive = mocktool.MockExecutive(should_log=True) + self._port = port port.path_from_chromium_base = self._mock_path_from_chromium_base output = outputcapture.OutputCapture() orig_environ = os.environ.copy() @@ -65,6 +67,7 @@ class ChromiumWinTest(unittest.TestCase): options=ChromiumWinTest.RegisterCygwinOption()) port._executive = mocktool.MockExecutive(should_log=True) port.path_from_chromium_base = self._mock_path_from_chromium_base + self._port = port setup_mount = self._mock_path_from_chromium_base("third_party", "cygwin", "setup_mount.bat") diff --git a/Tools/Scripts/webkitpy/layout_tests/port/config.py b/Tools/Scripts/webkitpy/layout_tests/port/config.py index e08ed9d..6016639 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/config.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/config.py @@ -32,8 +32,6 @@ # FIXME: This file needs to be unified with common/checkout/scm.py and # common/config/ports.py . -import os - from webkitpy.common.system import logutils from webkitpy.common.system import executive @@ -131,7 +129,7 @@ class Config(object): # # This code will also work if there is no SCM system at all. if not self._webkit_base_dir: - abspath = os.path.abspath(__file__) + abspath = self._filesystem.abspath(__file__) self._webkit_base_dir = abspath[0:abspath.find('Tools') - 1] return self._webkit_base_dir diff --git a/Tools/Scripts/webkitpy/layout_tests/port/google_chrome.py b/Tools/Scripts/webkitpy/layout_tests/port/google_chrome.py index 8d94bb5..ae90374 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/google_chrome.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/google_chrome.py @@ -24,11 +24,6 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from __future__ import with_statement - -import codecs -import os - def _test_expectations_overrides(port, super): # The chrome ports use the regular overrides plus anything in the @@ -40,14 +35,11 @@ def _test_expectations_overrides(port, super): # this changed in r60427. This should probably be changed back. overrides_path = port.path_from_chromium_base('webkit', 'tools', 'layout_tests', 'test_expectations_chrome.txt') - if not os.path.exists(overrides_path): + if not port._filesystem.exists(overrides_path): return chromium_overrides - with codecs.open(overrides_path, "r", "utf-8") as file: - if chromium_overrides: - return chromium_overrides + file.read() - else: - return file.read() + chromium_overrides = chromium_overrides or '' + return chromium_overrides + port._filesystem.read_text_file(overrides_path) def GetGoogleChromePort(**kwargs): """Some tests have slightly different results when compiled as Google diff --git a/Tools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py index e60c274..aab8dd1 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py @@ -24,11 +24,9 @@ # (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 codecs -import os import unittest -from webkitpy.common import newstringio +from webkitpy.common.system import filesystem_mock import factory import google_chrome @@ -50,7 +48,7 @@ class GetGoogleChromePortTest(unittest.TestCase): port = google_chrome.GetGoogleChromePort(port_name=port_name, options=None) path = port.baseline_search_path()[0] - self.assertEqual(expected_path, os.path.split(path)[1]) + self.assertEqual(expected_path, port._filesystem.basename(path)) def _verify_expectations_overrides(self, port_name): # FIXME: make this more robust when we have the Tree() abstraction. @@ -58,45 +56,27 @@ class GetGoogleChromePortTest(unittest.TestCase): # be able to control the contents better. chromium_port = factory.get("chromium-mac") - chromium_overrides = chromium_port.test_expectations_overrides() + chromium_base = chromium_port.path_from_chromium_base() + fs = filesystem_mock.MockFileSystem() port = google_chrome.GetGoogleChromePort(port_name=port_name, - options=None) - - orig_exists = os.path.exists - orig_open = codecs.open - expected_string = "// hello, world\n" - - def mock_exists_chrome_not_found(path): - if 'test_expectations_chrome.txt' in path: - return False - return orig_exists(path) - - def mock_exists_chrome_found(path): - if 'test_expectations_chrome.txt' in path: - return True - return orig_exists(path) - - def mock_open(path, mode, encoding): - if 'test_expectations_chrome.txt' in path: - return newstringio.StringIO(expected_string) - return orig_open(path, mode, encoding) - - try: - os.path.exists = mock_exists_chrome_not_found - chrome_overrides = port.test_expectations_overrides() - self.assertEqual(chromium_overrides, chrome_overrides) - - os.path.exists = mock_exists_chrome_found - codecs.open = mock_open - chrome_overrides = port.test_expectations_overrides() - if chromium_overrides: - self.assertEqual(chrome_overrides, - chromium_overrides + expected_string) - else: - self.assertEqual(chrome_overrides, expected_string) - finally: - os.path.exists = orig_exists - codecs.open = orig_open + options=None, filesystem=fs) + + expected_chromium_overrides = '// chromium overrides\n' + expected_chrome_overrides = '// chrome overrides\n' + chromium_path = fs.join(chromium_base, 'webkit', 'tools', + 'layout_tests', 'test_expectations.txt') + chrome_path = fs.join(chromium_base, 'webkit', 'tools', + 'layout_tests', 'test_expectations_chrome.txt') + + fs.files[chromium_path] = expected_chromium_overrides + fs.files[chrome_path] = None + actual_chrome_overrides = port.test_expectations_overrides() + self.assertEqual(expected_chromium_overrides, actual_chrome_overrides) + + fs.files[chrome_path] = expected_chrome_overrides + actual_chrome_overrides = port.test_expectations_overrides() + self.assertEqual(actual_chrome_overrides, + expected_chromium_overrides + expected_chrome_overrides) if __name__ == '__main__': diff --git a/Tools/Scripts/webkitpy/layout_tests/port/gtk.py b/Tools/Scripts/webkitpy/layout_tests/port/gtk.py index a18fdff..0ec9f87 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/gtk.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/gtk.py @@ -57,8 +57,8 @@ class GtkPort(WebKitPort): def _path_to_apache_config_file(self): # FIXME: This needs to detect the distribution and change config files. - return os.path.join(self.layout_tests_dir(), 'http', 'conf', - 'apache2-debian-httpd.conf') + return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', + 'apache2-debian-httpd.conf') def _shut_down_http_server(self, server_pid): """Shut down the httpd web server. Blocks until it's fully @@ -103,7 +103,7 @@ class GtkPort(WebKitPort): else: config_name = 'apache2-debian-httpd.conf' - return os.path.join(self.layout_tests_dir(), 'http', 'conf', + return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', config_name) def _path_to_wdiff(self): @@ -113,4 +113,4 @@ class GtkPort(WebKitPort): return '/usr/bin/wdiff' def _is_redhat_based(self): - return os.path.exists(os.path.join('/etc', 'redhat-release')) + return self._filesystem.exists(self._filesystem.join('/etc', 'redhat-release')) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mac.py b/Tools/Scripts/webkitpy/layout_tests/port/mac.py index 696e339..0622196 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/mac.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/mac.py @@ -76,9 +76,9 @@ class MacPort(WebKitPort): # platforms and moved into base.Port. skipped_files = [] if self._name in ('mac-tiger', 'mac-leopard', 'mac-snowleopard'): - skipped_files.append(os.path.join( + skipped_files.append(self._filesystem.join( self._webkit_baseline_path(self._name), 'Skipped')) - skipped_files.append(os.path.join(self._webkit_baseline_path('mac'), + skipped_files.append(self._filesystem.join(self._webkit_baseline_path('mac'), 'Skipped')) return skipped_files @@ -99,7 +99,7 @@ class MacPort(WebKitPort): return '' def _build_java_test_support(self): - java_tests_path = os.path.join(self.layout_tests_dir(), "java") + java_tests_path = self._filesystem.join(self.layout_tests_dir(), "java") build_java = ["/usr/bin/make", "-C", java_tests_path] if self._executive.run_command(build_java, return_exit_code=True): _log.error("Failed to build Java support files: %s" % build_java) @@ -124,8 +124,8 @@ class MacPort(WebKitPort): ] def _path_to_apache_config_file(self): - return os.path.join(self.layout_tests_dir(), 'http', 'conf', - 'apache2-httpd.conf') + return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', + 'apache2-httpd.conf') # FIXME: This doesn't have anything to do with WebKit. def _shut_down_http_server(self, server_pid): diff --git a/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py b/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py index c4b36ac..0b03b4c 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py @@ -28,8 +28,6 @@ """Unit testing base class for Port implementations.""" -import os -import tempfile import unittest from webkitpy.tool import mocktool @@ -52,44 +50,39 @@ class PortTestCase(unittest.TestCase): return self.assertTrue(len(port.driver_cmd_line())) - def test_http_server(self): + def disabled_test_http_server(self): port = self.make_port() if not port: return port.start_http_server() port.stop_http_server() - def test_image_diff(self): + def disabled_test_image_diff(self): port = self.make_port() if not port: return - # FIXME: not sure why this shouldn't always be True - #self.assertTrue(port.check_image_diff()) if not port.check_image_diff(): + # The port hasn't been built - don't run the tests. return dir = port.layout_tests_dir() - file1 = os.path.join(dir, 'fast', 'css', 'button_center.png') - fh1 = file(file1) - contents1 = fh1.read() - file2 = os.path.join(dir, 'fast', 'css', - 'remove-shorthand-expected.png') - fh2 = file(file2) - contents2 = fh2.read() - tmpfile = tempfile.mktemp() + file1 = port._filesystem.join(dir, 'fast', 'css', 'button_center.png') + contents1 = port._filesystem.read_binary_file(file1) + file2 = port._filesystem.join(dir, 'fast', 'css', + 'remove-shorthand-expected.png') + contents2 = port._filesystem.read_binary_file(file2) + tmpfd, tmpfile = port._filesystem.open_binary_tempfile('') + tmpfd.close() self.assertFalse(port.diff_image(contents1, contents1)) self.assertTrue(port.diff_image(contents1, contents2)) self.assertTrue(port.diff_image(contents1, contents2, tmpfile)) - fh1.close() - fh2.close() - # FIXME: this may not be being written? - # self.assertTrue(os.path.exists(tmpfile)) - # os.remove(tmpfile) - def test_websocket_server(self): + port._filesystem.remove(tmpfile) + + def disabled_test_websocket_server(self): port = self.make_port() if not port: return diff --git a/Tools/Scripts/webkitpy/layout_tests/port/qt.py b/Tools/Scripts/webkitpy/layout_tests/port/qt.py index af94acc..1695b60 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/qt.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/qt.py @@ -71,8 +71,8 @@ class QtPort(WebKitPort): def _path_to_apache_config_file(self): # FIXME: This needs to detect the distribution and change config files. - return os.path.join(self.layout_tests_dir(), 'http', 'conf', - 'apache2-debian-httpd.conf') + return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', + 'apache2-debian-httpd.conf') def _shut_down_http_server(self, server_pid): """Shut down the httpd web server. Blocks until it's fully diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test.py b/Tools/Scripts/webkitpy/layout_tests/port/test.py index 935881c..5df5c2d 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/test.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/test.py @@ -30,12 +30,10 @@ """Dummy Port implementation used for testing.""" from __future__ import with_statement -import codecs -import fnmatch -import os -import sys import time +from webkitpy.common.system import filesystem_mock + from webkitpy.layout_tests.layout_package import test_output import base @@ -64,8 +62,7 @@ class TestInstance: # This is an in-memory list of tests, what we want them to produce, and # what we want to claim are the expected results. class TestList: - def __init__(self, port): - self.port = port + def __init__(self): self.tests = {} def add(self, name, **kwargs): @@ -84,66 +81,141 @@ class TestList: return self.tests[item] +def unit_test_list(): + tests = TestList() + tests.add('failures/expected/checksum.html', + actual_checksum='checksum_fail-checksum') + tests.add('failures/expected/crash.html', crash=True) + tests.add('failures/expected/exception.html', exception=True) + tests.add('failures/expected/timeout.html', timeout=True) + tests.add('failures/expected/hang.html', hang=True) + tests.add('failures/expected/missing_text.html', + expected_text=None) + tests.add('failures/expected/image.html', + actual_image='image_fail-png', + expected_image='image-png') + tests.add('failures/expected/image_checksum.html', + actual_checksum='image_checksum_fail-checksum', + actual_image='image_checksum_fail-png') + tests.add('failures/expected/keyboard.html', + keyboard=True) + tests.add('failures/expected/missing_check.html', + expected_checksum=None) + tests.add('failures/expected/missing_image.html', + expected_image=None) + tests.add('failures/expected/missing_text.html', + expected_text=None) + tests.add('failures/expected/newlines_leading.html', + expected_text="\nfoo\n", + actual_text="foo\n") + tests.add('failures/expected/newlines_trailing.html', + expected_text="foo\n\n", + actual_text="foo\n") + tests.add('failures/expected/newlines_with_excess_CR.html', + expected_text="foo\r\r\r\n", + actual_text="foo\n") + tests.add('failures/expected/text.html', + actual_text='text_fail-png') + tests.add('failures/unexpected/crash.html', crash=True) + tests.add('failures/unexpected/text-image-checksum.html', + actual_text='text-image-checksum_fail-txt', + actual_checksum='text-image-checksum_fail-checksum') + tests.add('failures/unexpected/timeout.html', timeout=True) + tests.add('http/tests/passes/text.html') + tests.add('http/tests/ssl/text.html') + tests.add('passes/error.html', error='stuff going to stderr') + tests.add('passes/image.html') + tests.add('passes/platform_image.html') + # Text output files contain "\r\n" on Windows. This may be + # helpfully filtered to "\r\r\n" by our Python/Cygwin tooling. + tests.add('passes/text.html', + expected_text='\nfoo\n\n', + actual_text='\nfoo\r\n\r\r\n') + tests.add('websocket/tests/passes/text.html') + return tests + + +# Here we use a non-standard location for the layout tests, to ensure that +# this works. The path contains a '.' in the name because we've seen bugs +# related to this before. + +LAYOUT_TEST_DIR = '/test.checkout/LayoutTests' + + +# Here we synthesize an in-memory filesystem from the test list +# in order to fully control the test output and to demonstrate that +# we don't need a real filesystem to run the tests. + +def unit_test_filesystem(files=None): + """Return the FileSystem object used by the unit tests.""" + test_list = unit_test_list() + files = files or {} + + def add_file(files, test, suffix, contents): + dirname = test.name[0:test.name.rfind('/')] + base = test.base + path = LAYOUT_TEST_DIR + '/' + dirname + '/' + base + suffix + files[path] = contents + + # Add each test and the expected output, if any. + for test in test_list.tests.values(): + add_file(files, test, '.html', '') + add_file(files, test, '-expected.txt', test.expected_text) + add_file(files, test, '-expected.checksum', test.expected_checksum) + add_file(files, test, '-expected.png', test.expected_image) + + # Add the test_expectations file. + files[LAYOUT_TEST_DIR + '/platform/test/test_expectations.txt'] = """ +WONTFIX : failures/expected/checksum.html = IMAGE +WONTFIX : failures/expected/crash.html = CRASH +// This one actually passes because the checksums will match. +WONTFIX : failures/expected/image.html = PASS +WONTFIX : failures/expected/image_checksum.html = IMAGE +WONTFIX : failures/expected/missing_check.html = MISSING PASS +WONTFIX : failures/expected/missing_image.html = MISSING PASS +WONTFIX : failures/expected/missing_text.html = MISSING PASS +WONTFIX : failures/expected/newlines_leading.html = TEXT +WONTFIX : failures/expected/newlines_trailing.html = TEXT +WONTFIX : failures/expected/newlines_with_excess_CR.html = TEXT +WONTFIX : failures/expected/text.html = TEXT +WONTFIX : failures/expected/timeout.html = TIMEOUT +WONTFIX SKIP : failures/expected/hang.html = TIMEOUT +WONTFIX SKIP : failures/expected/keyboard.html = CRASH +WONTFIX SKIP : failures/expected/exception.html = CRASH +""" + + fs = filesystem_mock.MockFileSystem(files) + fs._tests = test_list + return fs + + class TestPort(base.Port): """Test implementation of the Port interface.""" def __init__(self, **kwargs): + # FIXME: what happens if we're not passed in the test filesystem + # and the tests don't match what's in the filesystem? + # + # We'll leave as is for now to avoid unnecessary dependencies while + # converting all of the unit tests over to using + # unit_test_filesystem(). If things get out of sync the tests should + # fail in fairly obvious ways. Eventually we want to just do: + # + # assert kwargs['filesystem']._tests + # self._tests = kwargs['filesystem']._tests + + if 'filesystem' not in kwargs or kwargs['filesystem'] is None: + kwargs['filesystem'] = unit_test_filesystem() + self._tests = kwargs['filesystem']._tests + else: + self._tests = unit_test_list() + + kwargs.setdefault('port_name', 'test') base.Port.__init__(self, **kwargs) - tests = TestList(self) - tests.add('failures/expected/checksum.html', - actual_checksum='checksum_fail-checksum') - tests.add('failures/expected/crash.html', crash=True) - tests.add('failures/expected/exception.html', exception=True) - tests.add('failures/expected/timeout.html', timeout=True) - tests.add('failures/expected/hang.html', hang=True) - tests.add('failures/expected/missing_text.html', - expected_text=None) - tests.add('failures/expected/image.html', - actual_image='image_fail-png', - expected_image='image-png') - tests.add('failures/expected/image_checksum.html', - actual_checksum='image_checksum_fail-checksum', - actual_image='image_checksum_fail-png') - tests.add('failures/expected/keyboard.html', - keyboard=True) - tests.add('failures/expected/missing_check.html', - expected_checksum=None) - tests.add('failures/expected/missing_image.html', - expected_image=None) - tests.add('failures/expected/missing_text.html', - expected_text=None) - tests.add('failures/expected/newlines_leading.html', - expected_text="\nfoo\n", - actual_text="foo\n") - tests.add('failures/expected/newlines_trailing.html', - expected_text="foo\n\n", - actual_text="foo\n") - tests.add('failures/expected/newlines_with_excess_CR.html', - expected_text="foo\r\r\r\n", - actual_text="foo\n") - tests.add('failures/expected/text.html', - actual_text='text_fail-png') - tests.add('failures/unexpected/crash.html', crash=True) - tests.add('failures/unexpected/text-image-checksum.html', - actual_text='text-image-checksum_fail-txt', - actual_checksum='text-image-checksum_fail-checksum') - tests.add('failures/unexpected/timeout.html', timeout=True) - tests.add('http/tests/passes/text.html') - tests.add('http/tests/ssl/text.html') - tests.add('passes/error.html', error='stuff going to stderr') - tests.add('passes/image.html') - tests.add('passes/platform_image.html') - # Text output files contain "\r\n" on Windows. This may be - # helpfully filtered to "\r\r\n" by our Python/Cygwin tooling. - tests.add('passes/text.html', - expected_text='\nfoo\n\n', - actual_text='\nfoo\r\n\r\r\n') - tests.add('websocket/tests/passes/text.html') - self._tests = tests def baseline_path(self): - return os.path.join(self.layout_tests_dir(), 'platform', - self.name() + self.version()) + return self._filesystem.join(self.layout_tests_dir(), 'platform', + self.name() + self.version()) def baseline_search_path(self): return [self.baseline_path()] @@ -155,92 +227,12 @@ class TestPort(base.Port): diff_filename=None): diffed = actual_contents != expected_contents if diffed and diff_filename: - with codecs.open(diff_filename, "w", "utf-8") as diff_fh: - diff_fh.write("< %s\n---\n> %s\n" % - (expected_contents, actual_contents)) + self._filesystem.write_text_file(diff_filename, + "< %s\n---\n> %s\n" % (expected_contents, actual_contents)) return diffed - def expected_checksum(self, test): - test = self.relative_test_filename(test) - return self._tests[test].expected_checksum - - def expected_image(self, test): - test = self.relative_test_filename(test) - return self._tests[test].expected_image - - def expected_text(self, test): - test = self.relative_test_filename(test) - text = self._tests[test].expected_text - if not text: - text = '' - return text - - def tests(self, paths): - # Test the idea of port-specific overrides for test lists. Also - # keep in memory to speed up the test harness. - if not paths: - paths = ['*'] - - matched_tests = [] - for p in paths: - if self.path_isdir(p): - matched_tests.extend(fnmatch.filter(self._tests.keys(), p + '*')) - else: - matched_tests.extend(fnmatch.filter(self._tests.keys(), p)) - layout_tests_dir = self.layout_tests_dir() - return set([os.path.join(layout_tests_dir, p) for p in matched_tests]) - - def path_exists(self, path): - # used by test_expectations.py and printing.py - rpath = self.relative_test_filename(path) - if rpath in self._tests: - return True - if self.path_isdir(rpath): - return True - if rpath.endswith('-expected.txt'): - test = rpath.replace('-expected.txt', '.html') - return (test in self._tests and - self._tests[test].expected_text) - if rpath.endswith('-expected.checksum'): - test = rpath.replace('-expected.checksum', '.html') - return (test in self._tests and - self._tests[test].expected_checksum) - if rpath.endswith('-expected.png'): - test = rpath.replace('-expected.png', '.html') - return (test in self._tests and - self._tests[test].expected_image) - return False - def layout_tests_dir(self): - return self.path_from_webkit_base('Tools', 'Scripts', - 'webkitpy', 'layout_tests', 'data') - - def path_isdir(self, path): - # Used by test_expectations.py - # - # We assume that a path is a directory if we have any tests - # that whose prefix matches the path plus a directory modifier - # and not a file extension. - if path[-1] != '/': - path += '/' - - # FIXME: Directories can have a dot in the name. We should - # probably maintain a white list of known cases like CSS2.1 - # and check it here in the future. - if path.find('.') != -1: - # extension separator found, assume this is a file - return False - - # strip out layout tests directory path if found. The tests - # keys are relative to it. - tests_dir = self.layout_tests_dir() - if path.startswith(tests_dir): - path = path[len(tests_dir) + 1:] - - return any([t.startswith(path) for t in self._tests.keys()]) - - def test_dirs(self): - return ['passes', 'failures'] + return LAYOUT_TEST_DIR def name(self): return self._name @@ -269,33 +261,12 @@ class TestPort(base.Port): def stop_websocket_server(self): pass - def test_expectations(self): - """Returns the test expectations for this port. - - Basically this string should contain the equivalent of a - test_expectations file. See test_expectations.py for more details.""" - return """ -WONTFIX : failures/expected/checksum.html = IMAGE -WONTFIX : failures/expected/crash.html = CRASH -// This one actually passes because the checksums will match. -WONTFIX : failures/expected/image.html = PASS -WONTFIX : failures/expected/image_checksum.html = IMAGE -WONTFIX : failures/expected/missing_check.html = MISSING PASS -WONTFIX : failures/expected/missing_image.html = MISSING PASS -WONTFIX : failures/expected/missing_text.html = MISSING PASS -WONTFIX : failures/expected/newlines_leading.html = TEXT -WONTFIX : failures/expected/newlines_trailing.html = TEXT -WONTFIX : failures/expected/newlines_with_excess_CR.html = TEXT -WONTFIX : failures/expected/text.html = TEXT -WONTFIX : failures/expected/timeout.html = TIMEOUT -WONTFIX SKIP : failures/expected/hang.html = TIMEOUT -WONTFIX SKIP : failures/expected/keyboard.html = CRASH -WONTFIX SKIP : failures/expected/exception.html = CRASH -""" - def test_base_platform_names(self): return ('mac', 'win') + def test_expectations(self): + return self._filesystem.read_text_file(LAYOUT_TEST_DIR + '/platform/test/test_expectations.txt') + def test_platform_name(self): return 'mac' diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test_files.py b/Tools/Scripts/webkitpy/layout_tests/port/test_files.py index 2c0a7b6..41d918f 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/test_files.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/test_files.py @@ -34,8 +34,6 @@ list of test files is constrained to those found under the paths passed in, i.e. calling find(["LayoutTests/fast"]) will only return files under that directory.""" -import glob -import os import time from webkitpy.common.system import logutils @@ -58,16 +56,18 @@ def find(port, paths): paths: a list of command line paths relative to the layout_tests_dir() to limit the search to. glob patterns are ok. """ + fs = port._filesystem gather_start_time = time.time() paths_to_walk = set() + # if paths is empty, provide a pre-defined list. if paths: _log.debug("Gathering tests from: %s relative to %s" % (paths, port.layout_tests_dir())) for path in paths: # If there's an * in the name, assume it's a glob pattern. - path = os.path.join(port.layout_tests_dir(), path) + path = fs.join(port.layout_tests_dir(), path) if path.find('*') > -1: - filenames = glob.glob(path) + filenames = fs.glob(path) paths_to_walk.update(filenames) else: paths_to_walk.add(path) @@ -75,30 +75,12 @@ def find(port, paths): _log.debug("Gathering tests from: %s" % port.layout_tests_dir()) paths_to_walk.add(port.layout_tests_dir()) - # Now walk all the paths passed in on the command line and get filenames + # FIXME: I'm not sure there's much point in this being a set. A list would + # probably be faster. test_files = set() for path in paths_to_walk: - if os.path.isfile(path) and _is_test_file(path): - test_files.add(os.path.normpath(path)) - continue - - for root, dirs, files in os.walk(path): - # Don't walk skipped directories or their sub-directories. - if os.path.basename(root) in _skipped_directories: - del dirs[:] - continue - # This copy and for-in is slightly inefficient, but - # the extra walk avoidance consistently shaves .5 seconds - # off of total walk() time on my MacBook Pro. - for directory in dirs[:]: - if directory in _skipped_directories: - dirs.remove(directory) - - for filename in files: - if _is_test_file(filename): - filename = os.path.join(root, filename) - filename = os.path.normpath(filename) - test_files.add(filename) + files = fs.files_under(path, _skipped_directories, _is_test_file) + test_files.update(set(files)) gather_time = time.time() - gather_start_time _log.debug("Test gathering took %f seconds" % gather_time) @@ -106,10 +88,10 @@ def find(port, paths): return test_files -def _has_supported_extension(filename): +def _has_supported_extension(fs, filename): """Return true if filename is one of the file extensions we want to run a test on.""" - extension = os.path.splitext(filename)[1] + extension = fs.splitext(filename)[1] return extension in _supported_file_extensions @@ -122,7 +104,7 @@ def _is_reference_html_file(filename): return False -def _is_test_file(filename): +def _is_test_file(fs, dirname, filename): """Return true if the filename points to a test file.""" - return (_has_supported_extension(filename) and + return (_has_supported_extension(fs, filename) and not _is_reference_html_file(filename)) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py index 83525c8..a68950a 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py @@ -26,7 +26,6 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -import os import unittest import base @@ -37,8 +36,8 @@ class TestFilesTest(unittest.TestCase): def test_find_no_paths_specified(self): port = base.Port() layout_tests_dir = port.layout_tests_dir() - port.layout_tests_dir = lambda: os.path.join(layout_tests_dir, - 'fast', 'html') + port.layout_tests_dir = lambda: port._filesystem.join(layout_tests_dir, + 'fast', 'html') tests = test_files.find(port, []) self.assertNotEqual(tests, 0) @@ -64,11 +63,13 @@ class TestFilesTest(unittest.TestCase): self.assertEqual(tests, set([])) def test_is_test_file(self): - self.assertTrue(test_files._is_test_file('foo.html')) - self.assertTrue(test_files._is_test_file('foo.shtml')) - self.assertFalse(test_files._is_test_file('foo.png')) - self.assertFalse(test_files._is_test_file('foo-expected.html')) - self.assertFalse(test_files._is_test_file('foo-expected-mismatch.html')) + port = base.Port() + fs = port._filesystem + self.assertTrue(test_files._is_test_file(fs, '', 'foo.html')) + self.assertTrue(test_files._is_test_file(fs, '', 'foo.shtml')) + self.assertFalse(test_files._is_test_file(fs, '', 'foo.png')) + self.assertFalse(test_files._is_test_file(fs, '', 'foo-expected.html')) + self.assertFalse(test_files._is_test_file(fs, '', 'foo-expected-mismatch.html')) if __name__ == '__main__': diff --git a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py index afdebeb..577acd4 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py @@ -31,20 +31,14 @@ """WebKit implementations of the Port interface.""" -from __future__ import with_statement - -import codecs import logging +import operator import os import re -import shutil import signal import sys import time import webbrowser -import operator -import tempfile -import shutil import webkitpy.common.system.ospath as ospath import webkitpy.layout_tests.layout_package.test_output as test_output @@ -72,8 +66,8 @@ class WebKitPort(base.Port): return [self._webkit_baseline_path(self._name)] def path_to_test_expectations_file(self): - return os.path.join(self._webkit_baseline_path(self._name), - 'test_expectations.txt') + return self._filesystem.join(self._webkit_baseline_path(self._name), + 'test_expectations.txt') # Only needed by ports which maintain versioned test expectations (like mac-tiger vs. mac-leopard) def version(self): @@ -85,7 +79,7 @@ class WebKitPort(base.Port): def _check_driver(self): driver_path = self._path_to_driver() - if not os.path.exists(driver_path): + if not self._filesystem.exists(driver_path): _log.error("DumpRenderTree was not found at %s" % driver_path) return False return True @@ -108,7 +102,7 @@ class WebKitPort(base.Port): def check_image_diff(self, override_step=None, logging=True): image_diff_path = self._path_to_image_diff() - if not os.path.exists(image_diff_path): + if not self._filesystem.exists(image_diff_path): _log.error("ImageDiff was not found at %s" % image_diff_path) return False return True @@ -165,8 +159,7 @@ class WebKitPort(base.Port): if m.group(2) == 'passed': result = False elif output and diff_filename: - with open(diff_filename, 'w') as file: - file.write(output) + self._filesystem.write_text_file(diff_filename, output) elif sp.timed_out: _log.error("ImageDiff timed out") elif sp.crashed: @@ -300,25 +293,22 @@ class WebKitPort(base.Port): return tests_to_skip def _skipped_file_paths(self): - return [os.path.join(self._webkit_baseline_path(self._name), - 'Skipped')] + return [self._filesystem.join(self._webkit_baseline_path(self._name), 'Skipped')] def _expectations_from_skipped_files(self): tests_to_skip = [] for filename in self._skipped_file_paths(): - if not os.path.exists(filename): + if not self._filesystem.exists(filename): _log.warn("Failed to open Skipped file: %s" % filename) continue - with codecs.open(filename, "r", "utf-8") as skipped_file: - tests_to_skip.extend(self._tests_from_skipped_file(skipped_file)) + skipped_file = self._filesystem.read_text_file(filename) return tests_to_skip def test_expectations(self): # The WebKit mac port uses a combination of a test_expectations file # and 'Skipped' files. expectations_path = self.path_to_test_expectations_file() - with codecs.open(expectations_path, "r", "utf-8") as file: - return file.read() + self._skips() + return self._filesystem.read_text_file(expectations_path) + self._skips() def _skips(self): # Each Skipped file contains a list of files @@ -373,7 +363,7 @@ class WebKitPort(base.Port): # The Apache binary path can vary depending on OS and distribution # See http://wiki.apache.org/httpd/DistrosDefaultLayout for path in ["/usr/sbin/httpd", "/usr/sbin/apache2"]: - if os.path.exists(path): + if self._filesystem.exists(path): self._cached_apache_path = path break @@ -389,10 +379,10 @@ class WebKitDriver(base.Driver): def __init__(self, port, worker_number): self._worker_number = worker_number self._port = port - self._driver_tempdir = tempfile.mkdtemp(prefix='DumpRenderTree-') + self._driver_tempdir = port._filesystem.mkdtemp(prefix='DumpRenderTree-') def __del__(self): - shutil.rmtree(self._driver_tempdir) + self._port._filesystem.rmtree(str(self._driver_tempdir)) def cmd_line(self): cmd = self._command_wrapper(self._port.get_option('wrapper')) @@ -406,7 +396,7 @@ class WebKitDriver(base.Driver): def start(self): environment = self._port.setup_environ_for_server() environment['DYLD_FRAMEWORK_PATH'] = self._port._build_path() - environment['DUMPRENDERTREE_TEMP'] = self._driver_tempdir + environment['DUMPRENDERTREE_TEMP'] = str(self._driver_tempdir) self._server_process = server_process.ServerProcess(self._port, "DumpRenderTree", self.cmd_line(), environment) diff --git a/Tools/Scripts/webkitpy/layout_tests/port/win.py b/Tools/Scripts/webkitpy/layout_tests/port/win.py index 9e30155..e7d2004 100644 --- a/Tools/Scripts/webkitpy/layout_tests/port/win.py +++ b/Tools/Scripts/webkitpy/layout_tests/port/win.py @@ -29,7 +29,6 @@ """WebKit Win implementation of the Port interface.""" import logging -import os from webkitpy.layout_tests.port.webkit import WebKitPort @@ -60,8 +59,8 @@ class WinPort(WebKitPort): ] def _path_to_apache_config_file(self): - return os.path.join(self.layout_tests_dir(), 'http', 'conf', - 'cygwin-httpd.conf') + return self._filesystem.join(self.layout_tests_dir(), 'http', 'conf', + 'cygwin-httpd.conf') def _shut_down_http_server(self, server_pid): """Shut down the httpd web server. Blocks until it's fully diff --git a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py index 4d8b7c9..c852186 100644 --- a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py +++ b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py @@ -41,26 +41,18 @@ The script does the following for each platform specified: At the end, the script generates a html that compares old and new baselines. """ -from __future__ import with_statement - -import codecs import copy import logging import optparse -import os import re -import shutil -import subprocess import sys -import tempfile import time import urllib import zipfile +from webkitpy.common.checkout import scm from webkitpy.common.system import path -from webkitpy.common.system import user -from webkitpy.common.system.executive import Executive, ScriptError -import webkitpy.common.checkout.scm as scm +from webkitpy.common.system.executive import ScriptError import port from layout_package import test_expectations @@ -70,16 +62,16 @@ _log = logging.getLogger("webkitpy.layout_tests." BASELINE_SUFFIXES = ['.txt', '.png', '.checksum'] REBASELINE_PLATFORM_ORDER = ['mac', 'win', 'win-xp', 'win-vista', 'linux'] -ARCHIVE_DIR_NAME_DICT = {'win': 'Webkit_Win', +ARCHIVE_DIR_NAME_DICT = {'win': 'Webkit_Win__deps_', 'win-vista': 'webkit-dbg-vista', - 'win-xp': 'Webkit_Win', - 'mac': 'Webkit_Mac10_5', - 'linux': 'webkit-rel-linux64', - 'win-canary': 'webkit-rel-webkit-org', + 'win-xp': 'Webkit_Win__deps_', + 'mac': 'Webkit_Mac10_5__deps_', + 'linux': 'Webkit_Linux__deps_', + 'win-canary': 'Webkit_Win', 'win-vista-canary': 'webkit-dbg-vista', - 'win-xp-canary': 'webkit-rel-webkit-org', - 'mac-canary': 'webkit-rel-mac-webkit-org', - 'linux-canary': 'webkit-rel-linux-webkit-org'} + 'win-xp-canary': 'Webkit_Win', + 'mac-canary': 'Webkit_Mac10_5', + 'linux-canary': 'Webkit_Linux'} def log_dashed_string(text, platform, logging_level=logging.INFO): @@ -100,41 +92,35 @@ def log_dashed_string(text, platform, logging_level=logging.INFO): _log.info(msg) -def setup_html_directory(html_directory): +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. - - Args: - html_directory: parent directory that stores the rebaselining results. - If None, a temp directory is created. - - Returns: - the directory that stores the html related rebaselining 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 html_directory: - html_directory = tempfile.mkdtemp() - elif not os.path.exists(html_directory): - os.mkdir(html_directory) + if not parent_directory: + parent_directory = str(filesystem.mkdtemp()) + else: + filesystem.maybe_make_directory(parent_directory) - html_directory = os.path.join(html_directory, 'rebaseline_html') + html_directory = filesystem.join(parent_directory, 'rebaseline_html') _log.info('Html directory: "%s"', html_directory) - if os.path.exists(html_directory): - shutil.rmtree(html_directory, True) - _log.info('Deleted file at html directory: "%s"', html_directory) + if filesystem.exists(html_directory): + filesystem.rmtree(html_directory) + _log.info('Deleted html directory: "%s"', html_directory) - if not os.path.exists(html_directory): - os.mkdir(html_directory) + filesystem.maybe_make_directory(html_directory) return html_directory -def get_result_file_fullpath(html_directory, baseline_filename, platform, +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 @@ -144,9 +130,9 @@ def get_result_file_fullpath(html_directory, baseline_filename, platform, Full path of the baseline file for rebaselining result comparison. """ - base, ext = os.path.splitext(baseline_filename) + base, ext = filesystem.splitext(baseline_filename) result_filename = '%s-%s-%s%s' % (base, platform, result_type, ext) - fullpath = os.path.join(html_directory, result_filename) + fullpath = filesystem.join(html_directory, result_filename) _log.debug(' Result file full path: "%s".', fullpath) return fullpath @@ -168,6 +154,7 @@ class Rebaseliner(object): self._platform = platform self._options = options self._port = running_port + self._filesystem = running_port._filesystem self._target_port = target_port self._rebaseline_port = port.get( self._target_port.test_platform_name_to_name(platform), options) @@ -370,7 +357,7 @@ class Rebaseliner(object): found = False scm_error = False - test_basename = os.path.splitext(test)[0] + test_basename = self._filesystem.splitext(test)[0] for suffix in BASELINE_SUFFIXES: archive_test_name = ('layout-test-results/%s-actual%s' % (test_basename, suffix)) @@ -385,15 +372,14 @@ class Rebaseliner(object): # Extract new baseline from archive and save it to a temp file. data = zip_file.read(archive_test_name) - temp_fd, temp_name = tempfile.mkstemp(suffix) - f = os.fdopen(temp_fd, 'wb') - f.write(data) - f.close() + tempfile, temp_name = self._filesystem.open_binary_tempfile(suffix) + tempfile.write(data) + tempfile.close() expected_filename = '%s-expected%s' % (test_basename, suffix) - expected_fullpath = os.path.join( + expected_fullpath = self._filesystem.join( self._rebaseline_port.baseline_path(), expected_filename) - expected_fullpath = os.path.normpath(expected_fullpath) + expected_fullpath = self._filesystem.normpath(expected_fullpath) _log.debug(' Expected file full path: "%s"', expected_fullpath) @@ -407,16 +393,13 @@ class Rebaseliner(object): test, suffix, self._platform): - os.remove(temp_name) + self._filesystem.remove(temp_name) self._delete_baseline(expected_fullpath) continue - # Create the new baseline directory if it doesn't already - # exist. - self._port.maybe_make_directory( - os.path.dirname(expected_fullpath)) + self._filesystem.maybe_make_directory(self._filesystem.dirname(expected_fullpath)) - shutil.move(temp_name, expected_fullpath) + self._filesystem.move(temp_name, expected_fullpath) if 0 != self._scm.add(expected_fullpath, return_exit_code=True): # FIXME: print detailed diagnose messages @@ -436,7 +419,7 @@ class Rebaseliner(object): test_no += 1 zip_file.close() - os.remove(archive_file) + self._filesystem.remove(archive_file) return self._rebaselined_tests @@ -458,21 +441,17 @@ class Rebaseliner(object): True if the baseline is unnecessary. False otherwise. """ - test_filepath = os.path.join(self._target_port.layout_tests_dir(), + test_filepath = self._filesystem.join(self._target_port.layout_tests_dir(), test) all_baselines = self._rebaseline_port.expected_baselines( test_filepath, suffix, True) for (fallback_dir, fallback_file) in all_baselines: if fallback_dir and fallback_file: - fallback_fullpath = os.path.normpath( - os.path.join(fallback_dir, fallback_file)) + fallback_fullpath = self._filesystem.normpath( + self._filesystem.join(fallback_dir, fallback_file)) if fallback_fullpath.lower() != baseline_path.lower(): - with codecs.open(new_baseline, "r", - None) as file_handle1: - new_output = file_handle1.read() - with codecs.open(fallback_fullpath, "r", - None) as file_handle2: - fallback_output = file_handle2.read() + 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): @@ -507,7 +486,7 @@ class Rebaseliner(object): filename: full path of the file to delete. """ - if not filename or not os.path.isfile(filename): + if not filename or not self._filesystem.isfile(filename): return self._scm.delete(filename) @@ -530,14 +509,12 @@ class Rebaseliner(object): date_suffix = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())) backup_file = ('%s.orig.%s' % (path, date_suffix)) - if os.path.exists(backup_file): - os.remove(backup_file) + if self._filesystem.exists(backup_file): + self._filesystem.remove(backup_file) _log.info('Saving original file to "%s"', backup_file) - os.rename(path, backup_file) - # FIXME: What encoding are these files? - # Or is new_expectations always a byte array? - with open(path, "w") as file: - file.write(new_expectations) + self._filesystem.move(path, backup_file) + + self._filesystem.write_text_file(path, new_expectations) # self._scm.add(path) else: _log.info('No test was rebaselined so nothing to remove.') @@ -551,15 +528,15 @@ class Rebaseliner(object): baseline_fullpath: full path of the expected baseline file. """ - if not baseline_fullpath or not os.path.exists(baseline_fullpath): + if not baseline_fullpath or not self._filesystem.exists(baseline_fullpath): return # Copy the new baseline to html directory for result comparison. - baseline_filename = os.path.basename(baseline_fullpath) - new_file = get_result_file_fullpath(self._options.html_directory, + baseline_filename = self._filesystem.basename(baseline_fullpath) + new_file = get_result_file_fullpath(self._filesystem, self._options.html_directory, baseline_filename, self._platform, 'new') - shutil.copyfile(baseline_fullpath, new_file) + self._filesystem.copyfile(baseline_fullpath, new_file) _log.info(' Html: copied new baseline file from "%s" to "%s".', baseline_fullpath, new_file) @@ -574,12 +551,13 @@ class Rebaseliner(object): 'NO SUCH FILE OR DIRECTORY')): _log.info(' No base file: "%s"', baseline_fullpath) return - base_file = get_result_file_fullpath(self._options.html_directory, + base_file = get_result_file_fullpath(self._filesystem, self._options.html_directory, baseline_filename, self._platform, 'old') - # We should be using an explicit encoding here. - with open(base_file, "wb") as file: - file.write(output) + if base_file.upper().endswith('.PNG'): + self._filesystem.write_binary_file(base_file, output) + else: + self._filesystem.write_text_file(base_file, output) _log.info(' Html: created old baseline file: "%s".', base_file) @@ -587,11 +565,10 @@ class Rebaseliner(object): if baseline_filename.upper().endswith('.TXT'): output = self._scm.diff_for_file(baseline_fullpath, log=_log) if output: - diff_file = get_result_file_fullpath( + diff_file = get_result_file_fullpath(self._filesystem, self._options.html_directory, baseline_filename, self._platform, 'diff') - with open(diff_file, 'wb') as file: - file.write(output) + self._filesystem.write_text_file(diff_file, output) _log.info(' Html: created baseline diff file: "%s".', diff_file) @@ -642,19 +619,19 @@ class HtmlGenerator(object): '<img style="width: 200" src="%(uri)s" /></a></td>') HTML_TR = '<tr>%s</tr>' - def __init__(self, target_port, options, platforms, rebaselining_tests, - executive): + def __init__(self, port, target_port, options, platforms, rebaselining_tests): self._html_directory = options.html_directory + self._port = port self._target_port = target_port self._platforms = platforms self._rebaselining_tests = rebaselining_tests - self._executive = executive - self._html_file = os.path.join(options.html_directory, - 'rebaseline.html') + self._filesystem = port._filesystem + 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._executive) + return path.abspath_to_uri(filename, self._port._executive) def generate_html(self): """Generate html file for rebaselining result comparison.""" @@ -677,9 +654,7 @@ class HtmlGenerator(object): 'body': html_body}) _log.debug(html) - with codecs.open(self._html_file, "w", "utf-8") as file: - file.write(html) - + self._filesystem.write_text_file(self._html_file, html) _log.info('Baseline comparison html generated at "%s"', self._html_file) @@ -687,7 +662,7 @@ class HtmlGenerator(object): """Launch the rebaselining html in brwoser.""" _log.info('Launching html: "%s"', self._html_file) - user.User().open_url(self._html_file) + self._port._user.open_url(self._html_file) _log.info('Html launched.') def _generate_baseline_links(self, test_basename, suffix, platform): @@ -705,14 +680,14 @@ class HtmlGenerator(object): baseline_filename = '%s-expected%s' % (test_basename, suffix) _log.debug(' baseline filename: "%s"', baseline_filename) - new_file = get_result_file_fullpath(self._html_directory, + new_file = get_result_file_fullpath(self._filesystem, self._html_directory, baseline_filename, platform, 'new') _log.info(' New baseline file: "%s"', new_file) - if not os.path.exists(new_file): + if not self._filesystem.exists(new_file): _log.info(' No new baseline file: "%s"', new_file) return '' - old_file = get_result_file_fullpath(self._html_directory, + old_file = get_result_file_fullpath(self._filesystem, self._html_directory, baseline_filename, platform, 'old') _log.info(' Old baseline file: "%s"', old_file) if suffix == '.png': @@ -721,7 +696,7 @@ class HtmlGenerator(object): html_td_link = self.HTML_TD_LINK links = '' - if os.path.exists(old_file): + if self._filesystem.exists(old_file): links += html_td_link % { 'uri': self.abspath_to_uri(old_file), 'name': baseline_filename} @@ -732,11 +707,11 @@ class HtmlGenerator(object): links += html_td_link % {'uri': self.abspath_to_uri(new_file), 'name': baseline_filename} - diff_file = get_result_file_fullpath(self._html_directory, + diff_file = get_result_file_fullpath(self._filesystem, self._html_directory, baseline_filename, platform, 'diff') _log.info(' Baseline diff file: "%s"', diff_file) - if os.path.exists(diff_file): + if self._filesystem.exists(diff_file): links += html_td_link % {'uri': self.abspath_to_uri(diff_file), 'name': 'Diff'} else: @@ -755,7 +730,7 @@ class HtmlGenerator(object): html that compares baseline results for the test. """ - test_basename = os.path.basename(os.path.splitext(test)[0]) + test_basename = self._filesystem.basename(self._filesystem.splitext(test)[0]) _log.info(' basename: "%s"', test_basename) rows = [] for suffix in BASELINE_SUFFIXES: @@ -776,8 +751,7 @@ class HtmlGenerator(object): rows.append(self.HTML_TR % row) if rows: - test_path = os.path.join(self._target_port.layout_tests_dir(), - test) + 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) @@ -883,7 +857,7 @@ def parse_options(args): return (options, target_options) -def main(executive=Executive()): +def main(): """Main function to produce new baselines.""" (options, target_options) = parse_options(sys.argv[1:]) @@ -929,7 +903,7 @@ def main(executive=Executive()): if platform in platforms: rebaseline_platforms.append(platform) - options.html_directory = setup_html_directory(options.html_directory) + options.html_directory = setup_html_directory(host_port_obj._filesystem, options.html_directory) rebaselining_tests = set() backup = options.backup @@ -950,11 +924,11 @@ def main(executive=Executive()): _log.info('') log_dashed_string('Rebaselining result comparison started', None) - html_generator = HtmlGenerator(target_port_obj, + html_generator = HtmlGenerator(host_port_obj, + target_port_obj, options, rebaseline_platforms, - rebaselining_tests, - executive=executive) + rebaselining_tests) html_generator.generate_html() if not options.quiet: html_generator.show_html() diff --git a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py index 7c55b94..50c0204 100644 --- a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py @@ -29,15 +29,15 @@ """Unit tests for rebaseline_chromium_webkit_tests.py.""" -import os -import sys import unittest from webkitpy.tool import mocktool -from webkitpy.layout_tests import port -from webkitpy.layout_tests import rebaseline_chromium_webkit_tests +from webkitpy.common.system import filesystem_mock from webkitpy.common.system.executive import Executive, ScriptError +import port +import rebaseline_chromium_webkit_tests + class MockPort(object): def __init__(self, image_diff_exists): @@ -88,9 +88,10 @@ class TestRebaseliner(unittest.TestCase): def make_rebaseliner(self): options = mocktool.MockOptions(configuration=None, html_directory=None) - host_port_obj = port.get('test', options) + filesystem = filesystem_mock.MockFileSystem() + host_port_obj = port.get('test', options, filesystem=filesystem) target_options = options - target_port_obj = port.get('test', target_options) + target_port_obj = port.get('test', target_options, filesystem=filesystem) platform = 'test' return rebaseline_chromium_webkit_tests.Rebaseliner( host_port_obj, target_port_obj, platform, options) @@ -113,44 +114,43 @@ class TestRebaseliner(unittest.TestCase): def test_diff_baselines_txt(self): rebaseliner = self.make_rebaseliner() output = rebaseliner._port.expected_text( - os.path.join(rebaseliner._port.layout_tests_dir(), - 'passes/text.html')) + rebaseliner._port._filesystem.join(rebaseliner._port.layout_tests_dir(), + 'passes/text.html')) self.assertFalse(rebaseliner._diff_baselines(output, output, is_image=False)) def test_diff_baselines_png(self): rebaseliner = self.make_rebaseliner() image = rebaseliner._port.expected_image( - os.path.join(rebaseliner._port.layout_tests_dir(), - 'passes/image.html')) + rebaseliner._port._filesystem.join(rebaseliner._port.layout_tests_dir(), + 'passes/image.html')) self.assertFalse(rebaseliner._diff_baselines(image, image, is_image=True)) class TestHtmlGenerator(unittest.TestCase): - def make_generator(self, tests): - return rebaseline_chromium_webkit_tests.HtmlGenerator( + def make_generator(self, files, tests): + options = mocktool.MockOptions(configuration=None, html_directory='/tmp') + host_port = port.get('test', options, filesystem=filesystem_mock.MockFileSystem(files)) + generator = rebaseline_chromium_webkit_tests.HtmlGenerator( + host_port, target_port=None, - options=mocktool.MockOptions(configuration=None, - html_directory='/tmp'), + options=options, platforms=['mac'], - rebaselining_tests=tests, - executive=Executive()) + rebaselining_tests=tests) + return generator, host_port def test_generate_baseline_links(self): - orig_platform = sys.platform - orig_exists = os.path.exists - - try: - sys.platform = 'darwin' - os.path.exists = lambda x: True - generator = self.make_generator(["foo.txt"]) - 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) - finally: - sys.platform = orig_platform - os.path.exists = orig_exists + 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__': diff --git a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py index a141661..17b6e89 100755 --- a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py +++ b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py @@ -32,7 +32,6 @@ from __future__ import with_statement -import codecs import errno import logging import optparse @@ -80,7 +79,7 @@ def run(port, options, args, regular_output=sys.stderr, printer.cleanup() return 0 - last_unexpected_results = _gather_unexpected_results(options) + last_unexpected_results = _gather_unexpected_results(port._filesystem, options) if options.print_last_failures: printer.write("\n".join(last_unexpected_results) + "\n") printer.cleanup() @@ -146,7 +145,7 @@ def _set_up_derived_options(port_obj, options): if not options.use_apache: options.use_apache = sys.platform in ('darwin', 'linux2') - if not os.path.isabs(options.results_directory): + if not port_obj._filesystem.isabs(options.results_directory): # This normalizes the path to the build dir. # FIXME: how this happens is not at all obvious; this is a dumb # interface and should be cleaned up. @@ -162,15 +161,16 @@ def _set_up_derived_options(port_obj, options): return warnings -def _gather_unexpected_results(options): +def _gather_unexpected_results(filesystem, options): """Returns the unexpected results from the previous run, if any.""" last_unexpected_results = [] if options.print_last_failures or options.retest_last_failures: - unexpected_results_filename = os.path.join( - options.results_directory, "unexpected_results.json") - with codecs.open(unexpected_results_filename, "r", "utf-8") as file: - results = simplejson.load(file) - last_unexpected_results = results['tests'].keys() + unexpected_results_filename = filesystem.join( + options.results_directory, "unexpected_results.json") + if filesystem.exists(unexpected_results_filename): + content = filesystem.read_text_file(unexpected_results_filename) + results = simplejson.loads(content) + last_unexpected_results = results['tests'].keys() return last_unexpected_results @@ -277,6 +277,8 @@ def parse_args(args=None): default="layout-test-results", help="Output results directory source dir, relative to Debug or " "Release"), + optparse.make_option("--build-directory", + help="Path to the directory under which build files are kept (should not include configuration)"), optparse.make_option("--new-baseline", action="store_true", default=False, help="Save all generated results as new baselines " "into the platform directory, overwriting whatever's " diff --git a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py index 2bfac2f..677becd 100644 --- a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py +++ b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py @@ -30,14 +30,13 @@ """Unit tests for run_webkit_tests.""" +from __future__ import with_statement + import codecs import itertools import logging -import os import Queue -import shutil import sys -import tempfile import thread import time import threading @@ -45,6 +44,7 @@ import unittest from webkitpy.common import array_stream from webkitpy.common.system import outputcapture +from webkitpy.common.system import filesystem_mock from webkitpy.common.system import user from webkitpy.layout_tests import port from webkitpy.layout_tests import run_webkit_tests @@ -88,25 +88,25 @@ def parse_args(extra_args=None, record_results=False, tests_included=False, def passing_run(extra_args=None, port_obj=None, record_results=False, - tests_included=False): + tests_included=False, filesystem=None): options, parsed_args = parse_args(extra_args, record_results, tests_included) if not port_obj: port_obj = port.get(port_name=options.platform, options=options, - user=MockUser()) + user=MockUser(), filesystem=filesystem) res = run_webkit_tests.run(port_obj, options, parsed_args) return res == 0 -def logging_run(extra_args=None, port_obj=None, tests_included=False): +def logging_run(extra_args=None, port_obj=None, record_results=False, tests_included=False, filesystem=None): options, parsed_args = parse_args(extra_args=extra_args, - record_results=False, + record_results=record_results, tests_included=tests_included, print_nothing=False) user = MockUser() if not port_obj: port_obj = port.get(port_name=options.platform, options=options, - user=user) + user=user, filesystem=filesystem) res, buildbot_output, regular_output = run_and_capture(port_obj, options, parsed_args) @@ -127,7 +127,7 @@ def run_and_capture(port_obj, options, parsed_args): return (res, buildbot_output, regular_output) -def get_tests_run(extra_args=None, tests_included=False, flatten_batches=False): +def get_tests_run(extra_args=None, tests_included=False, flatten_batches=False, filesystem=None): extra_args = extra_args or [] if not tests_included: # Not including http tests since they get run out of order (that @@ -163,7 +163,7 @@ def get_tests_run(extra_args=None, tests_included=False, flatten_batches=False): def create_driver(self, worker_number): return RecordingTestDriver(self, worker_number) - recording_port = RecordingTestPort(options=options, user=user) + recording_port = RecordingTestPort(options=options, user=user, filesystem=filesystem) run_and_capture(recording_port, options, parsed_args) if flatten_batches: @@ -239,9 +239,12 @@ class MainTest(unittest.TestCase): ['failures/expected/keyboard.html'], tests_included=True) def test_last_results(self): - passing_run(['--clobber-old-results'], record_results=True) + fs = port.unit_test_filesystem() + # We do a logging run here instead of a passing run in order to + # suppress the output from the json generator. + (res, buildbot_output, regular_output, user) = logging_run(['--clobber-old-results'], record_results=True, filesystem=fs) (res, buildbot_output, regular_output, user) = logging_run( - ['--print-last-failures']) + ['--print-last-failures'], filesystem=fs) self.assertEqual(regular_output.get(), ['\n\n']) self.assertEqual(buildbot_output.get(), []) @@ -315,19 +318,33 @@ class MainTest(unittest.TestCase): tests_run = get_tests_run(['passes/text.html'], tests_included=True, flatten_batches=True) self.assertEquals(['passes/text.html'], tests_run) + def test_single_file_with_prefix(self): + tests_run = get_tests_run(['LayoutTests/passes/text.html'], tests_included=True, flatten_batches=True) + self.assertEquals(['passes/text.html'], tests_run) + + def test_single_skipped_file(self): + tests_run = get_tests_run(['failures/expected/keybaord.html'], tests_included=True, flatten_batches=True) + self.assertEquals([], tests_run) + def test_test_list(self): - filename = tempfile.mktemp() - tmpfile = file(filename, mode='w+') - tmpfile.write('passes/text.html') - tmpfile.close() - tests_run = get_tests_run(['--test-list=%s' % filename], tests_included=True, flatten_batches=True) + fs = port.unit_test_filesystem() + filename = '/tmp/foo.txt' + fs.write_text_file(filename, 'passes/text.html') + tests_run = get_tests_run(['--test-list=%s' % filename], tests_included=True, flatten_batches=True, filesystem=fs) self.assertEquals(['passes/text.html'], tests_run) - os.remove(filename) + fs.remove(filename) res, out, err, user = logging_run(['--test-list=%s' % filename], - tests_included=True) + tests_included=True, filesystem=fs) self.assertEqual(res, -1) self.assertFalse(err.empty()) + def test_test_list_with_prefix(self): + fs = port.unit_test_filesystem() + filename = '/tmp/foo.txt' + fs.write_text_file(filename, 'LayoutTests/passes/text.html') + tests_run = get_tests_run(['--test-list=%s' % filename], tests_included=True, flatten_batches=True, filesystem=fs) + self.assertEquals(['passes/text.html'], tests_run) + def test_unexpected_failures(self): # Run tests including the unexpected failures. self._url_opened = None @@ -393,11 +410,11 @@ class MainTest(unittest.TestCase): # We run a configuration that should fail, to generate output, then # look for what the output results url was. - tmpdir = tempfile.mkdtemp() - res, out, err, user = logging_run(['--results-directory=' + tmpdir], - tests_included=True) - self.assertEqual(user.url, os.path.join(tmpdir, 'results.html')) - shutil.rmtree(tmpdir, ignore_errors=True) + fs = port.unit_test_filesystem() + with fs.mkdtemp() as tmpdir: + res, out, err, user = logging_run(['--results-directory=' + str(tmpdir)], + tests_included=True, filesystem=fs) + self.assertEqual(user.url, fs.join(tmpdir, 'results.html')) def test_results_directory_default(self): # We run a configuration that should fail, to generate output, then @@ -454,18 +471,6 @@ class MainTest(unittest.TestCase): MainTest = skip_if(MainTest, sys.platform == 'cygwin' and compare_version(sys, '2.6')[0] < 0, 'new-run-webkit-tests tests hang on Cygwin Python 2.5.2') - -def _mocked_open(original_open, file_list): - def _wrapper(name, mode, encoding): - if name.find("-expected.") != -1 and mode.find("w") != -1: - # we don't want to actually write new baselines, so stub these out - name.replace('\\', '/') - file_list.append(name) - return original_open(os.devnull, mode, encoding) - return original_open(name, mode, encoding) - return _wrapper - - class RebaselineTest(unittest.TestCase): def assertBaselines(self, file_list, file): "assert that the file_list contains the baselines.""" @@ -476,49 +481,39 @@ class RebaselineTest(unittest.TestCase): # FIXME: Add tests to ensure that we're *not* writing baselines when we're not # supposed to be. - def disabled_test_reset_results(self): - # FIXME: This test is disabled until we can rewrite it to use a - # mock filesystem. - # + def test_reset_results(self): # Test that we update expectations in place. If the expectation # is missing, update the expected generic location. - file_list = [] + fs = port.unit_test_filesystem() passing_run(['--pixel-tests', '--reset-results', 'passes/image.html', 'failures/expected/missing_image.html'], - tests_included=True) + tests_included=True, filesystem=fs) + file_list = fs.written_files.keys() + file_list.remove('/tmp/layout-test-results/tests_run.txt') self.assertEqual(len(file_list), 6) self.assertBaselines(file_list, - "data/passes/image") + "/passes/image") self.assertBaselines(file_list, - "data/failures/expected/missing_image") + "/failures/expected/missing_image") - def disabled_test_new_baseline(self): - # FIXME: This test is disabled until we can rewrite it to use a - # mock filesystem. - # + def test_new_baseline(self): # Test that we update the platform expectations. If the expectation # is mssing, then create a new expectation in the platform dir. - file_list = [] - original_open = codecs.open - try: - # Test that we update the platform expectations. If the expectation - # is mssing, then create a new expectation in the platform dir. - file_list = [] - codecs.open = _mocked_open(original_open, file_list) - passing_run(['--pixel-tests', - '--new-baseline', - 'passes/image.html', - 'failures/expected/missing_image.html'], - tests_included=True) - self.assertEqual(len(file_list), 6) - self.assertBaselines(file_list, - "data/platform/test/passes/image") - self.assertBaselines(file_list, - "data/platform/test/failures/expected/missing_image") - finally: - codecs.open = original_open + fs = port.unit_test_filesystem() + passing_run(['--pixel-tests', + '--new-baseline', + 'passes/image.html', + 'failures/expected/missing_image.html'], + tests_included=True, filesystem=fs) + file_list = fs.written_files.keys() + file_list.remove('/tmp/layout-test-results/tests_run.txt') + self.assertEqual(len(file_list), 6) + self.assertBaselines(file_list, + "/platform/test/passes/image") + self.assertBaselines(file_list, + "/platform/test/failures/expected/missing_image") class DryrunTest(unittest.TestCase): @@ -526,15 +521,14 @@ class DryrunTest(unittest.TestCase): # chromium platforms require a chromium checkout, and the mac platform # requires fcntl, so it can't be tested on win32, etc. There is # probably a better way of handling this. - def test_darwin(self): + def disabled_test_darwin(self): if sys.platform != "darwin": return - self.assertTrue(passing_run(['--platform', 'test'])) - self.assertTrue(passing_run(['--platform', 'dryrun', - 'fast/html'])) - self.assertTrue(passing_run(['--platform', 'dryrun-mac', - 'fast/html'])) + self.assertTrue(passing_run(['--platform', 'dryrun', 'fast/html'], + tests_included=True)) + self.assertTrue(passing_run(['--platform', 'dryrun-mac', 'fast/html'], + tests_included=True)) def test_test(self): self.assertTrue(passing_run(['--platform', 'dryrun-test', diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py b/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py index da466c8..44605d2 100644 --- a/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py +++ b/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py @@ -34,13 +34,8 @@ match, returns FailureImageHashMismatch and outputs both hashes into the layout test results directory. """ -from __future__ import with_statement - -import codecs import errno import logging -import os -import shutil from webkitpy.layout_tests.layout_package import test_failures from webkitpy.layout_tests.test_types import test_type_base diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py b/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py index 4b96b3a..ad65016 100644 --- a/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py +++ b/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py @@ -32,13 +32,9 @@ Also defines the TestArguments "struct" to pass them additional arguments. """ -from __future__ import with_statement - -import codecs import cgi import errno import logging -import os.path _log = logging.getLogger("webkitpy.layout_tests.test_types.test_type_base") @@ -86,9 +82,10 @@ class TestTypeBase(object): def _make_output_directory(self, filename): """Creates the output directory (if needed) for a given test filename.""" - output_filename = os.path.join(self._root_output_dir, + fs = self._port._filesystem + output_filename = fs.join(self._root_output_dir, self._port.relative_test_filename(filename)) - self._port.maybe_make_directory(os.path.split(output_filename)[0]) + fs.maybe_make_directory(fs.dirname(output_filename)) def _save_baseline_data(self, filename, data, modifier, encoding, generate_new_baseline=True): @@ -106,21 +103,22 @@ class TestTypeBase(object): baseline, or update the existing one """ + port = self._port + fs = self._port._filesystem if generate_new_baseline: - relative_dir = os.path.dirname( - self._port.relative_test_filename(filename)) - baseline_path = self._port.baseline_path() - output_dir = os.path.join(baseline_path, relative_dir) - output_file = os.path.basename(os.path.splitext(filename)[0] + + relative_dir = fs.dirname(port.relative_test_filename(filename)) + baseline_path = port.baseline_path() + output_dir = fs.join(baseline_path, relative_dir) + output_file = fs.basename(fs.splitext(filename)[0] + self.FILENAME_SUFFIX_EXPECTED + modifier) - self._port.maybe_make_directory(output_dir) - output_path = os.path.join(output_dir, output_file) + fs.maybe_make_directory(output_dir) + output_path = fs.join(output_dir, output_file) _log.debug('writing new baseline result "%s"' % (output_path)) else: - output_path = self._port.expected_filename(filename, modifier) + output_path = port.expected_filename(filename, modifier) _log.debug('resetting baseline result "%s"' % output_path) - self._port.update_baseline(output_path, data, encoding) + port.update_baseline(output_path, data, encoding) def output_filename(self, filename, modifier): """Returns a filename inside the output dir that contains modifier. @@ -136,9 +134,10 @@ class TestTypeBase(object): Return: The absolute windows path to the output filename """ - output_filename = os.path.join(self._root_output_dir, + fs = self._port._filesystem + output_filename = fs.join(self._root_output_dir, self._port.relative_test_filename(filename)) - return os.path.splitext(output_filename)[0] + modifier + return fs.splitext(output_filename)[0] + modifier def compare_output(self, port, filename, test_args, actual_test_output, expected_test_output): @@ -165,11 +164,11 @@ class TestTypeBase(object): def _write_into_file_at_path(self, file_path, contents, encoding): """This method assumes that byte_array is already encoded into the right format.""" - open_mode = 'w' + fs = self._port._filesystem if encoding is None: - open_mode = 'w+b' - with codecs.open(file_path, open_mode, encoding=encoding) as file: - file.write(contents) + fs.write_binary_file(file_path, contents) + return + fs.write_text_file(file_path, contents) def write_output_files(self, filename, file_type, output, expected, encoding, diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py b/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py index ad25262..7b7febe 100644 --- a/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py +++ b/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py @@ -33,12 +33,8 @@ If the output doesn't match, returns FailureTextMismatch and outputs the diff files into the layout test results directory. """ -from __future__ import with_statement - -import codecs import errno import logging -import os.path from webkitpy.layout_tests.layout_package import test_failures from webkitpy.layout_tests.test_types import test_type_base diff --git a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py index 3be2556..b22138d 100644 --- a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py +++ b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py @@ -187,7 +187,9 @@ class CommitQueueTask(object): first_failing_tests = [result.filename for result in first_results] first_results_archive = self._delegate.archive_last_layout_test_results(self._patch) if self._test(): - self._report_flaky_tests(first_results, first_results_archive) + # Only report flaky tests if we were successful at archiving results. + if first_results_archive: + self._report_flaky_tests(first_results, first_results_archive) return True second_results = self._failing_results_from_last_run() diff --git a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py index 26231ae..87d0ab5 100644 --- a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py +++ b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py @@ -209,6 +209,34 @@ command_passed: success_message='Landed patch' patch='197' """ self._run_through_task(commit_queue, expected_stderr) + def test_failed_archive(self): + commit_queue = MockCommitQueue([ + None, + None, + None, + None, + ScriptError("MOCK tests failure"), + ]) + # It's possible delegate to fail to archive layout tests, don't try to report + # flaky tests when that happens. + commit_queue.archive_last_layout_test_results = lambda patch: None + expected_stderr = """run_webkit_patch: ['clean'] +command_passed: success_message='Cleaned working directory' patch='197' +run_webkit_patch: ['update'] +command_passed: success_message='Updated working directory' patch='197' +run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 197] +command_passed: success_message='Applied patch' patch='197' +run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=both'] +command_passed: success_message='Built patch' patch='197' +run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive'] +command_failed: failure_message='Patch does not pass tests' script_error='MOCK tests failure' patch='197' +run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive'] +command_passed: success_message='Passed tests' patch='197' +run_webkit_patch: ['land-attachment', '--force-clean', '--ignore-builders', '--non-interactive', '--parent-command=commit-queue', 197] +command_passed: success_message='Landed patch' patch='197' +""" + self._run_through_task(commit_queue, expected_stderr) + _double_flaky_test_counter = 0 def test_double_flaky_test_failure(self): diff --git a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py index 3b53d1a..996ab24 100644 --- a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py +++ b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py @@ -122,6 +122,7 @@ class EflEWS(AbstractEarlyWarningSystem): "leandro@profusion.mobi", "antognolli@profusion.mobi", "lucas.demarchi@profusion.mobi", + "gyuyoung.kim@samsung.com", ] diff --git a/Tools/Scripts/webkitpy/tool/commands/queues.py b/Tools/Scripts/webkitpy/tool/commands/queues.py index 42321cf..9e50dd4 100644 --- a/Tools/Scripts/webkitpy/tool/commands/queues.py +++ b/Tools/Scripts/webkitpy/tool/commands/queues.py @@ -323,10 +323,12 @@ class CommitQueue(AbstractPatchQueue, StepSequenceErrorHandler, CommitQueueTaskD results_name, _ = os.path.splitext(os.path.basename(results_directory)) # Note: We name the zip with the bug_id instead of patch_id to match work_item_log_path(). zip_path = self._tool.workspace.find_unused_filename(self._log_directory(), "%s-%s" % (patch.bug_id(), results_name), "zip") + if not zip_path: + return None archive = self._tool.workspace.create_zip(zip_path, results_directory) # Remove the results directory to prevent http logs, etc. from getting huge between runs. # We could have create_zip remove the original, but this is more explicit. - self._tool.filesystem.remove_tree(results_directory, ignore_errors=True) + self._tool.filesystem.rmtree(results_directory) return archive def refetch_patch(self, patch): diff --git a/Tools/Scripts/webkitpy/tool/main.py b/Tools/Scripts/webkitpy/tool/main.py index 76d5bef..6b07615 100755 --- a/Tools/Scripts/webkitpy/tool/main.py +++ b/Tools/Scripts/webkitpy/tool/main.py @@ -36,6 +36,7 @@ import threading from webkitpy.common.checkout.api import Checkout from webkitpy.common.checkout.scm import default_scm from webkitpy.common.config.ports import WebKitPort +from webkitpy.common.host import Host from webkitpy.common.net.bugzilla import Bugzilla from webkitpy.common.net.buildbot import BuildBot from webkitpy.common.net.irc.ircproxy import IRCProxy @@ -46,7 +47,7 @@ from webkitpy.tool.multicommandtool import MultiCommandTool import webkitpy.tool.commands as commands -class WebKitPatch(MultiCommandTool): +class WebKitPatch(MultiCommandTool, Host): global_options = [ make_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="enable all logging"), make_option("-d", "--directory", action="append", dest="patch_directories", default=[], help="Directory to look at for changed files"), @@ -59,58 +60,14 @@ class WebKitPatch(MultiCommandTool): def __init__(self, path): MultiCommandTool.__init__(self) + Host.__init__(self) self._path = path self.wakeup_event = threading.Event() - # FIXME: All of these shared objects should move off onto a - # separate "Tool" object. WebKitPatch should inherit from - # "Tool" and all these objects should use getters/setters instead of - # manual getter functions (e.g. scm()). - self.bugs = Bugzilla() - self.buildbot = BuildBot() - self.executive = executive.Executive() - self._irc = None - self.filesystem = filesystem.FileSystem() - self.workspace = workspace.Workspace(self.filesystem, self.executive) - self._port = None - self.user = user.User() - self._scm = None - self._checkout = None - self.status_server = StatusServer() - self.port_factory = port.factory - self.platform = platforminfo.PlatformInfo() - - def scm(self): - # Lazily initialize SCM to not error-out before command line parsing (or when running non-scm commands). - if not self._scm: - self._scm = default_scm(self._options.patch_directories) - return self._scm - - def checkout(self): - if not self._checkout: - self._checkout = Checkout(self.scm()) - return self._checkout - - def port(self): - return self._port - - def ensure_irc_connected(self, irc_delegate): - if not self._irc: - self._irc = IRCProxy(irc_delegate) - - def irc(self): - # We don't automatically construct IRCProxy here because constructing - # IRCProxy actually connects to IRC. We want clients to explicitly - # connect to IRC. - return self._irc def path(self): return self._path - def command_completed(self): - if self._irc: - self._irc.disconnect() - def should_show_in_main_help(self, command): if not command.show_in_main_help: return False @@ -120,7 +77,7 @@ class WebKitPatch(MultiCommandTool): # FIXME: This may be unnecessary since we pass global options to all commands during execute() as well. def handle_global_options(self, options): - self._options = options + self._initialize_scm(options.patch_directories) if options.dry_run: self.scm().dryrun = True self.bugs.dryrun = True diff --git a/Tools/WebKitAPITest/HostWindow.h b/Tools/WebKitAPITest/HostWindow.h index a2734ed..2aaa85f 100644 --- a/Tools/WebKitAPITest/HostWindow.h +++ b/Tools/WebKitAPITest/HostWindow.h @@ -30,7 +30,8 @@ namespace WebKitAPITest { -class HostWindow : public Noncopyable { +class HostWindow { + WTF_MAKE_NONCOPYABLE(HostWindow); public: HostWindow(); ~HostWindow(); diff --git a/Tools/WebKitAPITest/TestsController.h b/Tools/WebKitAPITest/TestsController.h index 11b457d..bdcc455 100644 --- a/Tools/WebKitAPITest/TestsController.h +++ b/Tools/WebKitAPITest/TestsController.h @@ -28,13 +28,13 @@ #include <windows.h> #include <wtf/Forward.h> #include <wtf/Deque.h> -#include <wtf/Noncopyable.h> namespace WebKitAPITest { class Test; -class TestsController : public Noncopyable { +class TestsController { + WTF_MAKE_NONCOPYABLE(TestsController); public: static TestsController& shared(); diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm b/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm index 0de2fd0..2f5c66f 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm +++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm @@ -256,6 +256,10 @@ EOF $self->_includeHeaders(\%contentsIncludes, $function->signature->type, $function->signature); + if ($function->signature->extendedAttributes->{"PassContext"}) { + push(@parameters, "context"); + } + foreach my $i (0..$#specifiedParameters) { my $parameter = $specifiedParameters[$i]; diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl index acc2f47..a88a838 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl +++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl @@ -76,6 +76,9 @@ module WTR { // Text search testing. boolean findString(in DOMString target, in object optionsArray); + + // Evaluating script in a special context + [PassContext] void evaluateScriptInIsolatedWorld(in unsigned long worldID, in DOMString script) }; } diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp index 999ca3a..972a606 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp @@ -47,6 +47,7 @@ InjectedBundle& InjectedBundle::shared() InjectedBundle::InjectedBundle() : m_bundle(0) + , m_topLoadingFrame(0) , m_state(Idle) { } @@ -161,6 +162,7 @@ void InjectedBundle::done() m_state = Stopping; page()->stopLoading(); + setTopLoadingFrame(0); WKRetainPtr<WKStringRef> doneMessageName(AdoptWK, WKStringCreateWithUTF8CString("Done")); WKRetainPtr<WKStringRef> doneMessageBody(AdoptWK, WKStringCreateWithUTF8CString(m_outputStream.str().c_str())); diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h index c1d8b37..9778441 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h @@ -65,6 +65,9 @@ public: bool isTestRunning() { return m_state == Testing; } + WKBundleFrameRef topLoadingFrame() { return m_topLoadingFrame; } + void setTopLoadingFrame(WKBundleFrameRef frame) { m_topLoadingFrame = frame; } + private: InjectedBundle(); ~InjectedBundle(); @@ -89,6 +92,8 @@ private: RefPtr<GCController> m_gcController; RefPtr<EventSendingController> m_eventSendingController; + WKBundleFrameRef m_topLoadingFrame; + std::ostringstream m_outputStream; enum State { diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp index 4bcb3c8..c5f4909 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp @@ -168,7 +168,6 @@ static ostream& operator<<(ostream& out, WKBundleFrameRef frame) InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page) : m_page(page) , m_world(AdoptWK, WKBundleScriptWorldCreateWorld()) - , m_isLoading(false) { WKBundlePageLoaderClient loaderClient = { 0, @@ -233,7 +232,6 @@ InjectedBundlePage::~InjectedBundlePage() void InjectedBundlePage::stopLoading() { WKBundlePageStopLoading(m_page); - m_isLoading = false; } void InjectedBundlePage::reset() @@ -334,8 +332,9 @@ void InjectedBundlePage::didStartProvisionalLoadForFrame(WKBundleFrameRef frame) if (!InjectedBundle::shared().isTestRunning()) return; - if (frame == WKBundlePageGetMainFrame(m_page)) - m_isLoading = true; + if (InjectedBundle::shared().topLoadingFrame()) + return; + InjectedBundle::shared().setTopLoadingFrame(frame); } void InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame(WKBundleFrameRef frame) @@ -344,6 +343,17 @@ void InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame(WKBu void InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef error) { + if (!InjectedBundle::shared().isTestRunning()) + return; + + if (frame != InjectedBundle::shared().topLoadingFrame()) + return; + InjectedBundle::shared().setTopLoadingFrame(0); + + if (InjectedBundle::shared().layoutTestController()->waitToDump()) + return; + + InjectedBundle::shared().done(); } void InjectedBundlePage::didCommitLoadForFrame(WKBundleFrameRef frame) @@ -475,18 +485,14 @@ void InjectedBundlePage::didFinishLoadForFrame(WKBundleFrameRef frame) if (!InjectedBundle::shared().isTestRunning()) return; - if (!WKBundleFrameIsMainFrame(frame)) - return; - - m_isLoading = false; - - if (this != InjectedBundle::shared().page()) + if (frame != InjectedBundle::shared().topLoadingFrame()) return; + InjectedBundle::shared().setTopLoadingFrame(0); if (InjectedBundle::shared().layoutTestController()->waitToDump()) return; - dump(); + InjectedBundle::shared().page()->dump(); } void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef) @@ -494,12 +500,11 @@ void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundleFrameRef frame, WK if (!InjectedBundle::shared().isTestRunning()) return; - if (!WKBundleFrameIsMainFrame(frame)) + if (frame != InjectedBundle::shared().topLoadingFrame()) return; + InjectedBundle::shared().setTopLoadingFrame(0); - m_isLoading = false; - - if (this != InjectedBundle::shared().page()) + if (InjectedBundle::shared().layoutTestController()->waitToDump()) return; InjectedBundle::shared().done(); @@ -521,12 +526,14 @@ void InjectedBundlePage::didClearWindowForFrame(WKBundleFrameRef frame, WKBundle if (!InjectedBundle::shared().isTestRunning()) return; - if (WKBundleScriptWorldNormalWorld() != world) - return; - JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world); JSObjectRef window = JSContextGetGlobalObject(context); + if (WKBundleScriptWorldNormalWorld() != world) { + JSObjectSetProperty(context, window, toJS("__worldID").get(), JSValueMakeNumber(context, LayoutTestController::worldIDForWorld(world)), kJSPropertyAttributeReadOnly, 0); + return; + } + JSValueRef exception = 0; InjectedBundle::shared().layoutTestController()->makeWindowObject(context, window, &exception); InjectedBundle::shared().gcController()->makeWindowObject(context, window, &exception); diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h index e9462df..3b99109 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h +++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h @@ -41,7 +41,6 @@ public: void dump(); void stopLoading(); - bool isLoading() { return m_isLoading; } void reset(); @@ -124,7 +123,6 @@ private: WKBundlePageRef m_page; WKRetainPtr<WKBundleScriptWorldRef> m_world; WKRetainPtr<WKBundleBackForwardListItemRef> m_previousTestBackForwardListItem; - bool m_isLoading; }; } // namespace WTR diff --git a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp index aa3dbf4..13c7b10 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp +++ b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp @@ -37,6 +37,7 @@ #include <WebKit2/WKBundlePrivate.h> #include <WebKit2/WKRetainPtr.h> #include <WebKit2/WebKit2.h> +#include <wtf/HashMap.h> namespace WTR { @@ -132,8 +133,9 @@ void LayoutTestController::notifyDone() if (!InjectedBundle::shared().isTestRunning()) return; - if (m_waitToDump && !InjectedBundle::shared().page()->isLoading()) + if (m_waitToDump && !InjectedBundle::shared().topLoadingFrame()) InjectedBundle::shared().page()->dump(); + m_waitToDump = false; } @@ -307,4 +309,44 @@ void LayoutTestController::makeWindowObject(JSContextRef context, JSObjectRef wi setProperty(context, windowObject, "layoutTestController", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception); } +typedef WTF::HashMap<unsigned, WKRetainPtr<WKBundleScriptWorldRef> > WorldMap; +static WorldMap& worldMap() +{ + static WorldMap& map = *new WorldMap; + return map; +} + +unsigned LayoutTestController::worldIDForWorld(WKBundleScriptWorldRef world) +{ + WorldMap::const_iterator end = worldMap().end(); + for (WorldMap::const_iterator it = worldMap().begin(); it != end; ++it) { + if (it->second == world) + return it->first; + } + + return 0; +} + +void LayoutTestController::evaluateScriptInIsolatedWorld(JSContextRef context, unsigned worldID, JSStringRef script) +{ + // A worldID of 0 always corresponds to a new world. Any other worldID corresponds to a world + // that is created once and cached forever. + WKRetainPtr<WKBundleScriptWorldRef> world; + if (!worldID) + world.adopt(WKBundleScriptWorldCreateWorld()); + else { + WKRetainPtr<WKBundleScriptWorldRef>& worldSlot = worldMap().add(worldID, 0).first->second; + if (!worldSlot) + worldSlot.adopt(WKBundleScriptWorldCreateWorld()); + world = worldSlot; + } + + WKBundleFrameRef frame = WKBundleFrameForJavaScriptContext(context); + if (!frame) + frame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page()); + + JSGlobalContextRef jsContext = WKBundleFrameGetJavaScriptContextForWorld(frame, world.get()); + JSEvaluateScript(jsContext, script, 0, 0, 0, 0); +} + } // namespace WTR diff --git a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h index 2aaad08..1f81970 100644 --- a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h +++ b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h @@ -28,6 +28,7 @@ #include "JSWrappable.h" #include <JavaScriptCore/JSRetainPtr.h> +#include <WebKit2/WKBundleScriptWorld.h> #include <string> #include <wtf/PassRefPtr.h> @@ -122,6 +123,9 @@ public: bool shouldCloseExtraWindowsAfterRunningTest() const { return m_shouldCloseExtraWindows; } + void evaluateScriptInIsolatedWorld(JSContextRef, unsigned worldID, JSStringRef script); + static unsigned worldIDForWorld(WKBundleScriptWorldRef); + private: static const double waitToDumpWatchdogTimerInterval; diff --git a/Tools/WebKitTestRunner/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp index 699982e..e856176 100644 --- a/Tools/WebKitTestRunner/TestController.cpp +++ b/Tools/WebKitTestRunner/TestController.cpp @@ -103,6 +103,11 @@ static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKF return true; } +void TestController::runModal(WKPageRef page, const void* clientInfo) +{ + runModal(static_cast<PlatformWebView*>(const_cast<void*>(clientInfo))); +} + static void closeOtherPage(WKPageRef page, const void* clientInfo) { WKPageClose(page); @@ -110,7 +115,7 @@ static void closeOtherPage(WKPageRef page, const void* clientInfo) delete view; } -static WKPageRef createOtherPage(WKPageRef oldPage, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void*) +WKPageRef TestController::createOtherPage(WKPageRef oldPage, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void*) { PlatformWebView* view = new PlatformWebView(WKPageGetContext(oldPage), WKPageGetPageGroup(oldPage)); WKPageRef newPage = view->page(); @@ -146,6 +151,12 @@ static WKPageRef createOtherPage(WKPageRef oldPage, WKDictionaryRef, WKEventModi 0, // exceededDatabaseQuota 0, // runOpenPanel 0, // decidePolicyForGeolocationPermissionRequest + 0, // headerHeight + 0, // footerHeight + 0, // drawHeader + 0, // drawFooter + 0, // printFrame + runModal, }; WKPageSetPageUIClient(newPage, &otherPageUIClient); @@ -251,6 +262,12 @@ void TestController::initialize(int argc, const char* argv[]) 0, // exceededDatabaseQuota 0, // runOpenPanel 0, // decidePolicyForGeolocationPermissionRequest + 0, // headerHeight + 0, // footerHeight + 0, // drawHeader + 0, // drawFooter + 0, // printFrame + 0, // runModal }; WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient); @@ -327,8 +344,11 @@ bool TestController::resetStateToConsistentValues() bool TestController::runTest(const char* test) { - if (!resetStateToConsistentValues()) + if (!resetStateToConsistentValues()) { + fputs("#CRASHED - WebProcess\n", stderr); + fflush(stderr); return false; + } m_state = RunningTest; m_currentInvocation.set(new TestInvocation(test)); @@ -386,6 +406,8 @@ void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody) { + if (!m_currentInvocation) + return; m_currentInvocation->didReceiveMessageFromInjectedBundle(messageName, messageBody); } diff --git a/Tools/WebKitTestRunner/TestController.h b/Tools/WebKitTestRunner/TestController.h index fc8bd30..65305a2 100644 --- a/Tools/WebKitTestRunner/TestController.h +++ b/Tools/WebKitTestRunner/TestController.h @@ -85,6 +85,10 @@ private: static void processDidCrash(WKPageRef, const void* clientInfo); void processDidCrash(WKPageRef); + static WKPageRef createOtherPage(WKPageRef oldPage, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void*); + + static void runModal(WKPageRef, const void* clientInfo); + static void runModal(PlatformWebView*); OwnPtr<TestInvocation> m_currentInvocation; diff --git a/Tools/WebKitTestRunner/TestInvocation.h b/Tools/WebKitTestRunner/TestInvocation.h index fec1f7a..efc6635 100644 --- a/Tools/WebKitTestRunner/TestInvocation.h +++ b/Tools/WebKitTestRunner/TestInvocation.h @@ -31,7 +31,8 @@ namespace WTR { -class TestInvocation : public Noncopyable { +class TestInvocation { + WTF_MAKE_NONCOPYABLE(TestInvocation); public: TestInvocation(const char*); ~TestInvocation(); diff --git a/Tools/WebKitTestRunner/mac/TestControllerMac.mm b/Tools/WebKitTestRunner/mac/TestControllerMac.mm index 6a4444f..8107890 100644 --- a/Tools/WebKitTestRunner/mac/TestControllerMac.mm +++ b/Tools/WebKitTestRunner/mac/TestControllerMac.mm @@ -25,6 +25,7 @@ #include "TestController.h" +#include "PlatformWebView.h" #include <WebKit2/WKStringCF.h> #include <mach-o/dyld.h> @@ -62,4 +63,12 @@ void TestController::platformInitializeContext() { } +void TestController::runModal(PlatformWebView* view) +{ + NSWindow *window = [view->platformView() window]; + if (!window) + return; + [NSApp runModalForWindow:window]; +} + } // namespace WTR diff --git a/Tools/WebKitTestRunner/qt/TestControllerQt.cpp b/Tools/WebKitTestRunner/qt/TestControllerQt.cpp index ca0a00c..df977fb 100644 --- a/Tools/WebKitTestRunner/qt/TestControllerQt.cpp +++ b/Tools/WebKitTestRunner/qt/TestControllerQt.cpp @@ -128,6 +128,11 @@ void TestController::platformInitializeContext() { } +void TestController::runModal(PlatformWebView*) +{ + // FIXME: Need to implement this to test showModalDialog. +} + #include "TestControllerQt.moc" } // namespace WTR diff --git a/Tools/WebKitTestRunner/win/TestControllerWin.cpp b/Tools/WebKitTestRunner/win/TestControllerWin.cpp index e562ada..08f188f 100644 --- a/Tools/WebKitTestRunner/win/TestControllerWin.cpp +++ b/Tools/WebKitTestRunner/win/TestControllerWin.cpp @@ -152,4 +152,9 @@ void TestController::platformInitializeContext() WKContextSetShouldPaintNativeControls(m_context.get(), false); } +void TestController::runModal(PlatformWebView*) +{ + // FIXME: Need to implement this to test showModalDialog. +} + } // namespace WTR |