Home | History | Annotate | Download | only in glue
      1 // Copyright (c) 2011 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 #include "webkit/glue/resource_fetcher.h"
      6 
      7 #include "base/callback.h"
      8 #include "base/message_loop.h"
      9 #include "base/timer.h"
     10 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
     11 #include "third_party/WebKit/Source/WebKit/chromium/public/WebURLResponse.h"
     12 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
     13 #include "webkit/glue/unittest_test_server.h"
     14 #include "webkit/tools/test_shell/simple_resource_loader_bridge.h"
     15 #include "webkit/tools/test_shell/test_shell_test.h"
     16 
     17 using WebKit::WebFrame;
     18 using WebKit::WebURLRequest;
     19 using WebKit::WebURLResponse;
     20 using webkit_glue::ResourceFetcher;
     21 using webkit_glue::ResourceFetcherWithTimeout;
     22 
     23 namespace {
     24 
     25 class ResourceFetcherTests : public TestShellTest {
     26  protected:
     27   UnittestTestServer test_server_;
     28 };
     29 
     30 static const int kMaxWaitTimeMs = 5000;
     31 
     32 class FetcherDelegate {
     33  public:
     34   FetcherDelegate()
     35       : completed_(false),
     36         timed_out_(false) {
     37     // Start a repeating timer waiting for the download to complete.  The
     38     // callback has to be a static function, so we hold on to our instance.
     39     FetcherDelegate::instance_ = this;
     40     StartTimer();
     41   }
     42 
     43   ResourceFetcher::Callback* NewCallback() {
     44     return ::NewCallback(this, &FetcherDelegate::OnURLFetchComplete);
     45   }
     46 
     47   virtual void OnURLFetchComplete(const WebURLResponse& response,
     48                                   const std::string& data) {
     49     response_ = response;
     50     data_ = data;
     51     completed_ = true;
     52     timer_.Stop();
     53     MessageLoop::current()->Quit();
     54   }
     55 
     56   bool completed() const { return completed_; }
     57   bool timed_out() const { return timed_out_; }
     58 
     59   std::string data() const { return data_; }
     60   const WebURLResponse& response() const { return response_; }
     61 
     62   // Wait for the request to complete or timeout.  We use a loop here b/c the
     63   // testing infrastructure (test_shell) can generate spurious calls to the
     64   // MessageLoop's Quit method.
     65   void WaitForResponse() {
     66     while (!completed() && !timed_out())
     67       MessageLoop::current()->Run();
     68   }
     69 
     70   void StartTimer() {
     71     timer_.Start(base::TimeDelta::FromMilliseconds(kMaxWaitTimeMs),
     72                  this,
     73                  &FetcherDelegate::TimerFired);
     74   }
     75 
     76   void TimerFired() {
     77     ASSERT_FALSE(completed_);
     78 
     79     timed_out_ = true;
     80     MessageLoop::current()->Quit();
     81     FAIL() << "fetch timed out";
     82   }
     83 
     84   static FetcherDelegate* instance_;
     85 
     86  private:
     87   base::OneShotTimer<FetcherDelegate> timer_;
     88   bool completed_;
     89   bool timed_out_;
     90   WebURLResponse response_;
     91   std::string data_;
     92 };
     93 
     94 FetcherDelegate* FetcherDelegate::instance_ = NULL;
     95 
     96 // Test a fetch from the test server.
     97 // Flaky, http://crbug.com/51622.
     98 TEST_F(ResourceFetcherTests, FLAKY_ResourceFetcherDownload) {
     99   ASSERT_TRUE(test_server_.Start());
    100 
    101   WebFrame* frame = test_shell_->webView()->mainFrame();
    102 
    103   GURL url(test_server_.GetURL("files/test_shell/index.html"));
    104   scoped_ptr<FetcherDelegate> delegate(new FetcherDelegate);
    105   scoped_ptr<ResourceFetcher> fetcher(new ResourceFetcher(
    106       url, frame, WebURLRequest::TargetIsMainFrame, delegate->NewCallback()));
    107 
    108   delegate->WaitForResponse();
    109 
    110   ASSERT_TRUE(delegate->completed());
    111   EXPECT_EQ(delegate->response().httpStatusCode(), 200);
    112   std::string text = delegate->data();
    113   EXPECT_TRUE(text.find("What is this page?") != std::string::npos);
    114 
    115   // Test 404 response.
    116   url = test_server_.GetURL("files/thisfiledoesntexist.html");
    117   delegate.reset(new FetcherDelegate);
    118   fetcher.reset(new ResourceFetcher(url, frame,
    119                                     WebURLRequest::TargetIsMainFrame,
    120                                     delegate->NewCallback()));
    121 
    122   delegate->WaitForResponse();
    123 
    124   ASSERT_TRUE(delegate->completed());
    125   EXPECT_EQ(delegate->response().httpStatusCode(), 404);
    126   EXPECT_TRUE(delegate->data().find("Not Found.") != std::string::npos);
    127 }
    128 
    129 // Flaky, http://crbug.com/51622.
    130 TEST_F(ResourceFetcherTests, FLAKY_ResourceFetcherDidFail) {
    131   ASSERT_TRUE(test_server_.Start());
    132 
    133   WebFrame* frame = test_shell_->webView()->mainFrame();
    134 
    135   // Try to fetch a page on a site that doesn't exist.
    136   GURL url("http://localhost:1339/doesnotexist");
    137   scoped_ptr<FetcherDelegate> delegate(new FetcherDelegate);
    138   scoped_ptr<ResourceFetcher> fetcher(new ResourceFetcher(
    139       url, frame, WebURLRequest::TargetIsMainFrame, delegate->NewCallback()));
    140 
    141   delegate->WaitForResponse();
    142 
    143   // When we fail, we still call the Delegate callback but we pass in empty
    144   // values.
    145   EXPECT_TRUE(delegate->completed());
    146   EXPECT_TRUE(delegate->response().isNull());
    147   EXPECT_EQ(delegate->data(), std::string());
    148   EXPECT_FALSE(delegate->timed_out());
    149 }
    150 
    151 TEST_F(ResourceFetcherTests, ResourceFetcherTimeout) {
    152   ASSERT_TRUE(test_server_.Start());
    153 
    154   WebFrame* frame = test_shell_->webView()->mainFrame();
    155 
    156   // Grab a page that takes at least 1 sec to respond, but set the fetcher to
    157   // timeout in 0 sec.
    158   GURL url(test_server_.GetURL("slow?1"));
    159   scoped_ptr<FetcherDelegate> delegate(new FetcherDelegate);
    160   scoped_ptr<ResourceFetcher> fetcher(new ResourceFetcherWithTimeout(
    161       url, frame, WebURLRequest::TargetIsMainFrame,
    162       0, delegate->NewCallback()));
    163 
    164   delegate->WaitForResponse();
    165 
    166   // When we timeout, we still call the Delegate callback but we pass in empty
    167   // values.
    168   EXPECT_TRUE(delegate->completed());
    169   EXPECT_TRUE(delegate->response().isNull());
    170   EXPECT_EQ(delegate->data(), std::string());
    171   EXPECT_FALSE(delegate->timed_out());
    172 }
    173 
    174 class EvilFetcherDelegate : public FetcherDelegate {
    175  public:
    176   void SetFetcher(ResourceFetcher* fetcher) {
    177     fetcher_.reset(fetcher);
    178   }
    179 
    180   void OnURLFetchComplete(const WebURLResponse& response,
    181                           const std::string& data) {
    182     // Destroy the ResourceFetcher here.  We are testing that upon returning
    183     // to the ResourceFetcher that it does not crash.
    184     fetcher_.reset();
    185     FetcherDelegate::OnURLFetchComplete(response, data);
    186   }
    187 
    188  private:
    189   scoped_ptr<ResourceFetcher> fetcher_;
    190 };
    191 
    192 TEST_F(ResourceFetcherTests, ResourceFetcherDeletedInCallback) {
    193   ASSERT_TRUE(test_server_.Start());
    194 
    195   WebFrame* frame = test_shell_->webView()->mainFrame();
    196 
    197   // Grab a page that takes at least 1 sec to respond, but set the fetcher to
    198   // timeout in 0 sec.
    199   GURL url(test_server_.GetURL("slow?1"));
    200   scoped_ptr<EvilFetcherDelegate> delegate(new EvilFetcherDelegate);
    201   scoped_ptr<ResourceFetcher> fetcher(new ResourceFetcherWithTimeout(
    202       url, frame, WebURLRequest::TargetIsMainFrame,
    203       0, delegate->NewCallback()));
    204   delegate->SetFetcher(fetcher.release());
    205 
    206   delegate->WaitForResponse();
    207   EXPECT_FALSE(delegate->timed_out());
    208 }
    209 
    210 }  // namespace
    211