| // Copyright 2023 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/thumbnail/cc/thumbnail_cache.h" |
| |
| #include "base/memory/weak_ptr.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/task_environment.h" |
| #include "cc/resources/ui_resource_client.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/android/ui_android_export.h" |
| |
| namespace thumbnail { |
| namespace { |
| |
| constexpr int kKiB = 1024; |
| constexpr int kN32PixelSize = 4; |
| constexpr int kDefaultCacheSize = 3; |
| constexpr int kCompressionQueueMaxSize = 2; |
| constexpr int kWriteQueueMaxSize = 2; |
| |
| class MockUIResourceProvider : public ui::UIResourceProvider { |
| public: |
| MOCK_METHOD(cc::UIResourceId, |
| CreateUIResource, |
| (cc::UIResourceClient*), |
| (override)); |
| MOCK_METHOD(void, DeleteUIResource, (cc::UIResourceId), (override)); |
| MOCK_METHOD(bool, SupportsETC1NonPowerOfTwo, (), (const, override)); |
| |
| base::WeakPtr<UIResourceProvider> GetWeakPtr() { |
| return weak_factory_.GetWeakPtr(); |
| } |
| |
| private: |
| base::WeakPtrFactory<MockUIResourceProvider> weak_factory_{this}; |
| }; |
| |
| } // namespace |
| |
| class ThumbnailCacheTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| thumbnail_cache_ = std::make_unique<ThumbnailCache>( |
| kDefaultCacheSize, kCompressionQueueMaxSize, kWriteQueueMaxSize, |
| /*save_jpeg_thumbnails=*/true); |
| thumbnail_cache_->SetUIResourceProvider(ui_resource_provider_.GetWeakPtr()); |
| |
| EXPECT_CALL(ui_resource_provider_, CreateUIResource(::testing::_)) |
| .WillRepeatedly(::testing::Return(1)); |
| } |
| |
| void TearDown() override {} |
| |
| ThumbnailCache& thumbnail_cache() { return *thumbnail_cache_; } |
| void RecordCacheMetrics() { thumbnail_cache_->RecordCacheMetrics(); } |
| |
| content::BrowserTaskEnvironment task_environment_; |
| |
| private: |
| MockUIResourceProvider ui_resource_provider_; |
| std::unique_ptr<ThumbnailCache> thumbnail_cache_; |
| }; |
| |
| // TODO(crbug.com/40885026): Tests are being added in the process of refactoring |
| // and optimizing the ThumbnailCache for modern usage add more tests here. |
| |
| TEST_F(ThumbnailCacheTest, PruneCache) { |
| constexpr int kTabId1 = 1; |
| constexpr int kTabId2 = 2; |
| constexpr int kDimension = 16; |
| SkBitmap bitmap; |
| ASSERT_TRUE(bitmap.tryAllocN32Pixels(kDimension * kKiB, kDimension)); |
| bitmap.setImmutable(); |
| |
| thumbnail_cache().UpdateVisibleIds(std::vector<TabId>({kTabId1, kTabId2}), |
| -1); |
| EXPECT_TRUE(thumbnail_cache().CheckAndUpdateThumbnailMetaData( |
| kTabId1, GURL("https://www.foo.com/"), /*force_update=*/false)); |
| std::unique_ptr<ThumbnailCaptureTracker, base::OnTaskRunnerDeleter> tracker1( |
| new ThumbnailCaptureTracker(base::DoNothing()), |
| base::OnTaskRunnerDeleter( |
| base::SequencedTaskRunner::GetCurrentDefault())); |
| thumbnail_cache().Put(kTabId1, std::move(tracker1), bitmap, |
| /*thumbnail_scale=*/1.0f); |
| |
| EXPECT_TRUE(thumbnail_cache().CheckAndUpdateThumbnailMetaData( |
| kTabId2, GURL("https://www.bar.com/"), /*force_update=*/false)); |
| std::unique_ptr<ThumbnailCaptureTracker, base::OnTaskRunnerDeleter> tracker2( |
| new ThumbnailCaptureTracker(base::DoNothing()), |
| base::OnTaskRunnerDeleter( |
| base::SequencedTaskRunner::GetCurrentDefault())); |
| thumbnail_cache().Put(kTabId2, std::move(tracker2), bitmap, |
| /*thumbnail_scale=*/1.0f); |
| |
| EXPECT_TRUE(thumbnail_cache().Get(kTabId1, false)); |
| EXPECT_TRUE(thumbnail_cache().Get(kTabId2, false)); |
| |
| thumbnail_cache().UpdateVisibleIds({kTabId1, kTabId2}, kTabId1); |
| EXPECT_TRUE(thumbnail_cache().Get(kTabId1, false)); |
| EXPECT_TRUE(thumbnail_cache().Get(kTabId2, false)); |
| |
| thumbnail_cache().UpdateVisibleIds({kTabId1, kTabId2}, -1); |
| EXPECT_TRUE(thumbnail_cache().Get(kTabId1, false)); |
| EXPECT_TRUE(thumbnail_cache().Get(kTabId2, false)); |
| |
| thumbnail_cache().UpdateVisibleIds({kTabId2}, kTabId1); |
| EXPECT_FALSE(thumbnail_cache().Get(kTabId1, false)); |
| EXPECT_TRUE(thumbnail_cache().Get(kTabId2, false)); |
| |
| thumbnail_cache().UpdateVisibleIds({kTabId1}, kTabId1); |
| // The thumbnail will not be paged in yet although will be scheduled. |
| EXPECT_FALSE(thumbnail_cache().Get(kTabId1, false)); |
| EXPECT_FALSE(thumbnail_cache().Get(kTabId2, false)); |
| } |
| |
| TEST_F(ThumbnailCacheTest, MetricsEmission) { |
| base::HistogramTester histograms; |
| histograms.ExpectTotalCount("Android.ThumbnailCache.InMemoryCacheEntries", 0); |
| histograms.ExpectTotalCount("Android.ThumbnailCache.InMemoryCacheSize", 0); |
| |
| SkBitmap bitmap; |
| constexpr int kTabId = 4; |
| constexpr int kDimension = 4; |
| ASSERT_TRUE(bitmap.tryAllocN32Pixels(kDimension * kKiB, kDimension)); |
| bitmap.setImmutable(); |
| thumbnail_cache().UpdateVisibleIds(std::vector<TabId>({kTabId}), -1); |
| EXPECT_TRUE(thumbnail_cache().CheckAndUpdateThumbnailMetaData( |
| kTabId, GURL("https://www.foo.com/"), /*force_update=*/false)); |
| std::unique_ptr<ThumbnailCaptureTracker, base::OnTaskRunnerDeleter> tracker( |
| new ThumbnailCaptureTracker(base::DoNothing()), |
| base::OnTaskRunnerDeleter( |
| base::SequencedTaskRunner::GetCurrentDefault())); |
| thumbnail_cache().Put(kTabId, std::move(tracker), bitmap, |
| /*thumbnail_scale=*/1.0f); |
| RecordCacheMetrics(); |
| |
| histograms.ExpectTotalCount("Android.ThumbnailCache.InMemoryCacheEntries", 1); |
| histograms.ExpectTotalCount("Android.ThumbnailCache.InMemoryCacheSize", 1); |
| histograms.ExpectUniqueSample("Android.ThumbnailCache.InMemoryCacheEntries", |
| 1, 1); |
| histograms.ExpectUniqueSample("Android.ThumbnailCache.InMemoryCacheSize", |
| kDimension * kDimension * kN32PixelSize, 1); |
| } |
| |
| TEST_F(ThumbnailCacheTest, InvalidateIfChanged) { |
| constexpr int kTabId1 = 1; |
| constexpr int kDimension = 16; |
| SkBitmap bitmap; |
| ASSERT_TRUE(bitmap.tryAllocN32Pixels(kDimension * kKiB, kDimension)); |
| bitmap.setImmutable(); |
| |
| thumbnail_cache().UpdateVisibleIds(std::vector<TabId>({kTabId1}), -1); |
| GURL url("https://www.foo.com/"); |
| EXPECT_TRUE(thumbnail_cache().CheckAndUpdateThumbnailMetaData( |
| kTabId1, url, /*force_update=*/false)); |
| std::unique_ptr<ThumbnailCaptureTracker, base::OnTaskRunnerDeleter> tracker1( |
| new ThumbnailCaptureTracker(base::DoNothing()), |
| base::OnTaskRunnerDeleter( |
| base::SequencedTaskRunner::GetCurrentDefault())); |
| thumbnail_cache().Put(kTabId1, std::move(tracker1), bitmap, |
| /*thumbnail_scale=*/1.0f); |
| |
| EXPECT_TRUE(thumbnail_cache().Get(kTabId1, false)); |
| |
| thumbnail_cache().InvalidateThumbnailIfChanged(kTabId1, url); |
| EXPECT_TRUE(thumbnail_cache().Get(kTabId1, false)); |
| |
| thumbnail_cache().InvalidateThumbnailIfChanged(kTabId1, GURL()); |
| EXPECT_TRUE(thumbnail_cache().Get(kTabId1, false)); |
| |
| thumbnail_cache().InvalidateThumbnailIfChanged(kTabId1, |
| GURL("https://www.bar.com/")); |
| EXPECT_FALSE(thumbnail_cache().Get(kTabId1, false)); |
| } |
| |
| } // namespace thumbnail |