PageRenderTime 60ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/components/favicon/content/content_favicon_driver_unittest.cc

https://github.com/chromium/chromium
C++ | 238 lines | 177 code | 26 blank | 35 comment | 0 complexity | 9226c0d6be39ef28a6ccdf680d63c161 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause
  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
  3. // found in the LICENSE file.
  4. #include "components/favicon/content/content_favicon_driver.h"
  5. #include <memory>
  6. #include <vector>
  7. #include "base/run_loop.h"
  8. #include "base/test/bind.h"
  9. #include "base/test/metrics/histogram_tester.h"
  10. #include "components/favicon/core/favicon_client.h"
  11. #include "components/favicon/core/favicon_handler.h"
  12. #include "components/favicon/core/test/favicon_driver_impl_test_helper.h"
  13. #include "components/favicon/core/test/mock_favicon_service.h"
  14. #include "content/public/browser/web_contents_observer.h"
  15. #include "content/public/test/navigation_simulator.h"
  16. #include "content/public/test/test_renderer_host.h"
  17. #include "content/public/test/web_contents_tester.h"
  18. #include "testing/gmock/include/gmock/gmock.h"
  19. #include "testing/gtest/include/gtest/gtest.h"
  20. #include "third_party/blink/public/mojom/favicon/favicon_url.mojom.h"
  21. #include "third_party/skia/include/core/SkBitmap.h"
  22. #include "ui/gfx/favicon_size.h"
  23. namespace favicon {
  24. namespace {
  25. using testing::_;
  26. using testing::Return;
  27. using testing::SizeIs;
  28. void TestFetchFaviconForPage(
  29. content::WebContents* web_contents,
  30. const GURL& page_url,
  31. const std::vector<blink::mojom::FaviconURLPtr>& candidates) {
  32. ContentFaviconDriver* favicon_driver =
  33. ContentFaviconDriver::FromWebContents(web_contents);
  34. content::WebContentsTester::For(web_contents)->NavigateAndCommit(page_url);
  35. static_cast<content::WebContentsObserver*>(favicon_driver)
  36. ->DidUpdateFaviconURL(web_contents->GetPrimaryMainFrame(), candidates);
  37. base::RunLoop().RunUntilIdle();
  38. }
  39. class ContentFaviconDriverTest : public content::RenderViewHostTestHarness {
  40. protected:
  41. const std::vector<gfx::Size> kEmptyIconSizes;
  42. const std::vector<SkBitmap> kEmptyIcons;
  43. const GURL kPageURL = GURL("http://www.google.com/");
  44. const GURL kIconURL = GURL("http://www.google.com/favicon.ico");
  45. const GURL kFakeManifestURL = GURL("http://www.google.com/manifest.json");
  46. ContentFaviconDriverTest() {
  47. ON_CALL(favicon_service_, UpdateFaviconMappingsAndFetch)
  48. .WillByDefault([](auto, auto, auto, auto,
  49. favicon_base::FaviconResultsCallback callback,
  50. base::CancelableTaskTracker* tracker) {
  51. return tracker->PostTask(
  52. base::ThreadTaskRunnerHandle::Get().get(), FROM_HERE,
  53. base::BindOnce(
  54. std::move(callback),
  55. std::vector<favicon_base::FaviconRawBitmapResult>()));
  56. });
  57. ON_CALL(favicon_service_, GetFaviconForPageURL)
  58. .WillByDefault([](auto, auto, auto,
  59. favicon_base::FaviconResultsCallback callback,
  60. base::CancelableTaskTracker* tracker) {
  61. return tracker->PostTask(
  62. base::ThreadTaskRunnerHandle::Get().get(), FROM_HERE,
  63. base::BindOnce(
  64. std::move(callback),
  65. std::vector<favicon_base::FaviconRawBitmapResult>()));
  66. });
  67. }
  68. ~ContentFaviconDriverTest() override = default;
  69. // content::RenderViewHostTestHarness:
  70. void SetUp() override {
  71. RenderViewHostTestHarness::SetUp();
  72. ContentFaviconDriver::CreateForWebContents(web_contents(),
  73. &favicon_service_);
  74. }
  75. content::WebContentsTester* web_contents_tester() {
  76. return content::WebContentsTester::For(web_contents());
  77. }
  78. testing::NiceMock<MockFaviconService> favicon_service_;
  79. };
  80. // Test that a download is initiated when there isn't a favicon in the database
  81. // for either the page URL or the icon URL.
  82. TEST_F(ContentFaviconDriverTest, ShouldCauseImageDownload) {
  83. // Mimic a page load.
  84. std::vector<blink::mojom::FaviconURLPtr> favicon_urls;
  85. favicon_urls.push_back(blink::mojom::FaviconURL::New(
  86. kIconURL, blink::mojom::FaviconIconType::kFavicon, kEmptyIconSizes));
  87. TestFetchFaviconForPage(web_contents(), kPageURL, favicon_urls);
  88. EXPECT_TRUE(web_contents_tester()->TestDidDownloadImage(
  89. kIconURL, 200, kEmptyIcons, kEmptyIconSizes));
  90. }
  91. // Ensures that we do not consider a manifest URL if it arrives before the
  92. // onload handler has fired.
  93. // TODO(crbug.com/1205018): This may not necessarily the desired behavior, but
  94. // this test will prevent unintentional behavioral changes until the issue is
  95. // resolved.
  96. TEST_F(ContentFaviconDriverTest, IgnoreManifestURLBeforeOnLoad) {
  97. ContentFaviconDriver* favicon_driver =
  98. ContentFaviconDriver::FromWebContents(web_contents());
  99. auto navigation = content::NavigationSimulator::CreateBrowserInitiated(
  100. kPageURL, web_contents());
  101. navigation->SetKeepLoading(true);
  102. navigation->Commit();
  103. GURL manifest_url = kFakeManifestURL;
  104. auto* rfh_tester = content::RenderFrameHostTester::For(
  105. web_contents()->GetPrimaryMainFrame());
  106. rfh_tester->SimulateManifestURLUpdate(manifest_url);
  107. static_cast<content::WebContentsObserver*>(favicon_driver)
  108. ->DidUpdateWebManifestURL(web_contents()->GetPrimaryMainFrame(),
  109. manifest_url);
  110. EXPECT_EQ(GURL(), favicon_driver->GetManifestURL(
  111. web_contents()->GetPrimaryMainFrame()));
  112. }
  113. // Ensures that we use a manifest URL if it arrives after the onload handler
  114. // has fired. See crbug.com/1205018 for details.
  115. TEST_F(ContentFaviconDriverTest, UseManifestURLAFterOnLoad) {
  116. ContentFaviconDriver* favicon_driver =
  117. ContentFaviconDriver::FromWebContents(web_contents());
  118. auto navigation = content::NavigationSimulator::CreateBrowserInitiated(
  119. kPageURL, web_contents());
  120. navigation->SetKeepLoading(true);
  121. navigation->Commit();
  122. navigation->StopLoading();
  123. GURL manifest_url = kFakeManifestURL;
  124. auto* rfh_tester = content::RenderFrameHostTester::For(
  125. web_contents()->GetPrimaryMainFrame());
  126. rfh_tester->SimulateManifestURLUpdate(manifest_url);
  127. static_cast<content::WebContentsObserver*>(favicon_driver)
  128. ->DidUpdateWebManifestURL(web_contents()->GetPrimaryMainFrame(),
  129. manifest_url);
  130. EXPECT_EQ(kFakeManifestURL, favicon_driver->GetManifestURL(
  131. web_contents()->GetPrimaryMainFrame()));
  132. }
  133. // Test that no download is initiated when
  134. // DocumentOnLoadCompletedInPrimaryMainFrame() is not triggered (e.g. user
  135. // stopped an ongoing page load).
  136. TEST_F(ContentFaviconDriverTest, ShouldNotCauseImageDownload) {
  137. ContentFaviconDriver* favicon_driver =
  138. ContentFaviconDriver::FromWebContents(web_contents());
  139. auto navigation = content::NavigationSimulator::CreateBrowserInitiated(
  140. kPageURL, web_contents());
  141. navigation->SetKeepLoading(true);
  142. navigation->Commit();
  143. std::vector<blink::mojom::FaviconURLPtr> favicon_urls;
  144. favicon_urls.push_back(blink::mojom::FaviconURL::New(
  145. kIconURL, blink::mojom::FaviconIconType::kFavicon, kEmptyIconSizes));
  146. static_cast<content::WebContentsObserver*>(favicon_driver)
  147. ->DidUpdateFaviconURL(web_contents()->GetPrimaryMainFrame(),
  148. favicon_urls);
  149. base::RunLoop().RunUntilIdle();
  150. EXPECT_FALSE(web_contents_tester()->HasPendingDownloadImage(kIconURL));
  151. }
  152. // Test that Favicon is not requested repeatedly during the same session if
  153. // the favicon is known to be unavailable (e.g. due to HTTP 404 status).
  154. TEST_F(ContentFaviconDriverTest, ShouldNotRequestRepeatedlyIfUnavailable) {
  155. ON_CALL(favicon_service_, WasUnableToDownloadFavicon(kIconURL))
  156. .WillByDefault(Return(true));
  157. // Mimic a page load.
  158. std::vector<blink::mojom::FaviconURLPtr> favicon_urls;
  159. favicon_urls.push_back(blink::mojom::FaviconURL::New(
  160. kIconURL, blink::mojom::FaviconIconType::kFavicon, kEmptyIconSizes));
  161. TestFetchFaviconForPage(web_contents(), kPageURL, favicon_urls);
  162. // Verify that no download request is pending for the image.
  163. EXPECT_FALSE(web_contents_tester()->HasPendingDownloadImage(kIconURL));
  164. }
  165. TEST_F(ContentFaviconDriverTest, ShouldDownloadSecondIfFirstUnavailable) {
  166. const GURL kOtherIconURL = GURL("http://www.google.com/other-favicon.ico");
  167. ON_CALL(favicon_service_, WasUnableToDownloadFavicon(kIconURL))
  168. .WillByDefault(Return(true));
  169. // Mimic a page load.
  170. std::vector<blink::mojom::FaviconURLPtr> favicon_urls;
  171. favicon_urls.push_back(blink::mojom::FaviconURL::New(
  172. kIconURL, blink::mojom::FaviconIconType::kFavicon, kEmptyIconSizes));
  173. favicon_urls.push_back(blink::mojom::FaviconURL::New(
  174. kOtherIconURL, blink::mojom::FaviconIconType::kFavicon, kEmptyIconSizes));
  175. TestFetchFaviconForPage(web_contents(), kPageURL, favicon_urls);
  176. // Verify a download request is pending for the second image.
  177. EXPECT_FALSE(web_contents_tester()->HasPendingDownloadImage(kIconURL));
  178. EXPECT_TRUE(web_contents_tester()->HasPendingDownloadImage(kOtherIconURL));
  179. }
  180. using ContentFaviconDriverTestNoFaviconService =
  181. content::RenderViewHostTestHarness;
  182. // This test verifies a crash doesn't happen during deletion of the
  183. // WebContents. The crash occurred because ~WebContentsImpl would trigger
  184. // running callbacks for manifests. This mean FaviconHandler would be called
  185. // while ContentFaviconDriver::web_contents() was null, which is unexpected and
  186. // crashed. See https://crbug.com/1114237 for more.
  187. TEST_F(ContentFaviconDriverTestNoFaviconService,
  188. WebContentsDeletedWithInProgressManifestRequest) {
  189. ContentFaviconDriver::CreateForWebContents(web_contents(), nullptr);
  190. // Manifests are only downloaded with TOUCH_LARGEST. Force creating this
  191. // handler so code path is exercised on all platforms.
  192. favicon::ContentFaviconDriver* driver =
  193. favicon::ContentFaviconDriver::FromWebContents(web_contents());
  194. FaviconDriverImplTestHelper::RecreateHandlerForType(
  195. driver, FaviconDriverObserver::TOUCH_LARGEST);
  196. // Mimic a page load.
  197. std::vector<blink::mojom::FaviconURLPtr> favicon_urls;
  198. favicon_urls.push_back(blink::mojom::FaviconURL::New(
  199. GURL("http://www.google.com/favicon.ico"),
  200. blink::mojom::FaviconIconType::kTouchIcon, std::vector<gfx::Size>()));
  201. TestFetchFaviconForPage(web_contents(), GURL("http://www.google.com/"),
  202. favicon_urls);
  203. // Trigger downloading a manifest.
  204. static_cast<content::WebContentsObserver*>(driver)->DidUpdateWebManifestURL(
  205. web_contents()->GetPrimaryMainFrame(), GURL("http://bad.manifest.com"));
  206. // The request for the manifest is still pending, delete the WebContents,
  207. // which should trigger notifying the callback for the manifest and *not*
  208. // crash.
  209. DeleteContents();
  210. }
  211. } // namespace
  212. } // namespace favicon