• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
TestShellContentRendererClient()47   TestShellContentRendererClient()
48       : latest_error_valid_(false),
49         latest_error_reason_(0),
50         latest_error_stale_copy_in_cache_(false) {}
51 
GetNavigationErrorStrings(content::RenderView * render_view,blink::WebFrame * frame,const blink::WebURLRequest & failed_request,const blink::WebURLError & error,std::string * error_html,base::string16 * error_description)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 
GetLatestError(int * error_code,bool * stale_cache_entry_present)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.
InterceptNetworkTransactions(net::URLRequestContextGetter * getter,net::Error error)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 
CallOnUIThreadValidatingReturn(const base::Closure & callback,int rv)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.
BackendClearCache(scoped_ptr<disk_cache::Backend * > backend,const base::Closure & callback,int rv)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.
ClearCache(net::URLRequestContextGetter * getter,const base::Closure & callback)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:
RenderViewBrowserTest()140   RenderViewBrowserTest() {}
141 
SetUpCommandLine(CommandLine * command_line)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 
SetUpOnMainThread()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|.
NavigateToURLAndWaitForTitle(const GURL & url,const std::string & expected_title,int num_navigations)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.
GetLatestErrorFromRendererClient(int * error_code,bool * stale_cache_entry_present)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.
GetLatestErrorFromRendererClient0(TestShellContentRendererClient * renderer_client,bool * result,int * error_code,bool * stale_cache_entry_present)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 
IN_PROC_BROWSER_TEST_F(RenderViewBrowserTest,ConfirmCacheInformationPlumbed)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