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