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.
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).
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"
45 class TestShellContentRendererClient
: public ShellContentRendererClient
{
47 TestShellContentRendererClient()
48 : latest_error_valid_(false),
49 latest_error_reason_(0),
50 latest_error_stale_copy_in_cache_(false) {}
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
{
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
;
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_
;
71 return latest_error_valid_
;
75 bool latest_error_valid_
;
76 int latest_error_reason_
;
77 bool latest_error_stale_copy_in_cache_
;
80 // Must be called on IO thread.
81 void InterceptNetworkTransactions(net::URLRequestContextGetter
* getter
,
83 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO
));
84 net::HttpCache
* cache(
85 getter
->GetURLRequestContext()->http_transaction_factory()->GetCache());
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(factory
.Pass());
94 void CallOnUIThreadValidatingReturn(const base::Closure
& callback
,
96 DCHECK_EQ(net::OK
, rv
);
97 BrowserThread::PostTask(
98 BrowserThread::UI
, FROM_HERE
, callback
);
101 // Must be called on IO thread. The callback will be called on
102 // completion of cache clearing on the UI thread.
103 void BackendClearCache(scoped_ptr
<disk_cache::Backend
*> backend
,
104 const base::Closure
& callback
,
107 DCHECK_EQ(net::OK
, rv
);
108 (*backend
)->DoomAllEntries(
109 base::Bind(&CallOnUIThreadValidatingReturn
, callback
));
112 // Must be called on IO thread. The callback will be called on
113 // completion of cache clearing on the UI thread.
114 void ClearCache(net::URLRequestContextGetter
* getter
,
115 const base::Closure
& callback
) {
116 DCHECK(content::BrowserThread::CurrentlyOn(BrowserThread::IO
));
117 net::HttpCache
* cache(
118 getter
->GetURLRequestContext()->http_transaction_factory()->GetCache());
120 scoped_ptr
<disk_cache::Backend
*> backend(new disk_cache::Backend
*);
122 disk_cache::Backend
** backend_ptr
= backend
.get();
124 net::CompletionCallback
backend_callback(
125 base::Bind(&BackendClearCache
, base::Passed(backend
.Pass()), callback
));
127 // backend_ptr is valid until all copies of backend_callback go out
129 if (net::OK
== cache
->GetBackend(backend_ptr
, backend_callback
)) {
130 // The call completed synchronously, so GetBackend didn't run the callback.
131 backend_callback
.Run(net::OK
);
137 class RenderViewBrowserTest
: public ContentBrowserTest
{
139 RenderViewBrowserTest() {}
141 virtual void SetUpCommandLine(CommandLine
* command_line
) override
{
142 // This method is needed to allow interaction with in-process renderer
143 // and use of a test ContentRendererClient.
144 command_line
->AppendSwitch(switches::kSingleProcess
);
147 virtual void SetUpOnMainThread() override
{
148 // Override setting of renderer client.
149 renderer_client_
= new TestShellContentRendererClient();
150 // Explicitly leaks ownership; this object will remain alive
151 // until process death. We don't deleted the returned value,
152 // since some contexts set the pointer to a non-heap address.
153 SetRendererClientForTesting(renderer_client_
);
156 // Navigates to the given URL and waits for |num_navigations| to occur, and
157 // the title to change to |expected_title|.
158 void NavigateToURLAndWaitForTitle(const GURL
& url
,
159 const std::string
& expected_title
,
160 int num_navigations
) {
161 content::TitleWatcher
title_watcher(
162 shell()->web_contents(), base::ASCIIToUTF16(expected_title
));
164 content::NavigateToURLBlockUntilNavigationsComplete(
165 shell(), url
, num_navigations
);
167 EXPECT_EQ(base::ASCIIToUTF16(expected_title
),
168 title_watcher
.WaitAndGetTitle());
171 // Returns true if there is a valid error stored; in this case
172 // |*error_code| and |*stale_cache_entry_present| will be updated
174 // Must be called after the renderer thread is created.
175 bool GetLatestErrorFromRendererClient(
176 int* error_code
, bool* stale_cache_entry_present
) {
179 PostTaskToInProcessRendererAndWait(
180 base::Bind(&RenderViewBrowserTest::GetLatestErrorFromRendererClient0
,
181 renderer_client_
, &result
, error_code
,
182 stale_cache_entry_present
));
187 // Must be run on renderer thread.
188 static void GetLatestErrorFromRendererClient0(
189 TestShellContentRendererClient
* renderer_client
,
190 bool* result
, int* error_code
, bool* stale_cache_entry_present
) {
191 *result
= renderer_client
->GetLatestError(
192 error_code
, stale_cache_entry_present
);
195 TestShellContentRendererClient
* renderer_client_
;
198 IN_PROC_BROWSER_TEST_F(RenderViewBrowserTest
, ConfirmCacheInformationPlumbed
) {
199 ASSERT_TRUE(test_server()->Start());
201 // Load URL with "nocache" set, to create stale cache.
202 GURL
test_url(test_server()->GetURL("files/nocache.html"));
203 NavigateToURLAndWaitForTitle(test_url
, "Nocache Test Page", 1);
205 // Reload same URL after forcing an error from the the network layer;
206 // confirm that the error page is told the cached copy exists.
208 shell()->web_contents()->GetMainFrame()->GetProcess()->GetID();
209 scoped_refptr
<net::URLRequestContextGetter
> url_request_context_getter
=
210 ShellContentBrowserClient::Get()->browser_context()->
211 GetRequestContextForRenderProcess(renderer_id
);
212 BrowserThread::PostTask(
213 BrowserThread::IO
, FROM_HERE
,
214 base::Bind(&InterceptNetworkTransactions
, url_request_context_getter
,
217 // An error results in one completed navigation.
218 NavigateToURLBlockUntilNavigationsComplete(shell(), test_url
, 1);
219 int error_code
= net::OK
;
220 bool stale_cache_entry_present
= false;
221 ASSERT_TRUE(GetLatestErrorFromRendererClient(
222 &error_code
, &stale_cache_entry_present
));
223 EXPECT_EQ(net::ERR_FAILED
, error_code
);
224 EXPECT_TRUE(stale_cache_entry_present
);
226 // Clear the cache and repeat; confirm lack of entry in cache reported.
227 scoped_refptr
<MessageLoopRunner
> runner
= new MessageLoopRunner
;
228 BrowserThread::PostTask(
229 BrowserThread::IO
, FROM_HERE
,
230 base::Bind(&ClearCache
, url_request_context_getter
,
231 runner
->QuitClosure()));
234 content::NavigateToURLBlockUntilNavigationsComplete(shell(), test_url
, 1);
236 error_code
= net::OK
;
237 stale_cache_entry_present
= true;
238 ASSERT_TRUE(GetLatestErrorFromRendererClient(
239 &error_code
, &stale_cache_entry_present
));
240 EXPECT_EQ(net::ERR_FAILED
, error_code
);
241 EXPECT_FALSE(stale_cache_entry_present
);
244 } // namespace content