| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 // This file contains the definition for LayoutTestController. | |
| 6 | |
| 7 #include <vector> | |
| 8 | |
| 9 #include "webkit/tools/test_shell/layout_test_controller.h" | |
| 10 | |
| 11 #include "base/base64.h" | |
| 12 #include "base/basictypes.h" | |
| 13 #include "base/bind.h" | |
| 14 #include "base/bind_helpers.h" | |
| 15 #include "base/file_path.h" | |
| 16 #include "base/file_util.h" | |
| 17 #include "base/logging.h" | |
| 18 #include "base/message_loop.h" | |
| 19 #include "base/path_service.h" | |
| 20 #include "base/string_number_conversions.h" | |
| 21 #include "base/utf_string_conversions.h" | |
| 22 #include "net/base/net_util.h" | |
| 23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebAnimationControlle
r.h" | |
| 24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebBindings.h" | |
| 25 #include "third_party/WebKit/Source/WebKit/chromium/public/WebConsoleMessage.h" | |
| 26 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDeviceOrientation.
h" | |
| 27 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDeviceOrientationC
lientMock.h" | |
| 28 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" | |
| 29 #include "third_party/WebKit/Source/WebKit/chromium/public/WebElement.h" | |
| 30 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" | |
| 31 #include "third_party/WebKit/Source/WebKit/chromium/public/WebGeolocationClientM
ock.h" | |
| 32 #include "third_party/WebKit/Source/WebKit/chromium/public/WebKit.h" | |
| 33 #include "third_party/WebKit/Source/WebKit/chromium/public/WebScriptSource.h" | |
| 34 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityPolicy.h" | |
| 35 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSettings.h" | |
| 36 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h" | |
| 37 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURL.h" | |
| 38 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | |
| 39 #include "webkit/glue/dom_operations.h" | |
| 40 #include "webkit/glue/webkit_glue.h" | |
| 41 #include "webkit/glue/webpreferences.h" | |
| 42 #include "webkit/support/simple_database_system.h" | |
| 43 #include "webkit/tools/test_shell/notification_presenter.h" | |
| 44 #include "webkit/tools/test_shell/simple_resource_loader_bridge.h" | |
| 45 #include "webkit/tools/test_shell/test_navigation_controller.h" | |
| 46 #include "webkit/tools/test_shell/test_shell.h" | |
| 47 #include "webkit/tools/test_shell/test_shell_devtools_agent.h" | |
| 48 #include "webkit/tools/test_shell/test_webview_delegate.h" | |
| 49 | |
| 50 using std::string; | |
| 51 | |
| 52 using WebKit::WebBindings; | |
| 53 using WebKit::WebConsoleMessage; | |
| 54 using WebKit::WebElement; | |
| 55 using WebKit::WebScriptSource; | |
| 56 using WebKit::WebSecurityPolicy; | |
| 57 using WebKit::WebSize; | |
| 58 using WebKit::WebString; | |
| 59 using WebKit::WebURL; | |
| 60 using webkit_glue::CppArgumentList; | |
| 61 using webkit_glue::CppVariant; | |
| 62 | |
| 63 TestShell* LayoutTestController::shell_ = NULL; | |
| 64 // Most of these flags need to be cleared in Reset() so that they get turned | |
| 65 // off between each test run. | |
| 66 bool LayoutTestController::accepts_editing_ = true; | |
| 67 bool LayoutTestController::wait_until_done_ = false; | |
| 68 bool LayoutTestController::can_open_windows_ = false; | |
| 69 bool LayoutTestController::close_remaining_windows_ = true; | |
| 70 bool LayoutTestController::stop_provisional_frame_loads_ = false; | |
| 71 LayoutTestController::WorkQueue LayoutTestController::work_queue_; | |
| 72 | |
| 73 LayoutTestController::LayoutTestController(TestShell* shell) : | |
| 74 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | |
| 75 // Set static shell_ variable since we can't do it in an initializer list. | |
| 76 // We also need to be careful not to assign shell_ to new windows which are | |
| 77 // temporary. | |
| 78 if (NULL == shell_) | |
| 79 shell_ = shell; | |
| 80 | |
| 81 // Initialize the map that associates methods of this class with the names | |
| 82 // they will use when called by JavaScript. The actual binding of those | |
| 83 // names to their methods will be done by calling BindToJavaScript() (defined | |
| 84 // by CppBoundClass, the parent to LayoutTestController). | |
| 85 BindCallback("waitUntilDone", | |
| 86 base::Bind(&LayoutTestController::waitUntilDone, | |
| 87 base::Unretained(this))); | |
| 88 BindCallback("notifyDone", | |
| 89 base::Bind(&LayoutTestController::notifyDone, | |
| 90 base::Unretained(this))); | |
| 91 | |
| 92 // The fallback method is called when an unknown method is invoked. | |
| 93 BindFallbackCallback(base::Bind(&LayoutTestController::fallbackMethod, | |
| 94 base::Unretained(this))); | |
| 95 } | |
| 96 | |
| 97 LayoutTestController::~LayoutTestController() { | |
| 98 } | |
| 99 | |
| 100 LayoutTestController::WorkQueue::WorkQueue() { | |
| 101 } | |
| 102 | |
| 103 LayoutTestController::WorkQueue::~WorkQueue() { | |
| 104 Reset(); | |
| 105 } | |
| 106 | |
| 107 void LayoutTestController::WorkQueue::ProcessWorkSoon() { | |
| 108 if (shell_->delegate()->top_loading_frame()) | |
| 109 return; | |
| 110 | |
| 111 if (!queue_.empty()) { | |
| 112 // We delay processing queued work to avoid recursion problems. | |
| 113 timer_.Start(FROM_HERE, base::TimeDelta(), this, &WorkQueue::ProcessWork); | |
| 114 } else if (!wait_until_done_) { | |
| 115 shell_->TestFinished(); | |
| 116 } | |
| 117 } | |
| 118 | |
| 119 void LayoutTestController::WorkQueue::ProcessWork() { | |
| 120 // Quit doing work once a load is in progress. | |
| 121 while (!queue_.empty()) { | |
| 122 bool started_load = queue_.front()->Run(shell_); | |
| 123 delete queue_.front(); | |
| 124 queue_.pop(); | |
| 125 | |
| 126 if (started_load) | |
| 127 return; | |
| 128 } | |
| 129 | |
| 130 if (!wait_until_done_ && !shell_->delegate()->top_loading_frame()) | |
| 131 shell_->TestFinished(); | |
| 132 } | |
| 133 | |
| 134 void LayoutTestController::WorkQueue::Reset() { | |
| 135 frozen_ = false; | |
| 136 while (!queue_.empty()) { | |
| 137 delete queue_.front(); | |
| 138 queue_.pop(); | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 void LayoutTestController::WorkQueue::AddWork(WorkItem* work) { | |
| 143 if (frozen_) { | |
| 144 delete work; | |
| 145 return; | |
| 146 } | |
| 147 queue_.push(work); | |
| 148 } | |
| 149 | |
| 150 void LayoutTestController::waitUntilDone( | |
| 151 const CppArgumentList& args, CppVariant* result) { | |
| 152 bool is_debugger_present = false; | |
| 153 #if defined(OS_WIN) | |
| 154 // TODO(ojan): Make cross-platform. | |
| 155 is_debugger_present = ::IsDebuggerPresent(); | |
| 156 #endif | |
| 157 | |
| 158 if (!is_debugger_present) { | |
| 159 // TODO(ojan): Use base::OneShotTimer. For some reason, using OneShotTimer | |
| 160 // seems to cause layout test failures on the try bots. | |
| 161 MessageLoop::current()->PostDelayedTask( | |
| 162 FROM_HERE, | |
| 163 base::Bind(&LayoutTestController::notifyDoneTimedOut, | |
| 164 weak_factory_.GetWeakPtr()), | |
| 165 base::TimeDelta::FromMilliseconds(shell_->GetLayoutTestTimeout())); | |
| 166 } | |
| 167 | |
| 168 wait_until_done_ = true; | |
| 169 result->SetNull(); | |
| 170 } | |
| 171 | |
| 172 void LayoutTestController::notifyDone( | |
| 173 const CppArgumentList& args, CppVariant* result) { | |
| 174 // Test didn't timeout. Kill the timeout timer. | |
| 175 weak_factory_.InvalidateWeakPtrs(); | |
| 176 | |
| 177 completeNotifyDone(false); | |
| 178 result->SetNull(); | |
| 179 } | |
| 180 | |
| 181 void LayoutTestController::notifyDoneTimedOut() { | |
| 182 completeNotifyDone(true); | |
| 183 } | |
| 184 | |
| 185 void LayoutTestController::completeNotifyDone(bool is_timeout) { | |
| 186 if (shell_->layout_test_mode() && wait_until_done_ && | |
| 187 !shell_->delegate()->top_loading_frame() && work_queue_.empty()) { | |
| 188 if (is_timeout) | |
| 189 shell_->TestTimedOut(); | |
| 190 else | |
| 191 shell_->TestFinished(); | |
| 192 } | |
| 193 wait_until_done_ = false; | |
| 194 } | |
| 195 | |
| 196 void LayoutTestController::Reset() { | |
| 197 if (shell_) { | |
| 198 shell_->webView()->setZoomLevel(false, 0); | |
| 199 shell_->webView()->setTabKeyCyclesThroughElements(true); | |
| 200 #if defined(TOOLKIT_GTK) | |
| 201 // (Constants copied because we can't depend on the header that defined | |
| 202 // them from this file.) | |
| 203 shell_->webView()->setSelectionColors( | |
| 204 0xff1e90ff, 0xff000000, 0xffc8c8c8, 0xff323232); | |
| 205 #endif // defined(TOOLKIT_GTK) | |
| 206 shell_->webView()->removeAllUserContent(); | |
| 207 | |
| 208 // Reset editingBehavior to a reasonable default between tests | |
| 209 // see http://trac.webkit.org/changeset/60158 | |
| 210 #if defined(OS_MACOSX) | |
| 211 shell_->webView()->settings()->setEditingBehavior( | |
| 212 WebKit::WebSettings::EditingBehaviorMac); | |
| 213 #else | |
| 214 shell_->webView()->settings()->setEditingBehavior( | |
| 215 WebKit::WebSettings::EditingBehaviorWin); | |
| 216 #endif | |
| 217 } | |
| 218 accepts_editing_ = true; | |
| 219 wait_until_done_ = false; | |
| 220 can_open_windows_ = false; | |
| 221 stop_provisional_frame_loads_ = false; | |
| 222 | |
| 223 SimpleResourceLoaderBridge::SetAcceptAllCookies(false); | |
| 224 WebSecurityPolicy::resetOriginAccessWhitelists(); | |
| 225 | |
| 226 // Reset the default quota for each origin to 5MB | |
| 227 SimpleDatabaseSystem::GetInstance()->SetDatabaseQuota(5 * 1024 * 1024); | |
| 228 | |
| 229 setlocale(LC_ALL, ""); | |
| 230 | |
| 231 if (close_remaining_windows_) { | |
| 232 // Iterate through the window list and close everything except the original | |
| 233 // shell. We don't want to delete elements as we're iterating, so we copy | |
| 234 // to a temp vector first. | |
| 235 WindowList* windows = TestShell::windowList(); | |
| 236 std::vector<gfx::NativeWindow> windows_to_delete; | |
| 237 for (WindowList::iterator i = windows->begin(); i != windows->end(); ++i) { | |
| 238 if (*i != shell_->mainWnd()) | |
| 239 windows_to_delete.push_back(*i); | |
| 240 } | |
| 241 DCHECK(windows_to_delete.size() + 1 == windows->size()); | |
| 242 for (size_t i = 0; i < windows_to_delete.size(); ++i) { | |
| 243 TestShell::DestroyWindow(windows_to_delete[i]); | |
| 244 } | |
| 245 DCHECK(windows->size() == 1); | |
| 246 } else { | |
| 247 // Reset the value | |
| 248 close_remaining_windows_ = true; | |
| 249 } | |
| 250 work_queue_.Reset(); | |
| 251 } | |
| 252 | |
| 253 void LayoutTestController::LocationChangeDone() { | |
| 254 // no more new work after the first complete load. | |
| 255 work_queue_.set_frozen(true); | |
| 256 | |
| 257 if (!wait_until_done_) | |
| 258 work_queue_.ProcessWorkSoon(); | |
| 259 } | |
| 260 | |
| 261 void LayoutTestController::PolicyDelegateDone() { | |
| 262 if (!shell_->layout_test_mode()) | |
| 263 return; | |
| 264 | |
| 265 DCHECK(wait_until_done_); | |
| 266 shell_->TestFinished(); | |
| 267 wait_until_done_ = false; | |
| 268 } | |
| 269 | |
| 270 void LayoutTestController::fallbackMethod( | |
| 271 const CppArgumentList& args, CppVariant* result) { | |
| 272 std::string message( | |
| 273 "JavaScript ERROR: unknown method called on LayoutTestController"); | |
| 274 if (!shell_->layout_test_mode()) { | |
| 275 logging::LogMessage("CONSOLE:", 0).stream() << message; | |
| 276 } else { | |
| 277 printf("CONSOLE MESSAGE: %s\n", message.c_str()); | |
| 278 } | |
| 279 result->SetNull(); | |
| 280 } | |
| 281 | |
| 282 void LayoutTestController::LogErrorToConsole(const std::string& text) { | |
| 283 shell_->delegate()->didAddMessageToConsole( | |
| 284 WebConsoleMessage(WebConsoleMessage::LevelError, | |
| 285 WebString::fromUTF8(text)), | |
| 286 WebString(), 0); | |
| 287 } | |
| OLD | NEW |