1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/optimization_guide/core/hint_cache.h"
- #include <string>
- #include "base/bind.h"
- #include "base/files/scoped_temp_dir.h"
- #include "base/memory/raw_ptr.h"
- #include "base/run_loop.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/test/metrics/histogram_tester.h"
- #include "base/test/task_environment.h"
- #include "components/optimization_guide/core/optimization_guide_features.h"
- #include "components/optimization_guide/core/optimization_guide_store.h"
- #include "components/optimization_guide/core/proto_database_provider_test_base.h"
- #include "components/optimization_guide/core/store_update_data.h"
- #include "components/optimization_guide/proto/hint_cache.pb.h"
- #include "components/optimization_guide/proto/hints.pb.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "url/gurl.h"
- namespace optimization_guide {
- namespace {
- std::string GetHostDomainOrg(int index) {
- return "host.domain" + base::NumberToString(index) + ".org";
- }
- class HintCacheTest : public ProtoDatabaseProviderTestBase,
- public testing::WithParamInterface<bool> {
- public:
- HintCacheTest() : loaded_hint_(nullptr) {}
- HintCacheTest(const HintCacheTest&) = delete;
- HintCacheTest& operator=(const HintCacheTest&) = delete;
- ~HintCacheTest() override {}
- void SetUp() override { ProtoDatabaseProviderTestBase::SetUp(); }
- void TearDown() override {
- ProtoDatabaseProviderTestBase::TearDown();
- DestroyHintCache();
- }
- protected:
- // Creates and initializes the hint cache and optimization guide store and
- // waits for the callback indicating that initialization is complete.
- void CreateAndInitializeHintCache(int memory_cache_size,
- bool purge_existing_data = false) {
- auto database_path = temp_dir_.GetPath();
- auto database_task_runner = task_environment_.GetMainThreadTaskRunner();
- optimization_guide_store_ =
- IsBackedByPersistentStore()
- ? std::make_unique<OptimizationGuideStore>(
- db_provider_.get(), database_path, database_task_runner,
- /*pref_service_=*/nullptr)
- : nullptr;
- hint_cache_ = std::make_unique<HintCache>(
- optimization_guide_store_ ? optimization_guide_store_->AsWeakPtr()
- : nullptr,
- memory_cache_size);
- is_store_initialized_ = false;
- hint_cache_->Initialize(purge_existing_data,
- base::BindOnce(&HintCacheTest::OnStoreInitialized,
- base::Unretained(this)));
- while (!is_store_initialized_) {
- RunUntilIdle();
- }
- hint_cache_->SetClockForTesting(task_environment_.GetMockClock());
- }
- void DestroyHintCache() {
- hint_cache_.reset();
- optimization_guide_store_.reset();
- loaded_hint_ = nullptr;
- is_store_initialized_ = false;
- are_component_hints_updated_ = false;
- on_load_hint_callback_called_ = false;
- are_fetched_hints_updated_ = false;
- RunUntilIdle();
- }
- HintCache* hint_cache() { return hint_cache_.get(); }
- bool are_fetched_hints_updated() { return are_fetched_hints_updated_; }
- // Updates the cache with |component_data| and waits for callback indicating
- // that the update is complete.
- void UpdateComponentHints(std::unique_ptr<StoreUpdateData> component_data) {
- are_component_hints_updated_ = false;
- hint_cache_->UpdateComponentHints(
- std::move(component_data),
- base::BindOnce(&HintCacheTest::OnUpdateComponentHints,
- base::Unretained(this)));
- while (!are_component_hints_updated_) {
- RunUntilIdle();
- }
- }
- void UpdateFetchedHintsAndWait(
- std::unique_ptr<proto::GetHintsResponse> get_hints_response,
- base::Time stored_time,
- const base::flat_set<std::string>& hosts_fetched,
- const base::flat_set<GURL>& urls_fetched) {
- are_fetched_hints_updated_ = false;
- hint_cache_->UpdateFetchedHints(
- std::move(get_hints_response), stored_time, hosts_fetched, urls_fetched,
- base::BindOnce(&HintCacheTest::OnHintsUpdated, base::Unretained(this)));
- while (!are_fetched_hints_updated_)
- RunUntilIdle();
- }
- void OnHintsUpdated() { are_fetched_hints_updated_ = true; }
- // Loads hint for the specified host from the cache and waits for callback
- // indicating that loading the hint is complete.
- void LoadHint(const std::string& host) {
- on_load_hint_callback_called_ = false;
- loaded_hint_ = nullptr;
- hint_cache_->LoadHint(host, base::BindOnce(&HintCacheTest::OnLoadHint,
- base::Unretained(this)));
- while (!on_load_hint_callback_called_) {
- RunUntilIdle();
- }
- }
- const proto::Hint* GetLoadedHint() const { return loaded_hint_; }
- proto::Hint CreateHintForURL(
- const GURL& url,
- absl::optional<int> cache_duration_in_secs = absl::optional<int>()) {
- proto::Hint hint;
- hint.set_key(url.spec());
- hint.set_key_representation(proto::FULL_URL);
- if (cache_duration_in_secs)
- hint.mutable_max_cache_duration()->set_seconds(*cache_duration_in_secs);
- proto::PageHint* page_hint = hint.add_page_hints();
- page_hint->add_allowlisted_optimizations()->set_optimization_type(
- optimization_guide::proto::PERFORMANCE_HINTS);
- page_hint->set_page_pattern("whatever/*");
- return hint;
- }
- void MoveClockForwardBy(base::TimeDelta time_delta) {
- task_environment_.FastForwardBy(time_delta);
- RunUntilIdle();
- }
- void RunUntilIdle() {
- task_environment_.RunUntilIdle();
- base::RunLoop().RunUntilIdle();
- }
- bool IsBackedByPersistentStore() const { return GetParam(); }
- private:
- void OnStoreInitialized() { is_store_initialized_ = true; }
- void OnUpdateComponentHints() { are_component_hints_updated_ = true; }
- void OnLoadHint(const proto::Hint* hint) {
- on_load_hint_callback_called_ = true;
- loaded_hint_ = hint;
- }
- base::test::TaskEnvironment task_environment_{
- base::test::TaskEnvironment::TimeSource::MOCK_TIME};
- std::unique_ptr<OptimizationGuideStore> optimization_guide_store_;
- std::unique_ptr<HintCache> hint_cache_;
- raw_ptr<const proto::Hint> loaded_hint_;
- bool is_store_initialized_;
- bool are_component_hints_updated_;
- bool on_load_hint_callback_called_;
- bool are_fetched_hints_updated_;
- };
- INSTANTIATE_TEST_SUITE_P(WithPersistentStore,
- HintCacheTest,
- testing::Values(true, false));
- TEST_P(HintCacheTest, ComponentUpdate) {
- if (!IsBackedByPersistentStore())
- return;
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- base::Version version("2.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
- ASSERT_TRUE(update_data);
- proto::Hint hint1;
- hint1.set_key("subdomain.domain.org");
- hint1.set_key_representation(proto::HOST);
- proto::Hint hint2;
- hint2.set_key("host.domain.org");
- hint2.set_key_representation(proto::HOST);
- proto::Hint hint3;
- hint3.set_key("otherhost.subdomain.domain.org");
- hint3.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint1));
- update_data->MoveHintIntoUpdateData(std::move(hint2));
- update_data->MoveHintIntoUpdateData(std::move(hint3));
- UpdateComponentHints(std::move(update_data));
- // Not matched
- EXPECT_FALSE(hint_cache()->HasHint("domain.org"));
- EXPECT_FALSE(hint_cache()->HasHint("othersubdomain.domain.org"));
- // Matched
- EXPECT_TRUE(hint_cache()->HasHint("otherhost.subdomain.domain.org"));
- EXPECT_TRUE(hint_cache()->HasHint("host.domain.org"));
- EXPECT_TRUE(hint_cache()->HasHint("subdomain.domain.org"));
- }
- TEST_P(HintCacheTest, ComponentUpdateWithSameVersionIgnored) {
- if (!IsBackedByPersistentStore())
- return;
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- base::Version version("2.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
- ASSERT_TRUE(update_data);
- UpdateComponentHints(std::move(update_data));
- EXPECT_FALSE(hint_cache()->MaybeCreateUpdateDataForComponentHints(version));
- }
- TEST_P(HintCacheTest, ComponentUpdateWithEarlierVersionIgnored) {
- if (!IsBackedByPersistentStore())
- return;
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- base::Version version_1("1.0.0");
- base::Version version_2("2.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->MaybeCreateUpdateDataForComponentHints(version_2);
- ASSERT_TRUE(update_data);
- UpdateComponentHints(std::move(update_data));
- EXPECT_FALSE(hint_cache()->MaybeCreateUpdateDataForComponentHints(version_1));
- }
- TEST_P(HintCacheTest, ComponentUpdateWithLaterVersionProcessed) {
- if (!IsBackedByPersistentStore())
- return;
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- base::Version version_1("1.0.0");
- base::Version version_2("2.0.0");
- std::unique_ptr<StoreUpdateData> update_data_1 =
- hint_cache()->MaybeCreateUpdateDataForComponentHints(version_1);
- ASSERT_TRUE(update_data_1);
- proto::Hint hint1;
- hint1.set_key("subdomain.domain.org");
- hint1.set_key_representation(proto::HOST);
- proto::Hint hint2;
- hint2.set_key("host.domain.org");
- hint2.set_key_representation(proto::HOST);
- proto::Hint hint3;
- hint3.set_key("otherhost.subdomain.domain.org");
- hint3.set_key_representation(proto::HOST);
- update_data_1->MoveHintIntoUpdateData(std::move(hint1));
- update_data_1->MoveHintIntoUpdateData(std::move(hint2));
- update_data_1->MoveHintIntoUpdateData(std::move(hint3));
- UpdateComponentHints(std::move(update_data_1));
- // Not matched
- EXPECT_FALSE(hint_cache()->HasHint("domain.org"));
- EXPECT_FALSE(hint_cache()->HasHint("othersubdomain.domain.org"));
- // Matched
- EXPECT_TRUE(hint_cache()->HasHint("otherhost.subdomain.domain.org"));
- EXPECT_TRUE(hint_cache()->HasHint("host.domain.org"));
- EXPECT_TRUE(hint_cache()->HasHint("subdomain.domain.org"));
- std::unique_ptr<StoreUpdateData> update_data_2 =
- hint_cache()->MaybeCreateUpdateDataForComponentHints(version_2);
- ASSERT_TRUE(update_data_2);
- proto::Hint hint4;
- hint4.set_key("subdomain.domain2.org");
- hint4.set_key_representation(proto::HOST);
- proto::Hint hint5;
- hint5.set_key("host.domain2.org");
- hint5.set_key_representation(proto::HOST);
- proto::Hint hint6;
- hint6.set_key("otherhost.subdomain.domain2.org");
- hint6.set_key_representation(proto::HOST);
- update_data_2->MoveHintIntoUpdateData(std::move(hint4));
- update_data_2->MoveHintIntoUpdateData(std::move(hint5));
- update_data_2->MoveHintIntoUpdateData(std::move(hint6));
- UpdateComponentHints(std::move(update_data_2));
- // Not matched
- EXPECT_FALSE(hint_cache()->HasHint("otherhost.subdomain.domain.org"));
- EXPECT_FALSE(hint_cache()->HasHint("host.subdomain.domain.org"));
- EXPECT_FALSE(hint_cache()->HasHint("subhost.host.subdomain.domain.org"));
- EXPECT_FALSE(hint_cache()->HasHint("domain2.org"));
- EXPECT_FALSE(hint_cache()->HasHint("othersubdomain.domain2.org"));
- // Matched
- EXPECT_TRUE(hint_cache()->HasHint("otherhost.subdomain.domain2.org"));
- EXPECT_TRUE(hint_cache()->HasHint("subdomain.domain2.org"));
- EXPECT_TRUE(hint_cache()->HasHint("host.domain2.org"));
- }
- TEST_P(HintCacheTest, ComponentHintsAvailableAfterRestart) {
- if (!IsBackedByPersistentStore())
- return;
- for (int i = 0; i < 2; ++i) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize,
- false /*=purge_existing_data*/);
- base::Version version("2.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
- if (i == 0) {
- ASSERT_TRUE(update_data);
- proto::Hint hint1;
- hint1.set_key("subdomain.domain.org");
- hint1.set_key_representation(proto::HOST);
- proto::Hint hint2;
- hint2.set_key("host.domain.org");
- hint2.set_key_representation(proto::HOST);
- proto::Hint hint3;
- hint3.set_key("otherhost.subdomain.domain.org");
- hint3.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint1));
- update_data->MoveHintIntoUpdateData(std::move(hint2));
- update_data->MoveHintIntoUpdateData(std::move(hint3));
- UpdateComponentHints(std::move(update_data));
- } else {
- EXPECT_FALSE(update_data);
- }
- // Not matched
- EXPECT_FALSE(hint_cache()->HasHint("domain.org"));
- EXPECT_FALSE(hint_cache()->HasHint("othersubdomain.domain.org"));
- // Matched
- EXPECT_TRUE(hint_cache()->HasHint("otherhost.subdomain.domain.org"));
- EXPECT_TRUE(hint_cache()->HasHint("host.domain.org"));
- EXPECT_TRUE(hint_cache()->HasHint("subdomain.domain.org"));
- DestroyHintCache();
- }
- }
- TEST_P(HintCacheTest, ComponentHintsUpdatableAfterRestartWithPurge) {
- if (!IsBackedByPersistentStore())
- return;
- for (int i = 0; i < 2; ++i) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize,
- true /*=purge_existing_data*/);
- base::Version version("2.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
- ASSERT_TRUE(update_data);
- proto::Hint hint1;
- hint1.set_key("subdomain.domain.org");
- hint1.set_key_representation(proto::HOST);
- proto::Hint hint2;
- hint2.set_key("host.domain.org");
- hint2.set_key_representation(proto::HOST);
- proto::Hint hint3;
- hint3.set_key("otherhost.subdomain.domain.org");
- hint3.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint1));
- update_data->MoveHintIntoUpdateData(std::move(hint2));
- update_data->MoveHintIntoUpdateData(std::move(hint3));
- UpdateComponentHints(std::move(update_data));
- // Not matched
- EXPECT_FALSE(hint_cache()->HasHint("domain.org"));
- EXPECT_FALSE(hint_cache()->HasHint("othersubdomain.domain.org"));
- // Matched
- EXPECT_TRUE(hint_cache()->HasHint("otherhost.subdomain.domain.org"));
- EXPECT_TRUE(hint_cache()->HasHint("host.domain.org"));
- EXPECT_TRUE(hint_cache()->HasHint("subdomain.domain.org"));
- DestroyHintCache();
- }
- }
- TEST_P(HintCacheTest, ComponentHintsNotRetainedAfterRestartWithPurge) {
- if (!IsBackedByPersistentStore())
- return;
- for (int i = 0; i < 2; ++i) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize,
- true /*=purge_existing_data*/);
- base::Version version("2.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
- if (i == 0) {
- ASSERT_TRUE(update_data);
- proto::Hint hint1;
- hint1.set_key("subdomain.domain.org");
- hint1.set_key_representation(proto::HOST);
- proto::Hint hint2;
- hint2.set_key("host.domain.org");
- hint2.set_key_representation(proto::HOST);
- proto::Hint hint3;
- hint3.set_key("otherhost.subdomain.domain.org");
- hint3.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint1));
- update_data->MoveHintIntoUpdateData(std::move(hint2));
- update_data->MoveHintIntoUpdateData(std::move(hint3));
- UpdateComponentHints(std::move(update_data));
- } else {
- EXPECT_TRUE(update_data);
- }
- // Not matched
- EXPECT_FALSE(hint_cache()->HasHint("domain.org"));
- EXPECT_FALSE(hint_cache()->HasHint("othersubdomain.domain.org"));
- // Maybe matched
- bool should_match = (i == 0);
- EXPECT_EQ(hint_cache()->HasHint("otherhost.subdomain.domain.org"),
- should_match);
- EXPECT_EQ(hint_cache()->HasHint("subdomain.domain.org"), should_match);
- EXPECT_EQ(hint_cache()->HasHint("host.domain.org"), should_match);
- DestroyHintCache();
- }
- }
- TEST_P(HintCacheTest, TestMemoryCacheLeastRecentlyUsedPurge) {
- if (!IsBackedByPersistentStore())
- return;
- const int kTestHintCount = 10;
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- base::Version version("1.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
- ASSERT_TRUE(update_data);
- for (int i = 0; i < kTestHintCount; ++i) {
- proto::Hint hint;
- hint.set_key(GetHostDomainOrg(i));
- hint.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint));
- }
- UpdateComponentHints(std::move(update_data));
- for (int i = kTestHintCount - 1; i >= 0; --i) {
- std::string host = GetHostDomainOrg(i);
- EXPECT_TRUE(hint_cache()->HasHint(host));
- LoadHint(host);
- ASSERT_TRUE(GetLoadedHint());
- EXPECT_EQ(GetLoadedHint()->key(), host);
- }
- for (int i = 0; i < kTestHintCount; ++i) {
- std::string host = GetHostDomainOrg(i);
- if (i < kMemoryCacheSize) {
- ASSERT_TRUE(hint_cache()->GetHostKeyedHintIfLoaded(host));
- EXPECT_EQ(GetHostDomainOrg(i),
- hint_cache()->GetHostKeyedHintIfLoaded(host)->key());
- } else {
- EXPECT_FALSE(hint_cache()->GetHostKeyedHintIfLoaded(host));
- }
- EXPECT_TRUE(hint_cache()->HasHint(host));
- }
- }
- TEST_P(HintCacheTest, TestHostNotInCache) {
- if (!IsBackedByPersistentStore())
- return;
- const int kTestHintCount = 10;
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- base::Version version("1.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
- ASSERT_TRUE(update_data);
- for (int i = 0; i < kTestHintCount; ++i) {
- proto::Hint hint;
- hint.set_key(GetHostDomainOrg(i));
- hint.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint));
- }
- UpdateComponentHints(std::move(update_data));
- EXPECT_FALSE(hint_cache()->HasHint(GetHostDomainOrg(kTestHintCount)));
- }
- TEST_P(HintCacheTest, TestMemoryCacheLoadCallback) {
- if (!IsBackedByPersistentStore())
- return;
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- base::Version version("1.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
- ASSERT_TRUE(update_data);
- std::string hint_key = "subdomain.domain.org";
- proto::Hint hint;
- hint.set_key(hint_key);
- hint.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint));
- UpdateComponentHints(std::move(update_data));
- EXPECT_FALSE(hint_cache()->GetHostKeyedHintIfLoaded("subdomain.domain.org"));
- LoadHint("subdomain.domain.org");
- EXPECT_TRUE(hint_cache()->GetHostKeyedHintIfLoaded("subdomain.domain.org"));
- EXPECT_TRUE(GetLoadedHint());
- EXPECT_EQ(hint_key, GetLoadedHint()->key());
- }
- TEST_P(HintCacheTest, StoreValidFetchedHints) {
- if (!IsBackedByPersistentStore()) {
- // Checking the fetched hints update time is not relevant when we don't have
- // a backing store.
- return;
- }
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- // Default update time for empty optimization guide store is base::Time().
- EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), base::Time());
- std::unique_ptr<proto::GetHintsResponse> get_hints_response =
- std::make_unique<proto::GetHintsResponse>();
- proto::Hint* hint = get_hints_response->add_hints();
- hint->set_key_representation(proto::HOST);
- hint->set_key("host.domain.org");
- proto::PageHint* page_hint = hint->add_page_hints();
- page_hint->set_page_pattern("page pattern");
- base::Time stored_time = base::Time().Now();
- UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
- {"host.domain.org"}, {});
- EXPECT_TRUE(are_fetched_hints_updated());
- // Next update time for hints should be updated.
- EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), stored_time);
- }
- TEST_P(HintCacheTest, ParseEmptyFetchedHints) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- base::Time stored_time = base::Time().Now() + base::Days(1);
- std::unique_ptr<proto::GetHintsResponse> get_hints_response =
- std::make_unique<proto::GetHintsResponse>();
- UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
- {"host.domain.org"}, {});
- // Empty Fetched Hints causes the metadata entry to be updated if store is
- // available.
- EXPECT_TRUE(are_fetched_hints_updated());
- if (IsBackedByPersistentStore()) {
- EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), stored_time);
- } else {
- EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), base::Time());
- // Fetched hosts should still have an entry despite not getting a hint back
- // for it.
- EXPECT_TRUE(hint_cache()->HasHint("host.domain.org"));
- }
- }
- TEST_P(HintCacheTest, StoreValidFetchedHintsWithServerProvidedExpiryTime) {
- const int kMemoryCacheSize = 5;
- const int kFetchedHintExpirationSecs = 60;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- // Default update time for empty optimization guide store is base::Time().
- EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), base::Time());
- std::unique_ptr<proto::GetHintsResponse> get_hints_response =
- std::make_unique<proto::GetHintsResponse>();
- // Set server-provided expiration time.
- proto::Hint* hint = get_hints_response->add_hints();
- hint->set_key_representation(proto::HOST);
- hint->set_key("host.domain.org");
- hint->mutable_max_cache_duration()->set_seconds(kFetchedHintExpirationSecs);
- proto::PageHint* page_hint = hint->add_page_hints();
- page_hint->set_page_pattern("page pattern");
- base::Time stored_time = base::Time().Now();
- GURL navigation_url("https://foo.com");
- UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
- {"host.domain.org"}, {navigation_url});
- EXPECT_TRUE(are_fetched_hints_updated());
- if (IsBackedByPersistentStore()) {
- // Next update time for hints should be updated.
- EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), stored_time);
- } else {
- EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), base::Time());
- }
- // Should be loaded right when response is received.
- EXPECT_TRUE(hint_cache()->GetHostKeyedHintIfLoaded("host.domain.org"));
- // Set time so hint should be expired.
- MoveClockForwardBy(base::Seconds(kFetchedHintExpirationSecs + 1));
- EXPECT_FALSE(hint_cache()->GetHostKeyedHintIfLoaded("host.domain.org"));
- }
- TEST_P(HintCacheTest, StoreValidFetchedHintsWithDefaultExpiryTime) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- // Default update time for empty optimization guide store is base::Time().
- EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), base::Time());
- std::unique_ptr<proto::GetHintsResponse> get_hints_response =
- std::make_unique<proto::GetHintsResponse>();
- proto::Hint* hint = get_hints_response->add_hints();
- hint->set_key_representation(proto::HOST);
- hint->set_key("host.domain.org");
- proto::PageHint* page_hint = hint->add_page_hints();
- page_hint->set_page_pattern("page pattern");
- base::Time stored_time = base::Time().Now();
- UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
- {"host.domain.org"}, {});
- EXPECT_TRUE(are_fetched_hints_updated());
- if (IsBackedByPersistentStore()) {
- // Next update time for hints should be updated.
- EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), stored_time);
- } else {
- EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), base::Time());
- }
- // Should be loaded right when response is received.
- EXPECT_TRUE(hint_cache()->GetHostKeyedHintIfLoaded("host.domain.org"));
- // Set time so hint should be expired.
- MoveClockForwardBy(
- optimization_guide::features::StoredFetchedHintsFreshnessDuration() +
- base::Seconds(1));
- EXPECT_FALSE(hint_cache()->GetHostKeyedHintIfLoaded("host.domain.org"));
- }
- TEST_P(HintCacheTest, CacheValidURLKeyedHint) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->CreateUpdateDataForFetchedHints(base::Time());
- ASSERT_EQ(update_data != nullptr, IsBackedByPersistentStore());
- GURL url("https://whatever.com/r/werd");
- google::protobuf::RepeatedPtrField<proto::Hint> hints;
- *(hints.Add()) = CreateHintForURL(url);
- // Only URL-keyed hint included so there are no hints to store within the
- // update data.
- EXPECT_FALSE(hint_cache()->ProcessAndCacheHints(
- &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
- EXPECT_TRUE(hint_cache()->GetURLKeyedHint(url));
- }
- TEST_P(HintCacheTest, URLKeyedHintExpired) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->CreateUpdateDataForFetchedHints(base::Time());
- ASSERT_EQ(update_data != nullptr, IsBackedByPersistentStore());
- GURL url("https://whatever.com/r/werd");
- int cache_duration_in_secs = 60;
- google::protobuf::RepeatedPtrField<proto::Hint> hints;
- *(hints.Add()) = CreateHintForURL(url, cache_duration_in_secs);
- // Only URL-keyed hint included so there are no hints to store within the
- // update data.
- EXPECT_FALSE(hint_cache()->ProcessAndCacheHints(
- &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
- EXPECT_TRUE(hint_cache()->GetURLKeyedHint(url));
- MoveClockForwardBy(base::Seconds(cache_duration_in_secs + 1));
- EXPECT_FALSE(hint_cache()->GetURLKeyedHint(url));
- }
- TEST_P(HintCacheTest, PurgeExpiredFetchedHints) {
- if (!IsBackedByPersistentStore()) {
- // Purging expired fetched hints is only really relevant for when we have
- // a backing store.
- return;
- }
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->CreateUpdateDataForFetchedHints(base::Time());
- ASSERT_TRUE(update_data);
- int cache_duration_in_secs = 60;
- std::unique_ptr<proto::GetHintsResponse> get_hints_response =
- std::make_unique<proto::GetHintsResponse>();
- std::string host = "shouldpurge.com";
- proto::Hint* hint1 = get_hints_response->add_hints();
- hint1->set_key_representation(proto::HOST);
- hint1->set_key(host);
- hint1->mutable_max_cache_duration()->set_seconds(cache_duration_in_secs);
- proto::PageHint* page_hint1 = hint1->add_page_hints();
- page_hint1->set_page_pattern("page pattern");
- std::string host2 = "notpurged.com";
- proto::Hint* hint2 = get_hints_response->add_hints();
- hint2->set_key_representation(proto::HOST);
- hint2->set_key(host2);
- hint2->mutable_max_cache_duration()->set_seconds(cache_duration_in_secs * 2);
- proto::PageHint* page_hint2 = hint2->add_page_hints();
- page_hint2->set_page_pattern("page pattern");
- base::Time stored_time = base::Time().Now();
- UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
- {"shouldpurge.com", "notpurged.com"}, {});
- EXPECT_TRUE(are_fetched_hints_updated());
- EXPECT_TRUE(hint_cache()->HasHint("shouldpurge.com"));
- EXPECT_TRUE(hint_cache()->HasHint("notpurged.com"));
- MoveClockForwardBy(base::Seconds(cache_duration_in_secs + 1));
- hint_cache()->PurgeExpiredFetchedHints();
- RunUntilIdle();
- EXPECT_FALSE(hint_cache()->HasHint("shouldpurge.com"));
- EXPECT_TRUE(hint_cache()->HasHint("notpurged.com"));
- }
- TEST_P(HintCacheTest, ClearFetchedHints) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->CreateUpdateDataForFetchedHints(base::Time());
- ASSERT_EQ(update_data != nullptr, IsBackedByPersistentStore());
- GURL url("https://whatever.com/r/werd");
- int cache_duration_in_secs = 60;
- google::protobuf::RepeatedPtrField<proto::Hint> hints;
- *(hints.Add()) = CreateHintForURL(url, cache_duration_in_secs);
- std::unique_ptr<proto::GetHintsResponse> get_hints_response =
- std::make_unique<proto::GetHintsResponse>();
- std::string host = "host.com";
- proto::Hint* hint = get_hints_response->add_hints();
- hint->set_key_representation(proto::HOST);
- hint->set_key(host);
- proto::PageHint* page_hint = hint->add_page_hints();
- page_hint->set_page_pattern("page pattern");
- base::Time stored_time = base::Time().Now();
- UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
- {"host.com"}, {});
- EXPECT_TRUE(are_fetched_hints_updated());
- LoadHint(host);
- // Only URL-keyed hint included so there are no hints to store within the
- // update data.
- EXPECT_FALSE(hint_cache()->ProcessAndCacheHints(
- &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
- EXPECT_TRUE(hint_cache()->GetURLKeyedHint(url));
- EXPECT_TRUE(hint_cache()->GetHostKeyedHintIfLoaded(host));
- hint_cache()->ClearFetchedHints();
- EXPECT_FALSE(hint_cache()->GetURLKeyedHint(url));
- EXPECT_FALSE(hint_cache()->GetHostKeyedHintIfLoaded(host));
- }
- TEST_P(HintCacheTest, UnsupportedURLsForURLKeyedHints) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->CreateUpdateDataForFetchedHints(base::Time());
- ASSERT_EQ(update_data != nullptr, IsBackedByPersistentStore());
- GURL https_url("https://whatever.com/r/werd");
- GURL http_url("http://werd.com/werd/");
- GURL file_url("file://dog.png");
- GURL chrome_url("chrome://dog.png");
- GURL auth_url("https://username:password@www.example.com/");
- google::protobuf::RepeatedPtrField<proto::Hint> hints;
- *(hints.Add()) = CreateHintForURL(https_url);
- *(hints.Add()) = CreateHintForURL(http_url);
- *(hints.Add()) = CreateHintForURL(file_url);
- *(hints.Add()) = CreateHintForURL(chrome_url);
- *(hints.Add()) = CreateHintForURL(auth_url);
- // Only URL-keyed hint included so there are no hints to store within the
- // update data.
- EXPECT_FALSE(hint_cache()->ProcessAndCacheHints(
- &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
- EXPECT_TRUE(hint_cache()->GetURLKeyedHint(https_url));
- EXPECT_TRUE(hint_cache()->GetURLKeyedHint(http_url));
- EXPECT_FALSE(hint_cache()->GetURLKeyedHint(file_url));
- EXPECT_FALSE(hint_cache()->GetURLKeyedHint(chrome_url));
- EXPECT_FALSE(hint_cache()->GetURLKeyedHint(auth_url));
- }
- TEST_P(HintCacheTest, URLsWithNoURLKeyedHints) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- std::unique_ptr<StoreUpdateData> update_data =
- hint_cache()->CreateUpdateDataForFetchedHints(base::Time());
- ASSERT_EQ(update_data != nullptr, IsBackedByPersistentStore());
- GURL https_url_without_hint("https://whatever.com/r/nohint");
- GURL https_url_with_hint("https://whatever.com/r/hint");
- GURL https_url_unseen("https://unseen.com/new");
- GURL file_url("file://dog.png");
- GURL chrome_url("chrome://dog.png");
- GURL auth_url("https://username:password@www.example.com/");
- google::protobuf::RepeatedPtrField<proto::Hint> hints;
- *(hints.Add()) = CreateHintForURL(https_url_with_hint);
- // Only URL-keyed hint included so there are no hints to store within the
- // update data.
- EXPECT_FALSE(hint_cache()->ProcessAndCacheHints(
- &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
- // Add the url without hint to the url-keyed cache via UpdateFetchedHints.
- std::unique_ptr<proto::GetHintsResponse> get_hints_response =
- std::make_unique<proto::GetHintsResponse>();
- std::string host = "host.com";
- proto::Hint* hint = get_hints_response->add_hints();
- hint->set_key_representation(proto::HOST);
- hint->set_key(host);
- proto::PageHint* page_hint = hint->add_page_hints();
- page_hint->set_page_pattern("page pattern");
- base::Time stored_time = base::Time().Now();
- UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
- {"host.com"}, {https_url_without_hint});
- EXPECT_TRUE(hint_cache()->HasURLKeyedEntryForURL(https_url_with_hint));
- EXPECT_TRUE(hint_cache()->HasURLKeyedEntryForURL(https_url_with_hint));
- EXPECT_FALSE(hint_cache()->HasURLKeyedEntryForURL(file_url));
- EXPECT_FALSE(hint_cache()->HasURLKeyedEntryForURL(chrome_url));
- EXPECT_FALSE(hint_cache()->HasURLKeyedEntryForURL(auth_url));
- EXPECT_FALSE(hint_cache()->HasURLKeyedEntryForURL(https_url_unseen));
- }
- TEST_P(HintCacheTest, ProcessHintsNoUpdateData) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- proto::Hint hint;
- hint.set_key("whatever.com");
- hint.set_key_representation(proto::HOST);
- proto::PageHint* page_hint = hint.add_page_hints();
- page_hint->set_page_pattern("foo.org/*/one/");
- google::protobuf::RepeatedPtrField<proto::Hint> hints;
- *(hints.Add()) = hint;
- EXPECT_EQ(hint_cache()->ProcessAndCacheHints(&hints, nullptr),
- !IsBackedByPersistentStore());
- }
- TEST_P(HintCacheTest,
- ProcessHintsWithNoPageHintsOrAllowlistedOptimizationsAndUpdateData) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- proto::Hint hint;
- hint.set_key("whatever.com");
- hint.set_key_representation(proto::HOST);
- google::protobuf::RepeatedPtrField<proto::Hint> hints;
- *(hints.Add()) = hint;
- std::unique_ptr<StoreUpdateData> update_data =
- StoreUpdateData::CreateComponentStoreUpdateData(base::Version("1.0.0"));
- EXPECT_FALSE(hint_cache()->ProcessAndCacheHints(
- &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
- if (IsBackedByPersistentStore()) {
- // Verify there is 1 store entries: 1 for the metadata entry.
- EXPECT_EQ(1ul, update_data->TakeUpdateEntries()->size());
- }
- }
- TEST_P(HintCacheTest,
- ProcessHintsWithNoPageHintsButHasAllowlistedOptimizationsAndUpdateData) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- proto::Hint hint;
- hint.set_key("whatever.com");
- hint.set_key_representation(proto::HOST);
- hint.add_allowlisted_optimizations()->set_optimization_type(
- optimization_guide::proto::DEFER_ALL_SCRIPT);
- google::protobuf::RepeatedPtrField<proto::Hint> hints;
- *(hints.Add()) = hint;
- std::unique_ptr<StoreUpdateData> update_data =
- StoreUpdateData::CreateComponentStoreUpdateData(base::Version("1.0.0"));
- EXPECT_TRUE(hint_cache()->ProcessAndCacheHints(
- &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
- if (IsBackedByPersistentStore()) {
- // Verify there is 1 store entries: 1 for the metadata entry plus the 1
- // added hint entry.
- EXPECT_EQ(2ul, update_data->TakeUpdateEntries()->size());
- }
- }
- TEST_P(HintCacheTest, ProcessHintsWithPageHintsAndUpdateData) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- google::protobuf::RepeatedPtrField<proto::Hint> hints;
- proto::Hint hint;
- hint.set_key("foo.org");
- hint.set_key_representation(proto::HOST);
- proto::PageHint* page_hint = hint.add_page_hints();
- page_hint->set_page_pattern("foo.org/*/one/");
- *(hints.Add()) = hint;
- proto::Hint no_page_hints_hint;
- no_page_hints_hint.set_key("nopagehints.com");
- no_page_hints_hint.set_key_representation(proto::HOST);
- *(hints.Add()) = no_page_hints_hint;
- std::unique_ptr<StoreUpdateData> update_data =
- StoreUpdateData::CreateComponentStoreUpdateData(base::Version("1.0.0"));
- EXPECT_TRUE(hint_cache()->ProcessAndCacheHints(
- &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
- if (IsBackedByPersistentStore()) {
- // Verify there are 2 store entries: 1 for the metadata entry plus
- // the 1 added hint entry.
- EXPECT_EQ(2ul, update_data->TakeUpdateEntries()->size());
- }
- }
- TEST_P(HintCacheTest, RemoveHintsForURLs) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- int cache_duration_in_secs = 60;
- std::string host = "host.com";
- GURL url("https://bar.com/r/baz");
- std::unique_ptr<proto::GetHintsResponse> get_hints_response =
- std::make_unique<proto::GetHintsResponse>();
- *(get_hints_response->add_hints()) =
- CreateHintForURL(url, cache_duration_in_secs);
- proto::Hint* hint = get_hints_response->add_hints();
- hint->set_key_representation(proto::HOST);
- hint->set_key(host);
- proto::PageHint* page_hint = hint->add_page_hints();
- page_hint->set_page_pattern("page pattern");
- UpdateFetchedHintsAndWait(std::move(get_hints_response), base::Time().Now(),
- {host}, {url});
- EXPECT_TRUE(are_fetched_hints_updated());
- EXPECT_TRUE(hint_cache()->HasHint(host));
- EXPECT_TRUE(hint_cache()->HasURLKeyedEntryForURL(url));
- hint_cache()->RemoveHintsForURLs({url, GURL(host)});
- EXPECT_TRUE(hint_cache()->HasHint(host));
- EXPECT_FALSE(hint_cache()->HasURLKeyedEntryForURL(url));
- }
- TEST_P(HintCacheTest, RemoveHintsForHosts) {
- const int kMemoryCacheSize = 5;
- CreateAndInitializeHintCache(kMemoryCacheSize);
- int cache_duration_in_secs = 60;
- std::string host = "host.com";
- GURL url("https://bar.com/r/baz");
- std::unique_ptr<proto::GetHintsResponse> get_hints_response =
- std::make_unique<proto::GetHintsResponse>();
- *(get_hints_response->add_hints()) =
- CreateHintForURL(url, cache_duration_in_secs);
- proto::Hint* hint = get_hints_response->add_hints();
- hint->set_key_representation(proto::HOST);
- hint->set_key(host);
- proto::PageHint* page_hint = hint->add_page_hints();
- page_hint->set_page_pattern("page pattern");
- UpdateFetchedHintsAndWait(std::move(get_hints_response), base::Time().Now(),
- {host}, {url});
- EXPECT_TRUE(are_fetched_hints_updated());
- EXPECT_TRUE(hint_cache()->HasHint(host));
- EXPECT_TRUE(hint_cache()->HasURLKeyedEntryForURL(url));
- std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
- hint_cache()->RemoveHintsForHosts(run_loop->QuitClosure(),
- {url.spec(), host});
- run_loop->Run();
- EXPECT_FALSE(hint_cache()->HasHint(host));
- EXPECT_TRUE(hint_cache()->HasURLKeyedEntryForURL(url));
- }
- } // namespace
- } // namespace optimization_guide
|