Home | History | Annotate | Download | only in renderer
      1 // Copyright 2014 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 // Browser tests targeted at the RenderView that run in browser context.
      6 // Note that these tests rely on single-process mode, and hence may be
      7 // disabled in some configurations (check gyp files).
      8 
      9 #include "base/basictypes.h"
     10 #include "base/bind.h"
     11 #include "base/callback.h"
     12 #include "base/command_line.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "content/public/browser/browser_context.h"
     15 #include "content/public/browser/browser_thread.h"
     16 #include "content/public/browser/render_frame_host.h"
     17 #include "content/public/browser/render_process_host.h"
     18 #include "content/public/browser/web_contents.h"
     19 #include "content/public/common/content_switches.h"
     20 #include "content/public/renderer/render_view.h"
     21 #include "content/public/test/browser_test_utils.h"
     22 #include "content/public/test/content_browser_test.h"
     23 #include "content/public/test/content_browser_test_utils.h"
     24 #include "content/public/test/test_utils.h"
     25 #include "content/shell/browser/shell.h"
     26 #include "content/shell/browser/shell_browser_context.h"
     27 #include "content/shell/browser/shell_content_browser_client.h"
     28 #include "content/shell/common/shell_content_client.h"
     29 #include "content/shell/renderer/shell_content_renderer_client.h"
     30 #include "net/base/net_errors.h"
     31 #include "net/disk_cache/disk_cache.h"
     32 #include "net/http/failing_http_transaction_factory.h"
     33 #include "net/http/http_cache.h"
     34 #include "net/url_request/url_request_context.h"
     35 #include "net/url_request/url_request_context_getter.h"
     36 #include "testing/gtest/include/gtest/gtest.h"
     37 #include "third_party/WebKit/public/platform/WebURLError.h"
     38 #include "third_party/WebKit/public/platform/WebURLRequest.h"
     39 #include "third_party/WebKit/public/web/WebFrame.h"
     40 
     41 namespace content {
     42 
     43 namespace {
     44 
     45 class TestShellContentRendererClient : public ShellContentRendererClient {
     46  public:
     47   TestShellContentRendererClient()
     48       : latest_error_valid_(false),
     49         latest_error_reason_(0),
     50         latest_error_stale_copy_in_cache_(false) {}
     51 
     52   virtual void GetNavigationErrorStrings(
     53       content::RenderView* render_view,
     54       blink::WebFrame* frame,
     55       const blink::WebURLRequest& failed_request,
     56       const blink::WebURLError& error,
     57       std::string* error_html,
     58       base::string16* error_description) OVERRIDE {
     59     if (error_html)
     60       *error_html = "A suffusion of yellow.";
     61     latest_error_valid_ = true;
     62     latest_error_reason_ = error.reason;
     63     latest_error_stale_copy_in_cache_ = error.staleCopyInCache;
     64   }
     65 
     66   bool GetLatestError(int* error_code, bool* stale_cache_entry_present) {
     67     if (latest_error_valid_) {
     68       *error_code = latest_error_reason_;
     69       *stale_cache_entry_present = latest_error_stale_copy_in_cache_;
     70     }
     71     return latest_error_valid_;
     72   }
     73 
     74  private:
     75   bool latest_error_valid_;
     76   int latest_error_reason_;
     77   bool latest_error_stale_copy_in_cache_;
     78 };
     79 
     80 // Must be called on IO thread.
     81 void InterceptNetworkTransactions(net::URLRequestContextGetter* getter,
     82                                   net::Error error) {
     83   DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO));
     84   net::HttpCache* cache(
     85       getter->GetURLRequestContext()->http_transaction_factory()->GetCache());
     86   DCHECK(cache);
     87   scoped_ptr<net::FailingHttpTransactionFactory> factory(
     88       new net::FailingHttpTransactionFactory(cache->GetSession(), error));
     89   // Throw away old version; since this is a browser test, there is no
     90   // need to restore the old state.
     91   cache->SetHttpNetworkTransactionFactoryForTesting(
     92       factory.PassAs<net::HttpTransactionFactory>());
     93 }
     94 
     95 void CallOnUIThreadValidatingReturn(const base::Closure& callback,
     96                                     int rv) {
     97   DCHECK_EQ(net::OK, rv);
     98   BrowserThread::PostTask(
     99       BrowserThread::UI, FROM_HERE, callback);
    100 }
    101 
    102 // Must be called on IO thread.  The callback will be called on
    103 // completion of cache clearing on the UI thread.
    104 void BackendClearCache(scoped_ptr<disk_cache::Backend*> backend,
    105                        const base::Closure& callback,
    106                        int rv) {
    107   DCHECK(*backend);
    108   DCHECK_EQ(net::OK, rv);
    109   (*backend)->DoomAllEntries(
    110       base::Bind(&CallOnUIThreadValidatingReturn, callback));
    111 }
    112 
    113 // Must be called on IO thread.  The callback will be called on
    114 // completion of cache clearing on the UI thread.
    115 void ClearCache(net::URLRequestContextGetter* getter,
    116                 const base::Closure& callback) {
    117   DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO));
    118   net::HttpCache* cache(
    119       getter->GetURLRequestContext()->http_transaction_factory()->GetCache());
    120   DCHECK(cache);
    121   scoped_ptr<disk_cache::Backend*> backend(new disk_cache::Backend*);
    122   *backend = NULL;
    123   disk_cache::Backend** backend_ptr = backend.get();
    124 
    125   net::CompletionCallback backend_callback(
    126       base::Bind(&BackendClearCache, base::Passed(backend.Pass()), callback));
    127 
    128   // backend_ptr is valid until all copies of backend_callback go out
    129   // of scope.
    130   if (net::OK == cache->GetBackend(backend_ptr, backend_callback)) {
    131     // The call completed synchronously, so GetBackend didn't run the callback.
    132     backend_callback.Run(net::OK);
    133   }
    134 }
    135 
    136 }  // namespace
    137 
    138 class RenderViewBrowserTest : public ContentBrowserTest {
    139  public:
    140   RenderViewBrowserTest() {}
    141 
    142   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    143     // This method is needed to allow interaction with in-process renderer
    144     // and use of a test ContentRendererClient.
    145     command_line->AppendSwitch(switches::kSingleProcess);
    146   }
    147 
    148   virtual void SetUpOnMainThread() OVERRIDE {
    149     // Override setting of renderer client.
    150     renderer_client_ = new TestShellContentRendererClient();
    151     // Explicitly leaks ownership; this object will remain alive
    152     // until process death.  We don't deleted the returned value,
    153     // since some contexts set the pointer to a non-heap address.
    154     SetRendererClientForTesting(renderer_client_);
    155   }
    156 
    157   // Navigates to the given URL and waits for |num_navigations| to occur, and
    158   // the title to change to |expected_title|.
    159   void NavigateToURLAndWaitForTitle(const GURL& url,
    160                                     const std::string& expected_title,
    161                                     int num_navigations) {
    162     content::TitleWatcher title_watcher(
    163         shell()->web_contents(), base::ASCIIToUTF16(expected_title));
    164 
    165     content::NavigateToURLBlockUntilNavigationsComplete(
    166         shell(), url, num_navigations);
    167 
    168     EXPECT_EQ(base::ASCIIToUTF16(expected_title),
    169               title_watcher.WaitAndGetTitle());
    170   }
    171 
    172   // Returns true if there is a valid error stored; in this case
    173   // |*error_code| and |*stale_cache_entry_present| will be updated
    174   // appropriately.
    175   // Must be called after the renderer thread is created.
    176   bool GetLatestErrorFromRendererClient(
    177       int* error_code, bool* stale_cache_entry_present) {
    178     bool result = false;
    179 
    180     PostTaskToInProcessRendererAndWait(
    181         base::Bind(&RenderViewBrowserTest::GetLatestErrorFromRendererClient0,
    182                    renderer_client_, &result, error_code,
    183                    stale_cache_entry_present));
    184     return result;
    185   }
    186 
    187  private:
    188   // Must be run on renderer thread.
    189   static void GetLatestErrorFromRendererClient0(
    190       TestShellContentRendererClient* renderer_client,
    191       bool* result, int* error_code, bool* stale_cache_entry_present) {
    192     *result = renderer_client->GetLatestError(
    193         error_code, stale_cache_entry_present);
    194   }
    195 
    196   TestShellContentRendererClient* renderer_client_;
    197 };
    198 
    199 IN_PROC_BROWSER_TEST_F(RenderViewBrowserTest, ConfirmCacheInformationPlumbed) {
    200   ASSERT_TRUE(test_server()->Start());
    201 
    202   // Load URL with "nocache" set, to create stale cache.
    203   GURL test_url(test_server()->GetURL("files/nocache.html"));
    204   NavigateToURLAndWaitForTitle(test_url, "Nocache Test Page", 1);
    205 
    206   // Reload same URL after forcing an error from the the network layer;
    207   // confirm that the error page is told the cached copy exists.
    208   int renderer_id =
    209       shell()->web_contents()->GetMainFrame()->GetProcess()->GetID();
    210   scoped_refptr<net::URLRequestContextGetter> url_request_context_getter =
    211       ShellContentBrowserClient::Get()->browser_context()->
    212           GetRequestContextForRenderProcess(renderer_id);
    213   BrowserThread::PostTask(
    214       BrowserThread::IO, FROM_HERE,
    215       base::Bind(&InterceptNetworkTransactions, url_request_context_getter,
    216                  net::ERR_FAILED));
    217 
    218   // An error results in one completed navigation.
    219   NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
    220   int error_code = net::OK;
    221   bool stale_cache_entry_present = false;
    222   ASSERT_TRUE(GetLatestErrorFromRendererClient(
    223       &error_code, &stale_cache_entry_present));
    224   EXPECT_EQ(net::ERR_FAILED, error_code);
    225   EXPECT_TRUE(stale_cache_entry_present);
    226 
    227   // Clear the cache and repeat; confirm lack of entry in cache reported.
    228   scoped_refptr<MessageLoopRunner> runner = new MessageLoopRunner;
    229   BrowserThread::PostTask(
    230       BrowserThread::IO, FROM_HERE,
    231       base::Bind(&ClearCache, url_request_context_getter,
    232                  runner->QuitClosure()));
    233   runner->Run();
    234 
    235   content::NavigateToURLBlockUntilNavigationsComplete(shell(), test_url, 1);
    236 
    237   error_code = net::OK;
    238   stale_cache_entry_present = true;
    239   ASSERT_TRUE(GetLatestErrorFromRendererClient(
    240       &error_code, &stale_cache_entry_present));
    241   EXPECT_EQ(net::ERR_FAILED, error_code);
    242   EXPECT_FALSE(stale_cache_entry_present);
    243 }
    244 
    245 }  // namespace content
    246