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 "public/platform/Platform.h" 35 #include "public/platform/WebData.h" 36 #include "public/platform/WebString.h" 37 #include "public/platform/WebThread.h" 38 #include "public/platform/WebURLRequest.h" 39 #include "public/platform/WebURLResponse.h" 40 #include "public/platform/WebUnitTestSupport.h" 41 #include "public/web/WebSettings.h" 42 #include "public/web/WebViewClient.h" 43 #include "web/WebLocalFrameImpl.h" 44 #include "web/tests/URLTestHelpers.h" 45 #include "wtf/StdLibExtras.h" 46 47 namespace blink { 48 namespace FrameTestHelpers { 49 50 namespace { 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. 67 TestWebFrameClient* testClientForFrame(WebFrame* frame) 68 { 69 return static_cast<TestWebFrameClient*>(toWebLocalFrameImpl(frame)->client()); 70 } 71 72 class QuitTask : public WebThread::Task { 73 public: 74 void PostThis(WebCore::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 89 class ServeAsyncRequestsTask : public WebThread::Task { 90 public: 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 105 private: 106 TestWebFrameClient* const m_client; 107 }; 108 109 void pumpPendingRequests(WebFrame* frame) 110 { 111 Platform::current()->currentThread()->postTask(new ServeAsyncRequestsTask(testClientForFrame(frame))); 112 Platform::current()->currentThread()->enterRunLoop(); 113 } 114 115 class LoadTask : public WebThread::Task { 116 public: 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 128 private: 129 WebFrame* const m_frame; 130 const WebURLRequest m_request; 131 }; 132 133 class LoadHTMLStringTask : public WebThread::Task { 134 public: 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 147 private: 148 WebFrame* const m_frame; 149 const std::string m_html; 150 const WebURL m_baseURL; 151 }; 152 153 class LoadHistoryItemTask : public WebThread::Task { 154 public: 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 168 private: 169 WebFrame* const m_frame; 170 const WebHistoryItem m_item; 171 const WebHistoryLoadType m_loadType; 172 const WebURLRequest::CachePolicy m_cachePolicy; 173 }; 174 175 class ReloadTask : public WebThread::Task { 176 public: 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 188 private: 189 WebFrame* const m_frame; 190 const bool m_ignoreCache; 191 }; 192 193 TestWebFrameClient* defaultWebFrameClient() 194 { 195 DEFINE_STATIC_LOCAL(TestWebFrameClient, client, ()); 196 return &client; 197 } 198 199 WebViewClient* defaultWebViewClient() 200 { 201 DEFINE_STATIC_LOCAL(TestWebViewClient, client, ()); 202 return &client; 203 } 204 205 } // namespace 206 207 void 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 217 void 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 223 void 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 229 void reloadFrame(WebFrame* frame) 230 { 231 Platform::current()->currentThread()->postTask(new ReloadTask(frame, false)); 232 pumpPendingRequests(frame); 233 } 234 235 void reloadFrameIgnoringCache(WebFrame* frame) 236 { 237 Platform::current()->currentThread()->postTask(new ReloadTask(frame, true)); 238 pumpPendingRequests(frame); 239 } 240 241 void pumpPendingRequestsDoNotUse(WebFrame* frame) 242 { 243 pumpPendingRequests(frame); 244 } 245 246 // FIXME: There's a duplicate implementation in UnitTestHelpers.cpp. Remove one. 247 void runPendingTasks() 248 { 249 // Pending tasks include Timers that have been scheduled. 250 WebCore::Timer<QuitTask> quitOnTimeout(new QuitTask, &QuitTask::PostThis); 251 quitOnTimeout.startOneShot(0, FROM_HERE); 252 Platform::current()->currentThread()->enterRunLoop(); 253 } 254 255 WebViewHelper::WebViewHelper() 256 : m_webView(0) 257 { 258 } 259 260 WebViewHelper::~WebViewHelper() 261 { 262 reset(); 263 } 264 265 WebViewImpl* 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 285 WebViewImpl* 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 294 void 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 303 TestWebFrameClient::TestWebFrameClient() : m_loadsInProgress(0) 304 { 305 } 306 307 WebFrame* TestWebFrameClient::createChildFrame(WebLocalFrame* parent, const WebString& frameName) 308 { 309 WebFrame* frame = WebLocalFrame::create(this); 310 parent->appendChild(frame); 311 return frame; 312 } 313 314 void TestWebFrameClient::frameDetached(WebFrame* frame) 315 { 316 if (frame->parent()) 317 frame->parent()->removeChild(frame); 318 frame->close(); 319 } 320 321 void TestWebFrameClient::didStartLoading(bool) 322 { 323 ++m_loadsInProgress; 324 } 325 326 void TestWebFrameClient::didStopLoading() 327 { 328 ASSERT(m_loadsInProgress > 0); 329 --m_loadsInProgress; 330 } 331 332 void TestWebViewClient::initializeLayerTreeView() 333 { 334 m_layerTreeView = adoptPtr(Platform::current()->unitTestSupport()->createLayerTreeViewForTesting()); 335 ASSERT(m_layerTreeView); 336 } 337 338 } // namespace FrameTestHelpers 339 } // namespace blink 340