blob: e73a95f74c2d6e10326ad7aaf150af49c6db31c0 [file] [log] [blame]
pkotwiczfd773552015-03-16 00:29:141// Copyright 2015 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
sdefresne455826972015-04-10 15:25:155#include "components/favicon/content/content_favicon_driver.h"
pkotwiczfd773552015-03-16 00:29:146
skyostil02598352015-06-12 12:37:257#include "base/location.h"
pkotwiczfd773552015-03-16 00:29:148#include "base/memory/weak_ptr.h"
9#include "base/run_loop.h"
sdefresneb0befeec2015-04-08 09:21:5610#include "base/scoped_observer.h"
skyostil02598352015-06-12 12:37:2511#include "base/single_thread_task_runner.h"
12#include "base/thread_task_runner_handle.h"
pkotwiczfd773552015-03-16 00:29:1413#include "chrome/app/chrome_command_ids.h"
14#include "chrome/browser/chrome_notification_types.h"
pkotwiczfd773552015-03-16 00:29:1415#include "chrome/browser/ui/browser.h"
16#include "chrome/browser/ui/browser_commands.h"
17#include "chrome/browser/ui/tabs/tab_strip_model.h"
18#include "chrome/test/base/in_process_browser_test.h"
19#include "chrome/test/base/ui_test_utils.h"
sdefresneb0befeec2015-04-08 09:21:5620#include "components/favicon/core/favicon_driver_observer.h"
sdefresnecbacfd72015-03-20 12:11:3221#include "components/favicon/core/favicon_handler.h"
pkotwiczfd773552015-03-16 00:29:1422#include "content/public/browser/notification_observer.h"
23#include "content/public/browser/notification_registrar.h"
24#include "content/public/browser/notification_types.h"
25#include "content/public/browser/resource_dispatcher_host.h"
26#include "content/public/browser/resource_dispatcher_host_delegate.h"
27#include "net/base/load_flags.h"
28#include "net/test/spawned_test_server/spawned_test_server.h"
29#include "net/url_request/url_request.h"
30#include "url/url_constants.h"
31
32namespace {
33
34// Tracks whether the URL passed to the constructor is requested and whether
35// the request bypasses the cache.
36class TestResourceDispatcherHostDelegate
37 : public content::ResourceDispatcherHostDelegate {
38 public:
39 explicit TestResourceDispatcherHostDelegate(const GURL& url)
40 : url_(url), was_requested_(false), bypassed_cache_(false) {}
41 ~TestResourceDispatcherHostDelegate() override {}
42
43 void Reset() {
44 was_requested_ = false;
45 bypassed_cache_ = false;
46 }
47
48 // Resturns whether |url_| was requested.
49 bool was_requested() const { return was_requested_; }
50
51 // Returns whether any of the requests bypassed the HTTP cache.
52 bool bypassed_cache() const { return bypassed_cache_; }
53
54 private:
55 // content::ResourceDispatcherHostDelegate:
56 bool ShouldBeginRequest(const std::string& method,
57 const GURL& url,
58 content::ResourceType resource_type,
59 content::ResourceContext* resource_context) override {
60 return true;
61 }
62
63 void RequestBeginning(
64 net::URLRequest* request,
65 content::ResourceContext* resource_context,
66 content::AppCacheService* appcache_service,
67 content::ResourceType resource_type,
68 ScopedVector<content::ResourceThrottle>* throttles) override {
69 if (request->url() == url_) {
70 was_requested_ = true;
71 if (request->load_flags() & net::LOAD_BYPASS_CACHE)
72 bypassed_cache_ = true;
73 }
74 }
75
76 void DownloadStarting(
77 net::URLRequest* request,
78 content::ResourceContext* resource_context,
79 int child_id,
80 int route_id,
81 int request_id,
82 bool is_content_initiated,
83 bool must_download,
84 ScopedVector<content::ResourceThrottle>* throttles) override {}
85
86 private:
87 GURL url_;
88 bool was_requested_;
89 bool bypassed_cache_;
90
91 DISALLOW_COPY_AND_ASSIGN(TestResourceDispatcherHostDelegate);
92};
93
sdefresne455826972015-04-10 15:25:1594// Checks whether the FaviconDriver is waiting for a download to complete or
pkotwiczfd773552015-03-16 00:29:1495// for data from the FaviconService.
sdefresne455826972015-04-10 15:25:1596class FaviconDriverPendingTaskChecker {
pkotwiczfd773552015-03-16 00:29:1497 public:
sdefresne455826972015-04-10 15:25:1598 virtual ~FaviconDriverPendingTaskChecker() {}
pkotwiczfd773552015-03-16 00:29:1499
100 virtual bool HasPendingTasks() = 0;
101};
102
103// Waits for the following the finish:
104// - The pending navigation.
105// - FaviconHandler's pending favicon database requests.
106// - FaviconHandler's pending downloads.
sdefresneb0befeec2015-04-08 09:21:56107class PendingTaskWaiter : public content::NotificationObserver,
108 public favicon::FaviconDriverObserver {
pkotwiczfd773552015-03-16 00:29:14109 public:
110 PendingTaskWaiter(content::WebContents* web_contents,
sdefresne455826972015-04-10 15:25:15111 FaviconDriverPendingTaskChecker* checker)
sdefresneb0befeec2015-04-08 09:21:56112 : checker_(checker),
113 load_stopped_(false),
114 scoped_observer_(this),
115 weak_factory_(this) {
pkotwiczfd773552015-03-16 00:29:14116 registrar_.Add(this, content::NOTIFICATION_LOAD_STOP,
117 content::Source<content::NavigationController>(
118 &web_contents->GetController()));
sdefresne455826972015-04-10 15:25:15119 scoped_observer_.Add(
120 favicon::ContentFaviconDriver::FromWebContents(web_contents));
pkotwiczfd773552015-03-16 00:29:14121 }
122 ~PendingTaskWaiter() override {}
123
124 void Wait() {
125 if (load_stopped_ && !checker_->HasPendingTasks())
126 return;
127
128 base::RunLoop run_loop;
129 quit_closure_ = run_loop.QuitClosure();
130 run_loop.Run();
131 }
132
133 private:
134 // content::NotificationObserver:
135 void Observe(int type,
136 const content::NotificationSource& source,
137 const content::NotificationDetails& details) override {
138 if (type == content::NOTIFICATION_LOAD_STOP)
139 load_stopped_ = true;
140
sdefresneb0befeec2015-04-08 09:21:56141 OnNotification();
142 }
143
144 // favicon::Favicon
145 void OnFaviconAvailable(const gfx::Image& image) override {}
146 void OnFaviconUpdated(favicon::FaviconDriver* favicon_driver,
147 bool icon_url_changed) override {
148 OnNotification();
149 }
150
151 void OnNotification() {
pkotwiczfd773552015-03-16 00:29:14152 if (!quit_closure_.is_null()) {
153 // We stop waiting based on changes in state to FaviconHandler which occur
sdefresneb0befeec2015-04-08 09:21:56154 // immediately after OnFaviconUpdated() is called. Post a task to check if
155 // we can stop waiting.
skyostil02598352015-06-12 12:37:25156 base::ThreadTaskRunnerHandle::Get()->PostTask(
pkotwiczfd773552015-03-16 00:29:14157 FROM_HERE, base::Bind(&PendingTaskWaiter::EndLoopIfCanStopWaiting,
158 weak_factory_.GetWeakPtr()));
159 }
160 }
161
162 void EndLoopIfCanStopWaiting() {
163 if (!quit_closure_.is_null() &&
164 load_stopped_ &&
165 !checker_->HasPendingTasks()) {
166 quit_closure_.Run();
167 }
168 }
169
sdefresne455826972015-04-10 15:25:15170 FaviconDriverPendingTaskChecker* checker_; // Not owned.
pkotwiczfd773552015-03-16 00:29:14171 bool load_stopped_;
172 base::Closure quit_closure_;
173 content::NotificationRegistrar registrar_;
sdefresne455826972015-04-10 15:25:15174 ScopedObserver<favicon::FaviconDriver, PendingTaskWaiter> scoped_observer_;
pkotwiczfd773552015-03-16 00:29:14175 base::WeakPtrFactory<PendingTaskWaiter> weak_factory_;
176
177 DISALLOW_COPY_AND_ASSIGN(PendingTaskWaiter);
178};
179
180} // namespace
181
sdefresne455826972015-04-10 15:25:15182class ContentFaviconDriverTest : public InProcessBrowserTest,
183 public FaviconDriverPendingTaskChecker {
pkotwiczfd773552015-03-16 00:29:14184 public:
sdefresne455826972015-04-10 15:25:15185 ContentFaviconDriverTest() {}
186 ~ContentFaviconDriverTest() override {}
pkotwiczfd773552015-03-16 00:29:14187
188 content::WebContents* web_contents() {
189 return browser()->tab_strip_model()->GetActiveWebContents();
190 }
191
sdefresne455826972015-04-10 15:25:15192 // FaviconDriverPendingTaskChecker:
pkotwiczfd773552015-03-16 00:29:14193 bool HasPendingTasks() override {
sdefresne455826972015-04-10 15:25:15194 return favicon::ContentFaviconDriver::FromWebContents(web_contents())
sdefresne70a04802015-04-09 14:00:17195 ->HasPendingTasksForTest();
pkotwiczfd773552015-03-16 00:29:14196 }
197
198 private:
sdefresne455826972015-04-10 15:25:15199 DISALLOW_COPY_AND_ASSIGN(ContentFaviconDriverTest);
pkotwiczfd773552015-03-16 00:29:14200};
201
202// Test that when a user reloads a page ignoring the cache that the favicon is
203// is redownloaded and (not returned from either the favicon cache or the HTTP
204// cache).
sdefresne455826972015-04-10 15:25:15205IN_PROC_BROWSER_TEST_F(ContentFaviconDriverTest, ReloadIgnoringCache) {
pkotwiczfd773552015-03-16 00:29:14206 ASSERT_TRUE(test_server()->Start());
207 GURL url = test_server()->GetURL("files/favicon/page_with_favicon.html");
208 GURL icon_url = test_server()->GetURL("files/favicon/icon.ico");
209
210 scoped_ptr<TestResourceDispatcherHostDelegate> delegate(
211 new TestResourceDispatcherHostDelegate(icon_url));
212 content::ResourceDispatcherHost::Get()->SetDelegate(delegate.get());
213
214 // Initial visit in order to populate the cache.
215 {
216 PendingTaskWaiter waiter(web_contents(), this);
217 ui_test_utils::NavigateToURLWithDisposition(
218 browser(), url, CURRENT_TAB, ui_test_utils::BROWSER_TEST_NONE);
219 waiter.Wait();
220 }
221 ASSERT_TRUE(delegate->was_requested());
222 EXPECT_FALSE(delegate->bypassed_cache());
223 delegate->Reset();
224
225 ui_test_utils::NavigateToURL(browser(), GURL(url::kAboutBlankURL));
226
227 // A normal visit should fetch the favicon from either the favicon database or
228 // the HTTP cache.
229 {
230 PendingTaskWaiter waiter(web_contents(), this);
231 ui_test_utils::NavigateToURLWithDisposition(
232 browser(), url, CURRENT_TAB, ui_test_utils::BROWSER_TEST_NONE);
233 waiter.Wait();
234 }
235 EXPECT_FALSE(delegate->bypassed_cache());
236 delegate->Reset();
237
238 // A reload ignoring the cache should refetch the favicon from the website.
239 {
240 PendingTaskWaiter waiter(web_contents(), this);
241 chrome::ExecuteCommand(browser(), IDC_RELOAD_IGNORING_CACHE);
242 waiter.Wait();
243 }
244 ASSERT_TRUE(delegate->was_requested());
245 EXPECT_TRUE(delegate->bypassed_cache());
246}