1/* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "web/tests/FrameTestHelpers.h" 33 34#include "core/testing/URLTestHelpers.h" 35#include "public/platform/Platform.h" 36#include "public/platform/WebData.h" 37#include "public/platform/WebString.h" 38#include "public/platform/WebThread.h" 39#include "public/platform/WebURLRequest.h" 40#include "public/platform/WebURLResponse.h" 41#include "public/platform/WebUnitTestSupport.h" 42#include "public/web/WebSettings.h" 43#include "public/web/WebViewClient.h" 44#include "web/WebLocalFrameImpl.h" 45#include "wtf/StdLibExtras.h" 46 47namespace blink { 48namespace FrameTestHelpers { 49 50namespace { 51 52// The frame test helpers coordinate frame loads in a carefully choreographed 53// dance. Since the parser is threaded, simply spinning the run loop once is not 54// enough to ensure completion of a load. Instead, the following pattern is 55// used to ensure that tests see the final state: 56// 1. Post a task to trigger a load (LoadTask/LoadHTMLStringTask/ReloadTask). 57// 2. Enter the run loop. 58// 3. Posted task triggers the load, and starts pumping pending resource 59// requests using ServeAsyncRequestsTask. 60// 4. TestWebFrameClient watches for didStartLoading/didStopLoading calls, 61// keeping track of how many loads it thinks are in flight. 62// 5. While ServeAsyncRequestsTask observes TestWebFrameClient to still have 63// loads in progress, it posts itself back to the run loop. 64// 6. When ServeAsyncRequestsTask notices there are no more loads in progress, 65// it exits the run loop. 66// 7. At this point, all parsing, resource loads, and layout should be finished. 67TestWebFrameClient* testClientForFrame(WebFrame* frame) 68{ 69 return static_cast<TestWebFrameClient*>(toWebLocalFrameImpl(frame)->client()); 70} 71 72class QuitTask : public WebThread::Task { 73public: 74 void PostThis(Timer<QuitTask>*) 75 { 76 // We don't just quit here because the SharedTimer may be part-way 77 // through the current queue of tasks when runPendingTasks was called, 78 // and we can't miss the tasks that were behind it. 79 // Takes ownership of |this|. 80 Platform::current()->currentThread()->postTask(this); 81 } 82 83 virtual void run() 84 { 85 Platform::current()->currentThread()->exitRunLoop(); 86 } 87}; 88 89class ServeAsyncRequestsTask : public WebThread::Task { 90public: 91 explicit ServeAsyncRequestsTask(TestWebFrameClient* client) 92 : m_client(client) 93 { 94 } 95 96 virtual void run() OVERRIDE 97 { 98 Platform::current()->unitTestSupport()->serveAsynchronousMockedRequests(); 99 if (m_client->isLoading()) 100 Platform::current()->currentThread()->postTask(new ServeAsyncRequestsTask(m_client)); 101 else 102 Platform::current()->currentThread()->exitRunLoop(); 103 } 104 105private: 106 TestWebFrameClient* const m_client; 107}; 108 109void pumpPendingRequests(WebFrame* frame) 110{ 111 Platform::current()->currentThread()->postTask(new ServeAsyncRequestsTask(testClientForFrame(frame))); 112 Platform::current()->currentThread()->enterRunLoop(); 113} 114 115class LoadTask : public WebThread::Task { 116public: 117 LoadTask(WebFrame* frame, const WebURLRequest& request) 118 : m_frame(frame) 119 , m_request(request) 120 { 121 } 122 123 virtual void run() OVERRIDE 124 { 125 m_frame->loadRequest(m_request); 126 } 127 128private: 129 WebFrame* const m_frame; 130 const WebURLRequest m_request; 131}; 132 133class LoadHTMLStringTask : public WebThread::Task { 134public: 135 LoadHTMLStringTask(WebFrame* frame, const std::string& html, const WebURL& baseURL) 136 : m_frame(frame) 137 , m_html(html) 138 , m_baseURL(baseURL) 139 { 140 } 141 142 virtual void run() OVERRIDE 143 { 144 m_frame->loadHTMLString(WebData(m_html.data(), m_html.size()), m_baseURL); 145 } 146 147private: 148 WebFrame* const m_frame; 149 const std::string m_html; 150 const WebURL m_baseURL; 151}; 152 153class LoadHistoryItemTask : public WebThread::Task { 154public: 155 LoadHistoryItemTask(WebFrame* frame, const WebHistoryItem& item, WebHistoryLoadType loadType, WebURLRequest::CachePolicy cachePolicy) 156 : m_frame(frame) 157 , m_item(item) 158 , m_loadType(loadType) 159 , m_cachePolicy(cachePolicy) 160 { 161 } 162 163 virtual void run() OVERRIDE 164 { 165 m_frame->loadHistoryItem(m_item, m_loadType, m_cachePolicy); 166 } 167 168private: 169 WebFrame* const m_frame; 170 const WebHistoryItem m_item; 171 const WebHistoryLoadType m_loadType; 172 const WebURLRequest::CachePolicy m_cachePolicy; 173}; 174 175class ReloadTask : public WebThread::Task { 176public: 177 ReloadTask(WebFrame* frame, bool ignoreCache) 178 : m_frame(frame) 179 , m_ignoreCache(ignoreCache) 180 { 181 } 182 183 virtual void run() OVERRIDE 184 { 185 m_frame->reload(m_ignoreCache); 186 } 187 188private: 189 WebFrame* const m_frame; 190 const bool m_ignoreCache; 191}; 192 193TestWebFrameClient* defaultWebFrameClient() 194{ 195 DEFINE_STATIC_LOCAL(TestWebFrameClient, client, ()); 196 return &client; 197} 198 199WebViewClient* defaultWebViewClient() 200{ 201 DEFINE_STATIC_LOCAL(TestWebViewClient, client, ()); 202 return &client; 203} 204 205} // namespace 206 207void loadFrame(WebFrame* frame, const std::string& url) 208{ 209 WebURLRequest urlRequest; 210 urlRequest.initialize(); 211 urlRequest.setURL(URLTestHelpers::toKURL(url)); 212 213 Platform::current()->currentThread()->postTask(new LoadTask(frame, urlRequest)); 214 pumpPendingRequests(frame); 215} 216 217void loadHTMLString(WebFrame* frame, const std::string& html, const WebURL& baseURL) 218{ 219 Platform::current()->currentThread()->postTask(new LoadHTMLStringTask(frame, html, baseURL)); 220 pumpPendingRequests(frame); 221} 222 223void loadHistoryItem(WebFrame* frame, const WebHistoryItem& item, WebHistoryLoadType loadType, WebURLRequest::CachePolicy cachePolicy) 224{ 225 Platform::current()->currentThread()->postTask(new LoadHistoryItemTask(frame, item, loadType, cachePolicy)); 226 pumpPendingRequests(frame); 227} 228 229void reloadFrame(WebFrame* frame) 230{ 231 Platform::current()->currentThread()->postTask(new ReloadTask(frame, false)); 232 pumpPendingRequests(frame); 233} 234 235void reloadFrameIgnoringCache(WebFrame* frame) 236{ 237 Platform::current()->currentThread()->postTask(new ReloadTask(frame, true)); 238 pumpPendingRequests(frame); 239} 240 241void pumpPendingRequestsDoNotUse(WebFrame* frame) 242{ 243 pumpPendingRequests(frame); 244} 245 246// FIXME: There's a duplicate implementation in UnitTestHelpers.cpp. Remove one. 247void runPendingTasks() 248{ 249 // Pending tasks include Timers that have been scheduled. 250 Timer<QuitTask> quitOnTimeout(new QuitTask, &QuitTask::PostThis); 251 quitOnTimeout.startOneShot(0, FROM_HERE); 252 Platform::current()->currentThread()->enterRunLoop(); 253} 254 255WebViewHelper::WebViewHelper() 256 : m_webView(0) 257{ 258} 259 260WebViewHelper::~WebViewHelper() 261{ 262 reset(); 263} 264 265WebViewImpl* WebViewHelper::initialize(bool enableJavascript, TestWebFrameClient* webFrameClient, WebViewClient* webViewClient, void (*updateSettingsFunc)(WebSettings*)) 266{ 267 reset(); 268 269 if (!webFrameClient) 270 webFrameClient = defaultWebFrameClient(); 271 if (!webViewClient) 272 webViewClient = defaultWebViewClient(); 273 m_webView = WebViewImpl::create(webViewClient); 274 m_webView->settings()->setJavaScriptEnabled(enableJavascript); 275 if (updateSettingsFunc) 276 updateSettingsFunc(m_webView->settings()); 277 else 278 m_webView->settings()->setDeviceSupportsMouse(false); 279 280 m_webView->setMainFrame(WebLocalFrameImpl::create(webFrameClient)); 281 282 return m_webView; 283} 284 285WebViewImpl* WebViewHelper::initializeAndLoad(const std::string& url, bool enableJavascript, TestWebFrameClient* webFrameClient, WebViewClient* webViewClient, void (*updateSettingsFunc)(WebSettings*)) 286{ 287 initialize(enableJavascript, webFrameClient, webViewClient, updateSettingsFunc); 288 289 loadFrame(webView()->mainFrame(), url); 290 291 return webViewImpl(); 292} 293 294void WebViewHelper::reset() 295{ 296 if (m_webView) { 297 ASSERT(!testClientForFrame(m_webView->mainFrame())->isLoading()); 298 m_webView->close(); 299 m_webView = 0; 300 } 301} 302 303TestWebFrameClient::TestWebFrameClient() : m_loadsInProgress(0) 304{ 305} 306 307WebFrame* TestWebFrameClient::createChildFrame(WebLocalFrame* parent, const WebString& frameName) 308{ 309 WebFrame* frame = WebLocalFrame::create(this); 310 parent->appendChild(frame); 311 return frame; 312} 313 314void TestWebFrameClient::frameDetached(WebFrame* frame) 315{ 316 if (frame->parent()) 317 frame->parent()->removeChild(frame); 318 frame->close(); 319} 320 321void TestWebFrameClient::didStartLoading(bool) 322{ 323 ++m_loadsInProgress; 324} 325 326void TestWebFrameClient::didStopLoading() 327{ 328 ASSERT(m_loadsInProgress > 0); 329 --m_loadsInProgress; 330} 331 332void TestWebViewClient::initializeLayerTreeView() 333{ 334 m_layerTreeView = adoptPtr(Platform::current()->unitTestSupport()->createLayerTreeViewForTesting()); 335 ASSERT(m_layerTreeView); 336} 337 338} // namespace FrameTestHelpers 339} // namespace blink 340