chromium/chrome/browser/supervised_user/chromeos/supervised_user_favicon_request_handler_unittest.cc

// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/supervised_user/chromeos/supervised_user_favicon_request_handler.h"

#include "base/run_loop.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "chrome/browser/supervised_user/chromeos/mock_large_icon_service.h"
#include "components/favicon/core/large_icon_service.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_unittest_util.h"
#include "url/gurl.h"

using testing::_;

class SupervisedUserFaviconRequestHandlerTest : public ::testing::Test {
 public:
  SupervisedUserFaviconRequestHandlerTest() = default;
  SupervisedUserFaviconRequestHandlerTest(
      const SupervisedUserFaviconRequestHandlerTest&) = delete;
  SupervisedUserFaviconRequestHandlerTest& operator=(
      const SupervisedUserFaviconRequestHandlerTest&) = delete;

  void OnFaviconFetched(base::RunLoop* run_loop) { run_loop->Quit(); }

 protected:
  base::test::SingleThreadTaskEnvironment task_environment;

 private:
  base::OnceClosure quit_closure_;
};

TEST_F(SupervisedUserFaviconRequestHandlerTest, GetUncachedFavicon) {
  base::HistogramTester histogram_tester;
  const GURL page_url = GURL("https://www.example.com");
  MockLargeIconService large_icon_service;
  SupervisedUserFaviconRequestHandler handler(page_url, &large_icon_service);

  // If the icon is not in the cache, there should be two calls to fetch it from
  // the cache. One before the network request where the icon is not yet in the
  // cache and one afterwards, when the icon should be present in the cache.
  EXPECT_CALL(large_icon_service,
              GetLargeIconRawBitmapForPageUrl(page_url, _, _, _, _, _))
      .Times(2);
  EXPECT_CALL(large_icon_service,
              GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
                  page_url, _, _, _));
  // Confirm that the icon was retrieved from the cache.
  EXPECT_CALL(large_icon_service,
              TouchIconFromGoogleServer(large_icon_service.kIconUrl));

  base::RunLoop run_loop;
  handler.StartFaviconFetch(
      base::BindOnce(&SupervisedUserFaviconRequestHandlerTest::OnFaviconFetched,
                     base::Unretained(this), &run_loop));
  run_loop.Run();

  EXPECT_TRUE(gfx::test::AreBitmapsEqual(handler.GetFaviconOrFallback(),
                                         large_icon_service.favicon()));
  histogram_tester.ExpectUniqueSample(
      SupervisedUserFaviconRequestHandler::
          GetFaviconAvailabilityHistogramForTesting(),
      SupervisedUserFaviconRequestHandler::FaviconAvailability::kAvailable, 1);
}

TEST_F(SupervisedUserFaviconRequestHandlerTest, GetCachedFavicon) {
  base::HistogramTester histogram_tester;
  const GURL page_url = GURL("https://www.example.com");
  MockLargeIconService large_icon_service;
  large_icon_service.StoreIconInCache();
  SupervisedUserFaviconRequestHandler handler(page_url, &large_icon_service);

  // Confirm that the icon was retrieved from the cache on the first attempt
  // and no network request was made.
  EXPECT_CALL(large_icon_service,
              GetLargeIconRawBitmapForPageUrl(page_url, _, _, _, _, _))
      .Times(1);
  EXPECT_CALL(large_icon_service,
              GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
                  page_url, _, _, _))
      .Times(0);
  // Confirm that the icon was retrieved from the cache.
  EXPECT_CALL(large_icon_service,
              TouchIconFromGoogleServer(large_icon_service.kIconUrl));

  base::RunLoop run_loop;
  handler.StartFaviconFetch(
      base::BindOnce(&SupervisedUserFaviconRequestHandlerTest::OnFaviconFetched,
                     base::Unretained(this), &run_loop));
  run_loop.Run();

  EXPECT_TRUE(gfx::test::AreBitmapsEqual(handler.GetFaviconOrFallback(),
                                         large_icon_service.favicon()));
  histogram_tester.ExpectUniqueSample(
      SupervisedUserFaviconRequestHandler::
          GetFaviconAvailabilityHistogramForTesting(),
      SupervisedUserFaviconRequestHandler::FaviconAvailability::kAvailable, 1);
}

TEST_F(SupervisedUserFaviconRequestHandlerTest, GetFallbackFavicon) {
  base::HistogramTester histogram_tester;
  const GURL page_url = GURL("https://www.example.com");
  MockLargeIconService large_icon_service;
  large_icon_service.StoreIconInCache();
  SupervisedUserFaviconRequestHandler handler(page_url, &large_icon_service);

  // Confirm that the favicon is not fetched from a network request or from the
  // cache.
  EXPECT_CALL(large_icon_service,
              GetLargeIconImageOrFallbackStyleForPageUrl(page_url, _, _, _, _))
      .Times(0);
  EXPECT_CALL(large_icon_service,
              GetLargeIconOrFallbackStyleFromGoogleServerSkippingLocalCache(
                  page_url, _, _, _))
      .Times(0);
  EXPECT_CALL(large_icon_service,
              TouchIconFromGoogleServer(large_icon_service.kIconUrl))
      .Times(0);

  // Expect an icon to still be generated, even if it is not fetched.
  EXPECT_FALSE(handler.GetFaviconOrFallback().isNull());
  histogram_tester.ExpectUniqueSample(
      SupervisedUserFaviconRequestHandler::
          GetFaviconAvailabilityHistogramForTesting(),
      SupervisedUserFaviconRequestHandler::FaviconAvailability::kUnavailable,
      1);
}