Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(80)

Side by Side Diff: chrome/browser/favicon/content_favicon_driver_browsertest.cc

Issue 2950563002: Fix in-document navigations breaking icons from Web Manifests (Closed)
Patch Set: Adopted GetLastCommittedURL(). Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | chrome/test/data/favicon/pushstate_with_manifest.html » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/favicon/content/content_favicon_driver.h" 5 #include "components/favicon/content/content_favicon_driver.h"
6 6
7 #include "base/location.h" 7 #include "base/location.h"
8 #include "base/macros.h" 8 #include "base/macros.h"
9 #include "base/memory/weak_ptr.h" 9 #include "base/memory/weak_ptr.h"
10 #include "base/run_loop.h" 10 #include "base/run_loop.h"
11 #include "base/single_thread_task_runner.h" 11 #include "base/single_thread_task_runner.h"
12 #include "base/test/scoped_feature_list.h" 12 #include "base/test/scoped_feature_list.h"
13 #include "base/threading/thread_task_runner_handle.h" 13 #include "base/threading/thread_task_runner_handle.h"
14 #include "chrome/app/chrome_command_ids.h" 14 #include "chrome/app/chrome_command_ids.h"
15 #include "chrome/browser/chrome_notification_types.h" 15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/favicon/favicon_service_factory.h" 16 #include "chrome/browser/favicon/favicon_service_factory.h"
17 #include "chrome/browser/ui/browser.h" 17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_commands.h" 18 #include "chrome/browser/ui/browser_commands.h"
19 #include "chrome/browser/ui/tabs/tab_strip_model.h" 19 #include "chrome/browser/ui/tabs/tab_strip_model.h"
20 #include "chrome/test/base/in_process_browser_test.h" 20 #include "chrome/test/base/in_process_browser_test.h"
21 #include "chrome/test/base/ui_test_utils.h" 21 #include "chrome/test/base/ui_test_utils.h"
22 #include "components/favicon/core/favicon_handler.h" 22 #include "components/favicon/core/favicon_handler.h"
23 #include "components/favicon/core/favicon_service.h" 23 #include "components/favicon/core/favicon_service.h"
24 #include "components/favicon/core/features.h" 24 #include "components/favicon/core/features.h"
25 #include "content/public/browser/notification_observer.h"
26 #include "content/public/browser/notification_registrar.h"
27 #include "content/public/browser/notification_types.h"
28 #include "content/public/browser/resource_dispatcher_host.h" 25 #include "content/public/browser/resource_dispatcher_host.h"
29 #include "content/public/browser/resource_dispatcher_host_delegate.h" 26 #include "content/public/browser/resource_dispatcher_host_delegate.h"
27 #include "content/public/browser/web_contents_observer.h"
30 #include "net/base/load_flags.h" 28 #include "net/base/load_flags.h"
31 #include "net/test/embedded_test_server/embedded_test_server.h" 29 #include "net/test/embedded_test_server/embedded_test_server.h"
32 #include "net/url_request/url_request.h" 30 #include "net/url_request/url_request.h"
33 #include "url/url_constants.h" 31 #include "url/url_constants.h"
34 32
35 namespace { 33 namespace {
36 34
37 // Tracks whether the URL passed to the constructor is requested and whether 35 // Tracks whether the URL passed to the constructor is requested and whether
38 // the request bypasses the cache. 36 // the request bypasses the cache.
39 class TestResourceDispatcherHostDelegate 37 class TestResourceDispatcherHostDelegate
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 } 75 }
78 76
79 private: 77 private:
80 GURL url_; 78 GURL url_;
81 bool was_requested_; 79 bool was_requested_;
82 bool bypassed_cache_; 80 bool bypassed_cache_;
83 81
84 DISALLOW_COPY_AND_ASSIGN(TestResourceDispatcherHostDelegate); 82 DISALLOW_COPY_AND_ASSIGN(TestResourceDispatcherHostDelegate);
85 }; 83 };
86 84
87 // Checks whether the FaviconDriver is waiting for a download to complete or
88 // for data from the FaviconService.
89 class FaviconDriverPendingTaskChecker {
90 public:
91 virtual ~FaviconDriverPendingTaskChecker() {}
92
93 virtual bool HasPendingTasks() = 0;
94 };
95
96 // Waits for the following the finish: 85 // Waits for the following the finish:
97 // - The pending navigation. 86 // - The pending navigation.
98 // - FaviconHandler's pending favicon database requests. 87 // - FaviconHandler's pending favicon database requests.
99 // - FaviconHandler's pending downloads. 88 // - FaviconHandler's pending downloads.
100 class PendingTaskWaiter : public content::NotificationObserver { 89 // - Optionally, for a specific page URL (as a mechanism to wait of Javascript
90 // completion).
91 class PendingTaskWaiter : public content::WebContentsObserver {
101 public: 92 public:
102 PendingTaskWaiter(content::WebContents* web_contents, 93 PendingTaskWaiter(content::WebContents* web_contents,
103 FaviconDriverPendingTaskChecker* checker) 94 const GURL& required_url = GURL())
104 : checker_(checker), 95 : WebContentsObserver(web_contents),
105 load_stopped_(false), 96 required_url_(required_url),
106 weak_factory_(this) { 97 weak_factory_(this) {}
107 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
108 content::Source<content::NavigationController>(
109 &web_contents->GetController()));
110 }
111 ~PendingTaskWaiter() override {} 98 ~PendingTaskWaiter() override {}
112 99
113 void Wait() { 100 void Wait() {
114 if (load_stopped_ && !checker_->HasPendingTasks())
115 return;
116
117 base::RunLoop run_loop; 101 base::RunLoop run_loop;
118 quit_closure_ = run_loop.QuitClosure(); 102 quit_closure_ = run_loop.QuitClosure();
119 run_loop.Run(); 103 run_loop.Run();
120 } 104 }
121 105
122 private: 106 private:
123 // content::NotificationObserver: 107 // content::WebContentsObserver:
124 void Observe(int type, 108 void DidStopLoading() override {
125 const content::NotificationSource& source, 109 if (!required_url_.is_empty() &&
126 const content::NotificationDetails& details) override { 110 required_url_ != web_contents()->GetLastCommittedURL()) {
127 if (type == content::NOTIFICATION_LOAD_STOP) 111 return;
128 load_stopped_ = true; 112 }
129 113
130 // We need to poll periodically because Delegate::OnFaviconUpdated() is not 114 // We need to poll periodically because Delegate::OnFaviconUpdated() is not
131 // guaranteed to be called upon completion of the last database request / 115 // guaranteed to be called upon completion of the last database request /
132 // download. In particular, OnFaviconUpdated() might not be called if a 116 // download. In particular, OnFaviconUpdated() might not be called if a
133 // database request confirms the data sent in the previous 117 // database request confirms the data sent in the previous
134 // OnFaviconUpdated() call. 118 // OnFaviconUpdated() call.
135 CheckStopWaitingPeriodically(); 119 CheckStopWaitingPeriodically();
136 } 120 }
137 121
138 void CheckStopWaitingPeriodically() { 122 void CheckStopWaitingPeriodically() {
139 EndLoopIfCanStopWaiting(); 123 EndLoopIfCanStopWaiting();
140 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( 124 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
141 FROM_HERE, 125 FROM_HERE,
142 base::BindOnce(&PendingTaskWaiter::CheckStopWaitingPeriodically, 126 base::BindOnce(&PendingTaskWaiter::CheckStopWaitingPeriodically,
143 weak_factory_.GetWeakPtr()), 127 weak_factory_.GetWeakPtr()),
144 base::TimeDelta::FromSeconds(1)); 128 base::TimeDelta::FromSeconds(1));
145 } 129 }
146 130
147 void EndLoopIfCanStopWaiting() { 131 void EndLoopIfCanStopWaiting() {
148 if (!quit_closure_.is_null() && 132 if (!quit_closure_.is_null() &&
149 load_stopped_ && 133 !favicon::ContentFaviconDriver::FromWebContents(web_contents())
150 !checker_->HasPendingTasks()) { 134 ->HasPendingTasksForTest()) {
151 quit_closure_.Run(); 135 quit_closure_.Run();
152 } 136 }
153 } 137 }
154 138
155 FaviconDriverPendingTaskChecker* checker_; // Not owned.
156 bool load_stopped_;
157 base::Closure quit_closure_; 139 base::Closure quit_closure_;
158 content::NotificationRegistrar registrar_; 140 const GURL required_url_;
159 base::WeakPtrFactory<PendingTaskWaiter> weak_factory_; 141 base::WeakPtrFactory<PendingTaskWaiter> weak_factory_;
160 142
161 DISALLOW_COPY_AND_ASSIGN(PendingTaskWaiter); 143 DISALLOW_COPY_AND_ASSIGN(PendingTaskWaiter);
162 }; 144 };
163 145
164 } // namespace 146 } // namespace
165 147
166 class ContentFaviconDriverTest : public InProcessBrowserTest, 148 class ContentFaviconDriverTest : public InProcessBrowserTest {
167 public FaviconDriverPendingTaskChecker {
168 public: 149 public:
169 ContentFaviconDriverTest() {} 150 ContentFaviconDriverTest() {}
170 ~ContentFaviconDriverTest() override {} 151 ~ContentFaviconDriverTest() override {}
171 152
172 content::WebContents* web_contents() { 153 content::WebContents* web_contents() {
173 return browser()->tab_strip_model()->GetActiveWebContents(); 154 return browser()->tab_strip_model()->GetActiveWebContents();
174 } 155 }
175 156
176 // FaviconDriverPendingTaskChecker: 157 favicon_base::FaviconRawBitmapResult GetFaviconForPageURL(
177 bool HasPendingTasks() override { 158 const GURL& url,
178 return favicon::ContentFaviconDriver::FromWebContents(web_contents()) 159 favicon_base::IconType icon_type) {
179 ->HasPendingTasksForTest();
180 }
181
182 favicon_base::FaviconRawBitmapResult GetFaviconForPageURL(const GURL& url) {
183 favicon::FaviconService* favicon_service = 160 favicon::FaviconService* favicon_service =
184 FaviconServiceFactory::GetForProfile( 161 FaviconServiceFactory::GetForProfile(
185 browser()->profile(), ServiceAccessType::EXPLICIT_ACCESS); 162 browser()->profile(), ServiceAccessType::EXPLICIT_ACCESS);
186 163
187 std::vector<favicon_base::FaviconRawBitmapResult> results; 164 std::vector<favicon_base::FaviconRawBitmapResult> results;
188 base::CancelableTaskTracker tracker; 165 base::CancelableTaskTracker tracker;
189 base::RunLoop loop; 166 base::RunLoop loop;
190 favicon_service->GetFaviconForPageURL( 167 favicon_service->GetFaviconForPageURL(
191 url, favicon_base::FAVICON, /*desired_size_in_dip=*/0, 168 url, icon_type, /*desired_size_in_dip=*/0,
192 base::Bind( 169 base::Bind(
193 [](std::vector<favicon_base::FaviconRawBitmapResult>* save_results, 170 [](std::vector<favicon_base::FaviconRawBitmapResult>* save_results,
194 base::RunLoop* loop, 171 base::RunLoop* loop,
195 const std::vector<favicon_base::FaviconRawBitmapResult>& 172 const std::vector<favicon_base::FaviconRawBitmapResult>&
196 results) { 173 results) {
197 *save_results = results; 174 *save_results = results;
198 loop->Quit(); 175 loop->Quit();
199 }, 176 },
200 &results, &loop), 177 &results, &loop),
201 &tracker); 178 &tracker);
(...skipping 16 matching lines...) Expand all
218 ASSERT_TRUE(embedded_test_server()->Start()); 195 ASSERT_TRUE(embedded_test_server()->Start());
219 GURL url = embedded_test_server()->GetURL("/favicon/page_with_favicon.html"); 196 GURL url = embedded_test_server()->GetURL("/favicon/page_with_favicon.html");
220 GURL icon_url = embedded_test_server()->GetURL("/favicon/icon.png"); 197 GURL icon_url = embedded_test_server()->GetURL("/favicon/icon.png");
221 198
222 std::unique_ptr<TestResourceDispatcherHostDelegate> delegate( 199 std::unique_ptr<TestResourceDispatcherHostDelegate> delegate(
223 new TestResourceDispatcherHostDelegate(icon_url)); 200 new TestResourceDispatcherHostDelegate(icon_url));
224 content::ResourceDispatcherHost::Get()->SetDelegate(delegate.get()); 201 content::ResourceDispatcherHost::Get()->SetDelegate(delegate.get());
225 202
226 // Initial visit in order to populate the cache. 203 // Initial visit in order to populate the cache.
227 { 204 {
228 PendingTaskWaiter waiter(web_contents(), this); 205 PendingTaskWaiter waiter(web_contents());
229 ui_test_utils::NavigateToURLWithDisposition( 206 ui_test_utils::NavigateToURLWithDisposition(
230 browser(), url, WindowOpenDisposition::CURRENT_TAB, 207 browser(), url, WindowOpenDisposition::CURRENT_TAB,
231 ui_test_utils::BROWSER_TEST_NONE); 208 ui_test_utils::BROWSER_TEST_NONE);
232 waiter.Wait(); 209 waiter.Wait();
233 } 210 }
234 ASSERT_TRUE(delegate->was_requested()); 211 ASSERT_TRUE(delegate->was_requested());
235 EXPECT_FALSE(delegate->bypassed_cache()); 212 EXPECT_FALSE(delegate->bypassed_cache());
236 delegate->Reset(); 213 delegate->Reset();
237 214
238 ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)); 215 ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
239 216
240 // A normal visit should fetch the favicon from either the favicon database or 217 // A normal visit should fetch the favicon from either the favicon database or
241 // the HTTP cache. 218 // the HTTP cache.
242 { 219 {
243 PendingTaskWaiter waiter(web_contents(), this); 220 PendingTaskWaiter waiter(web_contents());
244 ui_test_utils::NavigateToURLWithDisposition( 221 ui_test_utils::NavigateToURLWithDisposition(
245 browser(), url, WindowOpenDisposition::CURRENT_TAB, 222 browser(), url, WindowOpenDisposition::CURRENT_TAB,
246 ui_test_utils::BROWSER_TEST_NONE); 223 ui_test_utils::BROWSER_TEST_NONE);
247 waiter.Wait(); 224 waiter.Wait();
248 } 225 }
249 EXPECT_FALSE(delegate->bypassed_cache()); 226 EXPECT_FALSE(delegate->bypassed_cache());
250 delegate->Reset(); 227 delegate->Reset();
251 228
252 // A reload ignoring the cache should refetch the favicon from the website. 229 // A reload ignoring the cache should refetch the favicon from the website.
253 { 230 {
254 PendingTaskWaiter waiter(web_contents(), this); 231 PendingTaskWaiter waiter(web_contents());
255 chrome::ExecuteCommand(browser(), IDC_RELOAD_BYPASSING_CACHE); 232 chrome::ExecuteCommand(browser(), IDC_RELOAD_BYPASSING_CACHE);
256 waiter.Wait(); 233 waiter.Wait();
257 } 234 }
258 ASSERT_TRUE(delegate->was_requested()); 235 ASSERT_TRUE(delegate->was_requested());
259 EXPECT_TRUE(delegate->bypassed_cache()); 236 EXPECT_TRUE(delegate->bypassed_cache());
260 } 237 }
261 238
262 // Test that loading a page that contains icons only in the Web Manifest causes 239 // Test that loading a page that contains icons only in the Web Manifest causes
263 // those icons to be used. 240 // those icons to be used.
264 IN_PROC_BROWSER_TEST_F(ContentFaviconDriverTest, LoadIconFromWebManifest) { 241 IN_PROC_BROWSER_TEST_F(ContentFaviconDriverTest, LoadIconFromWebManifest) {
265 ASSERT_TRUE(embedded_test_server()->Start()); 242 ASSERT_TRUE(embedded_test_server()->Start());
266 GURL url = embedded_test_server()->GetURL("/favicon/page_with_manifest.html"); 243 GURL url = embedded_test_server()->GetURL("/favicon/page_with_manifest.html");
267 GURL icon_url = embedded_test_server()->GetURL("/favicon/icon.png"); 244 GURL icon_url = embedded_test_server()->GetURL("/favicon/icon.png");
268 245
269 std::unique_ptr<TestResourceDispatcherHostDelegate> delegate( 246 std::unique_ptr<TestResourceDispatcherHostDelegate> delegate(
270 new TestResourceDispatcherHostDelegate(icon_url)); 247 new TestResourceDispatcherHostDelegate(icon_url));
271 content::ResourceDispatcherHost::Get()->SetDelegate(delegate.get()); 248 content::ResourceDispatcherHost::Get()->SetDelegate(delegate.get());
272 249
273 PendingTaskWaiter waiter(web_contents(), this); 250 PendingTaskWaiter waiter(web_contents());
274 ui_test_utils::NavigateToURLWithDisposition( 251 ui_test_utils::NavigateToURLWithDisposition(
275 browser(), url, WindowOpenDisposition::CURRENT_TAB, 252 browser(), url, WindowOpenDisposition::CURRENT_TAB,
276 ui_test_utils::BROWSER_TEST_NONE); 253 ui_test_utils::BROWSER_TEST_NONE);
277 waiter.Wait(); 254 waiter.Wait();
278 255
279 #if defined(OS_ANDROID) 256 #if defined(OS_ANDROID)
280 EXPECT_TRUE(delegate->was_requested()); 257 EXPECT_TRUE(delegate->was_requested());
258 EXPECT_NE(
259 nullptr,
260 GetFaviconForPageURL(url, favicon_base::WEB_MANIFEST_ICON).bitmap_data);
281 #else 261 #else
282 EXPECT_FALSE(delegate->was_requested()); 262 EXPECT_FALSE(delegate->was_requested());
283 #endif 263 #endif
284 } 264 }
285 265
286 // Test that loading a page that contains a Web Manifest without icons and a 266 // Test that loading a page that contains a Web Manifest without icons and a
287 // regular favicon in the HTML reports the icon. The regular icon is initially 267 // regular favicon in the HTML reports the icon. The regular icon is initially
288 // cached in the Favicon database. 268 // cached in the Favicon database.
289 IN_PROC_BROWSER_TEST_F(ContentFaviconDriverTest, 269 IN_PROC_BROWSER_TEST_F(ContentFaviconDriverTest,
290 LoadRegularIconDespiteWebManifestWithoutIcons) { 270 LoadRegularIconDespiteWebManifestWithoutIcons) {
291 ASSERT_TRUE(embedded_test_server()->Start()); 271 ASSERT_TRUE(embedded_test_server()->Start());
292 GURL url = embedded_test_server()->GetURL( 272 GURL url = embedded_test_server()->GetURL(
293 "/favicon/page_with_manifest_without_icons.html"); 273 "/favicon/page_with_manifest_without_icons.html");
294 GURL icon_url = embedded_test_server()->GetURL("/favicon/icon.png"); 274 GURL icon_url = embedded_test_server()->GetURL("/favicon/icon.png");
295 275
296 // Initial visit with the feature disabled, to populate the cache. 276 // Initial visit with the feature disabled, to populate the cache.
297 { 277 {
298 base::test::ScopedFeatureList override_features; 278 base::test::ScopedFeatureList override_features;
299 override_features.InitAndDisableFeature(favicon::kFaviconsFromWebManifest); 279 override_features.InitAndDisableFeature(favicon::kFaviconsFromWebManifest);
300 280
301 PendingTaskWaiter waiter(web_contents(), this); 281 PendingTaskWaiter waiter(web_contents());
302 ui_test_utils::NavigateToURLWithDisposition( 282 ui_test_utils::NavigateToURLWithDisposition(
303 browser(), url, WindowOpenDisposition::CURRENT_TAB, 283 browser(), url, WindowOpenDisposition::CURRENT_TAB,
304 ui_test_utils::BROWSER_TEST_NONE); 284 ui_test_utils::BROWSER_TEST_NONE);
305 waiter.Wait(); 285 waiter.Wait();
306 } 286 }
307 ASSERT_NE(nullptr, GetFaviconForPageURL(url).bitmap_data); 287 ASSERT_NE(nullptr,
288 GetFaviconForPageURL(url, favicon_base::FAVICON).bitmap_data);
308 289
309 ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL)); 290 ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
310 291
311 // Visit the page again now that the feature is enabled (default). 292 // Visit the page again now that the feature is enabled (default).
312 { 293 {
313 PendingTaskWaiter waiter(web_contents(), this); 294 PendingTaskWaiter waiter(web_contents());
314 ui_test_utils::NavigateToURLWithDisposition( 295 ui_test_utils::NavigateToURLWithDisposition(
315 browser(), url, WindowOpenDisposition::CURRENT_TAB, 296 browser(), url, WindowOpenDisposition::CURRENT_TAB,
316 ui_test_utils::BROWSER_TEST_NONE); 297 ui_test_utils::BROWSER_TEST_NONE);
317 waiter.Wait(); 298 waiter.Wait();
318 } 299 }
319 300
320 EXPECT_NE(nullptr, GetFaviconForPageURL(url).bitmap_data); 301 EXPECT_NE(nullptr,
302 GetFaviconForPageURL(url, favicon_base::FAVICON).bitmap_data);
321 } 303 }
304
305 #if defined(OS_ANDROID)
306 IN_PROC_BROWSER_TEST_F(ContentFaviconDriverTest,
307 LoadIconFromWebManifestDespitePushState) {
308 base::test::ScopedFeatureList override_features;
309 override_features.InitAndEnableFeature(favicon::kFaviconsFromWebManifest);
310
311 ASSERT_TRUE(embedded_test_server()->Start());
312 GURL url =
313 embedded_test_server()->GetURL("/favicon/pushstate_with_manifest.html");
314 GURL pushstate_url = embedded_test_server()->GetURL(
315 "/favicon/pushstate_with_manifest.html#pushState");
316
317 PendingTaskWaiter waiter(web_contents(), /*required_url=*/pushstate_url);
318 ui_test_utils::NavigateToURLWithDisposition(
319 browser(), url, WindowOpenDisposition::CURRENT_TAB,
320 ui_test_utils::BROWSER_TEST_NONE);
321 waiter.Wait();
322
323 EXPECT_NE(nullptr,
324 GetFaviconForPageURL(pushstate_url, favicon_base::WEB_MANIFEST_ICON)
325 .bitmap_data);
326 }
327 #endif
OLDNEW
« no previous file with comments | « no previous file | chrome/test/data/favicon/pushstate_with_manifest.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698