12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648 |
- // Copyright 2019 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/optimization_guide_store.h"
- #include <string>
- #include <vector>
- #include "base/bind.h"
- #include "base/files/file_util.h"
- #include "base/files/scoped_temp_dir.h"
- #include "base/memory/raw_ptr.h"
- #include "base/strings/string_number_conversions.h"
- #include "base/test/metrics/histogram_tester.h"
- #include "base/test/task_environment.h"
- #include "components/leveldb_proto/testing/fake_db.h"
- #include "components/optimization_guide/core/model_util.h"
- #include "components/optimization_guide/core/optimization_guide_features.h"
- #include "components/optimization_guide/core/optimization_guide_prefs.h"
- #include "components/optimization_guide/core/optimization_guide_util.h"
- #include "components/optimization_guide/core/store_update_data.h"
- #include "components/optimization_guide/proto/hint_cache.pb.h"
- #include "components/optimization_guide/proto/models.pb.h"
- #include "components/prefs/pref_registry_simple.h"
- #include "components/prefs/scoped_user_pref_update.h"
- #include "components/sync_preferences/testing_pref_service_syncable.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include "url/gurl.h"
- using leveldb_proto::test::FakeDB;
- using testing::Mock;
- namespace optimization_guide {
- namespace {
- constexpr char kDefaultComponentVersion[] = "1.0.0";
- constexpr char kUpdateComponentVersion[] = "2.0.0";
- std::string GetHost(size_t id) {
- // Host alternates between two different domain types depending on
- // whether the id is odd or even.
- if (id % 2 == 0) {
- return "domain" + base::NumberToString(id) + ".org";
- } else {
- return "different.domain" + base::NumberToString(id) + ".co.in";
- }
- }
- enum class MetadataSchemaState {
- kMissing,
- kInvalid,
- kValid,
- };
- std::unique_ptr<proto::PredictionModel> CreatePredictionModel() {
- std::unique_ptr<optimization_guide::proto::PredictionModel> prediction_model =
- std::make_unique<optimization_guide::proto::PredictionModel>();
- optimization_guide::proto::ModelInfo* model_info =
- prediction_model->mutable_model_info();
- model_info->set_version(1);
- model_info->set_optimization_target(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
- model_info->add_supported_model_engine_versions(
- proto::ModelEngineVersion::MODEL_ENGINE_VERSION_DECISION_TREE);
- return prediction_model;
- }
- } // namespace
- class OptimizationGuideStoreTest : public testing::Test {
- public:
- using StoreEntry = proto::StoreEntry;
- using StoreEntryMap = std::map<OptimizationGuideStore::EntryKey, StoreEntry>;
- OptimizationGuideStoreTest() = default;
- OptimizationGuideStoreTest(const OptimizationGuideStoreTest&) = delete;
- OptimizationGuideStoreTest& operator=(const OptimizationGuideStoreTest&) =
- delete;
- void SetUp() override {
- ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
- pref_service_ = std::make_unique<TestingPrefServiceSimple>();
- prefs::RegisterProfilePrefs(pref_service_->registry());
- }
- void TearDown() override {
- last_loaded_hint_.reset();
- pref_service_.reset();
- }
- // Initializes the entries contained within the database on startup.
- void SeedInitialData(
- MetadataSchemaState state,
- absl::optional<size_t> component_hint_count = absl::optional<size_t>(),
- absl::optional<base::Time> fetched_hints_update =
- absl::optional<base::Time>()) {
- db_store_.clear();
- // Add a metadata schema entry if its state isn't kMissing. The version
- // entry version is set to the store's current version if the state is
- // kValid; otherwise, it's set to the invalid version of "0".
- if (state == MetadataSchemaState::kValid) {
- db_store_[OptimizationGuideStore::GetMetadataTypeEntryKey(
- OptimizationGuideStore::MetadataType::kSchema)]
- .set_version(OptimizationGuideStore::kStoreSchemaVersion);
- } else if (state == MetadataSchemaState::kInvalid) {
- db_store_[OptimizationGuideStore::GetMetadataTypeEntryKey(
- OptimizationGuideStore::MetadataType::kSchema)]
- .set_version("0");
- }
- // If the database is being seeded with component hints, it is indicated
- // with a provided count. Add the component metadata with the default
- // component version and then add the indicated number of component hints.
- // if (component_hint_count && component_hint_count >
- // static_cast<size_t>(0)) {
- if (component_hint_count && component_hint_count > 0u) {
- db_store_[OptimizationGuideStore::GetMetadataTypeEntryKey(
- OptimizationGuideStore::MetadataType::kComponent)]
- .set_version(kDefaultComponentVersion);
- OptimizationGuideStore::EntryKeyPrefix component_hint_key_prefix =
- OptimizationGuideStore::GetComponentHintEntryKeyPrefix(
- base::Version(kDefaultComponentVersion));
- for (size_t i = 0; i < component_hint_count.value(); ++i) {
- std::string host = GetHost(i);
- StoreEntry& entry = db_store_[component_hint_key_prefix + host];
- entry.set_entry_type(static_cast<proto::StoreEntryType>(
- OptimizationGuideStore::StoreEntryType::kComponentHint));
- proto::Hint* hint = entry.mutable_hint();
- hint->set_key(host);
- hint->set_key_representation(proto::HOST);
- proto::PageHint* page_hint = hint->add_page_hints();
- page_hint->set_page_pattern("page pattern " + base::NumberToString(i));
- }
- }
- if (fetched_hints_update) {
- db_store_[OptimizationGuideStore::GetMetadataTypeEntryKey(
- OptimizationGuideStore::MetadataType::kFetched)]
- .set_update_time_secs(
- fetched_hints_update->ToDeltaSinceWindowsEpoch().InSeconds());
- }
- }
- // Moves the specified number of component hints into the update data.
- void SeedComponentUpdateData(StoreUpdateData* update_data,
- size_t component_hint_count) {
- for (size_t i = 0; i < component_hint_count; ++i) {
- std::string host = GetHost(i);
- proto::Hint hint;
- hint.set_key(host);
- hint.set_key_representation(proto::HOST);
- proto::PageHint* page_hint = hint.add_page_hints();
- page_hint->set_page_pattern("page pattern " + base::NumberToString(i));
- update_data->MoveHintIntoUpdateData(std::move(hint));
- }
- }
- // Moves the specified number of fetched hints into the update data.
- void SeedFetchedUpdateData(StoreUpdateData* update_data,
- size_t fetched_hint_count) {
- for (size_t i = 0; i < fetched_hint_count; ++i) {
- std::string host = GetHost(i);
- proto::Hint hint;
- hint.set_key(host);
- hint.set_key_representation(proto::HOST);
- proto::PageHint* page_hint = hint.add_page_hints();
- page_hint->set_page_pattern("page pattern " + base::NumberToString(i));
- update_data->MoveHintIntoUpdateData(std::move(hint));
- }
- }
- // Moves a prediction model with |optimization_target| into the update data.
- void SeedPredictionModelUpdateData(
- StoreUpdateData* update_data,
- optimization_guide::proto::OptimizationTarget optimization_target,
- absl::optional<base::FilePath> model_file_path = absl::nullopt,
- absl::optional<proto::ModelInfo> info = absl::nullopt,
- absl::optional<base::Time> expiry_time = absl::nullopt) {
- std::unique_ptr<optimization_guide::proto::PredictionModel>
- prediction_model = CreatePredictionModel();
- if (info)
- prediction_model->mutable_model_info()->MergeFrom(*info);
- prediction_model->mutable_model_info()->set_optimization_target(
- optimization_target);
- if (expiry_time) {
- auto diff = expiry_time.value() - base::Time::Now();
- prediction_model->mutable_model_info()
- ->mutable_valid_duration()
- ->set_seconds(diff.InSeconds());
- }
- if (model_file_path) {
- prediction_model->mutable_model()->set_download_url(
- FilePathToString(*model_file_path));
- }
- update_data->CopyPredictionModelIntoUpdateData(*prediction_model);
- }
- void CreateDatabase() {
- // Reset everything.
- db_ = nullptr;
- guide_store_.reset();
- // Setup the fake db and the class under test.
- auto db = std::make_unique<FakeDB<StoreEntry>>(&db_store_);
- db_ = db.get();
- guide_store_ = std::make_unique<OptimizationGuideStore>(
- std::move(db), task_environment_.GetMainThreadTaskRunner(),
- pref_service_.get());
- }
- void InitializeDatabase(bool success, bool purge_existing_data = false) {
- EXPECT_CALL(*this, OnInitialized());
- guide_store()->Initialize(
- purge_existing_data,
- base::BindOnce(&OptimizationGuideStoreTest::OnInitialized,
- base::Unretained(this)));
- // OnDatabaseInitialized callback
- db()->InitStatusCallback(success ? leveldb_proto::Enums::kOK
- : leveldb_proto::Enums::kError);
- }
- void InitializeStore(MetadataSchemaState state,
- bool purge_existing_data = false) {
- InitializeDatabase(true /*=success*/, purge_existing_data);
- if (purge_existing_data) {
- // OnPurgeDatabase callback
- db()->UpdateCallback(true);
- return;
- }
- // OnLoadMetadata callback
- db()->LoadCallback(true);
- if (state == MetadataSchemaState::kValid) {
- // OnLoadEntryKeys callback
- db()->LoadCallback(true);
- } else {
- // OnPurgeDatabase callback
- db()->UpdateCallback(true);
- }
- }
- void UpdateComponentHints(std::unique_ptr<StoreUpdateData> component_data,
- bool update_success = true,
- bool load_hint_entry_keys_success = true) {
- EXPECT_CALL(*this, OnUpdateStore());
- guide_store()->UpdateComponentHints(
- std::move(component_data),
- base::BindOnce(&OptimizationGuideStoreTest::OnUpdateStore,
- base::Unretained(this)));
- // OnUpdateStore callback
- db()->UpdateCallback(update_success);
- if (update_success) {
- // OnLoadEntryKeys callback
- db()->LoadCallback(load_hint_entry_keys_success);
- }
- }
- void UpdateFetchedHints(std::unique_ptr<StoreUpdateData> fetched_data,
- bool update_success = true,
- bool load_hint_entry_keys_success = true) {
- EXPECT_CALL(*this, OnUpdateStore());
- guide_store()->UpdateFetchedHints(
- std::move(fetched_data),
- base::BindOnce(&OptimizationGuideStoreTest::OnUpdateStore,
- base::Unretained(this)));
- // OnUpdateStore callback
- db()->UpdateCallback(update_success);
- if (update_success) {
- // OnLoadEntryKeys callback
- db()->LoadCallback(load_hint_entry_keys_success);
- }
- }
- void UpdatePredictionModels(
- std::unique_ptr<StoreUpdateData> prediction_models_data,
- bool update_success = true,
- bool load_prediction_models_entry_keys_success = true) {
- EXPECT_CALL(*this, OnUpdateStore());
- guide_store()->UpdatePredictionModels(
- std::move(prediction_models_data),
- base::BindOnce(&OptimizationGuideStoreTest::OnUpdateStore,
- base::Unretained(this)));
- // OnLoadModelsToBeUpdated callback
- db()->LoadCallback(true);
- // OnUpdateStore callback
- db()->UpdateCallback(update_success);
- if (update_success) {
- // OnLoadEntryKeys callback
- db()->LoadCallback(load_prediction_models_entry_keys_success);
- }
- }
- void ClearFetchedHintsFromDatabase() {
- guide_store()->ClearFetchedHintsFromDatabase();
- db()->UpdateCallback(true);
- db()->LoadCallback(true);
- }
- void PurgeExpiredFetchedHints() {
- guide_store()->PurgeExpiredFetchedHints();
- // OnLoadExpiredEntriesToPurge
- db()->LoadCallback(true);
- // OnUpdateStore
- db()->UpdateCallback(true);
- // OnLoadEntryKeys callback
- db()->LoadCallback(true);
- }
- void PurgeInactiveModels() {
- guide_store()->PurgeInactiveModels();
- // OnLoadModelsToBeUpdated
- db()->LoadCallback(true);
- // OnUpdateStore
- db()->UpdateCallback(true);
- // OnLoadEntryKeys
- db()->LoadCallback(true);
- }
- bool IsMetadataSchemaEntryKeyPresent() const {
- return IsKeyPresent(OptimizationGuideStore::GetMetadataTypeEntryKey(
- OptimizationGuideStore::MetadataType::kSchema));
- }
- // Verifies that the fetched metadata has the expected next update time.
- void ExpectFetchedMetadata(base::Time update_time) const {
- const auto& metadata_entry =
- db_store_.find(OptimizationGuideStore::GetMetadataTypeEntryKey(
- OptimizationGuideStore::MetadataType::kFetched));
- if (metadata_entry != db_store_.end()) {
- // The next update time should have same time up to the second as the
- // metadata entry is stored in seconds.
- EXPECT_TRUE(base::Time::FromDeltaSinceWindowsEpoch(base::Seconds(
- metadata_entry->second.update_time_secs())) -
- update_time <
- base::Seconds(1));
- } else {
- FAIL() << "No fetched metadata found";
- }
- }
- // Verifies that the component metadata has the expected version and all
- // expected component hints are present.
- void ExpectComponentHintsPresent(const std::string& version,
- int count) const {
- const auto& metadata_entry =
- db_store_.find(OptimizationGuideStore::GetMetadataTypeEntryKey(
- OptimizationGuideStore::MetadataType::kComponent));
- if (metadata_entry != db_store_.end()) {
- EXPECT_EQ(metadata_entry->second.version(), version);
- } else {
- FAIL() << "No component metadata found";
- }
- OptimizationGuideStore::EntryKeyPrefix component_hint_entry_key_prefix =
- OptimizationGuideStore::GetComponentHintEntryKeyPrefix(
- base::Version(version));
- for (int i = 0; i < count; ++i) {
- std::string host = GetHost(i);
- OptimizationGuideStore::EntryKey hint_entry_key =
- component_hint_entry_key_prefix + host;
- const auto& hint_entry = db_store_.find(hint_entry_key);
- if (hint_entry == db_store_.end()) {
- FAIL() << "No entry found for component hint: " << hint_entry_key;
- }
- if (!hint_entry->second.has_hint()) {
- FAIL() << "Component hint entry does not have hint: " << hint_entry_key;
- }
- EXPECT_EQ(hint_entry->second.hint().key(), host);
- }
- }
- // Returns true if the data is present for the given key.
- bool IsKeyPresent(const OptimizationGuideStore::EntryKey& entry_key) const {
- return db_store_.find(entry_key) != db_store_.end();
- }
- size_t GetDBStoreEntryCount() const { return db_store_.size(); }
- size_t GetStoreEntryKeyCount() const {
- return guide_store_->GetEntryKeyCount();
- }
- OptimizationGuideStore* guide_store() { return guide_store_.get(); }
- FakeDB<proto::StoreEntry>* db() { return db_; }
- base::FilePath temp_dir() const { return temp_dir_.GetPath(); }
- const OptimizationGuideStore::EntryKey& last_loaded_entry_key() const {
- return last_loaded_entry_key_;
- }
- MemoryHint* last_loaded_hint() { return last_loaded_hint_.get(); }
- proto::PredictionModel* last_loaded_prediction_model() {
- return last_loaded_prediction_model_.get();
- }
- void OnHintLoaded(const OptimizationGuideStore::EntryKey& hint_entry_key,
- std::unique_ptr<MemoryHint> loaded_hint) {
- last_loaded_entry_key_ = hint_entry_key;
- last_loaded_hint_ = std::move(loaded_hint);
- }
- void OnPredictionModelLoaded(
- std::unique_ptr<proto::PredictionModel> loaded_prediction_model) {
- last_loaded_prediction_model_ = std::move(loaded_prediction_model);
- }
- bool IsStoreFilesToDeletePrefEmpty() {
- DictionaryPrefUpdate pref_update(pref_service_.get(),
- prefs::kStoreFilePathsToDelete);
- return pref_update.Get()->DictEmpty();
- }
- void RunUntilIdle() { task_environment_.RunUntilIdle(); }
- MOCK_METHOD0(OnInitialized, void());
- MOCK_METHOD0(OnUpdateStore, void());
- private:
- base::test::TaskEnvironment task_environment_;
- std::unique_ptr<TestingPrefServiceSimple> pref_service_;
- raw_ptr<FakeDB<proto::StoreEntry>> db_;
- StoreEntryMap db_store_;
- std::unique_ptr<OptimizationGuideStore> guide_store_;
- base::ScopedTempDir temp_dir_;
- OptimizationGuideStore::EntryKey last_loaded_entry_key_;
- std::unique_ptr<MemoryHint> last_loaded_hint_;
- std::unique_ptr<proto::PredictionModel> last_loaded_prediction_model_;
- };
- TEST_F(OptimizationGuideStoreTest, NoInitialization) {
- base::HistogramTester histogram_tester;
- SeedInitialData(MetadataSchemaState::kMissing);
- CreateDatabase();
- histogram_tester.ExpectTotalCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult", 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 0);
- }
- TEST_F(OptimizationGuideStoreTest,
- InitializeFailedOnInitializeWithNoInitialData) {
- base::HistogramTester histogram_tester;
- SeedInitialData(MetadataSchemaState::kMissing);
- CreateDatabase();
- InitializeDatabase(false /*=success*/);
- // In the case where initialization fails, the store should be fully purged.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- histogram_tester.ExpectTotalCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult", 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 1);
- }
- TEST_F(OptimizationGuideStoreTest,
- InitializeFailedOnLoadMetadataWithNoInitialData) {
- base::HistogramTester histogram_tester;
- SeedInitialData(MetadataSchemaState::kMissing);
- CreateDatabase();
- InitializeDatabase(true /*=success*/);
- // OnLoadMetadata callback
- db()->LoadCallback(false);
- // In the case where initialization fails, the store should be fully purged.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 1 /* kLoadMetadataFailed */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 1);
- }
- TEST_F(OptimizationGuideStoreTest,
- InitializeFailedOnUpdateMetadataNoInitialData) {
- base::HistogramTester histogram_tester;
- SeedInitialData(MetadataSchemaState::kMissing);
- CreateDatabase();
- InitializeDatabase(true /*=success*/);
- // OnLoadMetadata callback
- db()->LoadCallback(true);
- // OnPurgeDatabase callback
- db()->UpdateCallback(false);
- // In the case where initialization fails, the store should be fully purged.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 2 /* kSchemaMetadataMissing */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 1);
- }
- TEST_F(OptimizationGuideStoreTest,
- InitializeFailedOnInitializeWithInitialData) {
- base::HistogramTester histogram_tester;
- SeedInitialData(MetadataSchemaState::kValid, 10);
- CreateDatabase();
- InitializeDatabase(false /*=success*/);
- // In the case where initialization fails, the store should be fully purged.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- histogram_tester.ExpectTotalCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult", 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 1);
- }
- TEST_F(OptimizationGuideStoreTest,
- InitializeFailedOnLoadMetadataWithInitialData) {
- base::HistogramTester histogram_tester;
- SeedInitialData(MetadataSchemaState::kValid, 10);
- CreateDatabase();
- InitializeDatabase(true /*=success*/);
- // OnLoadMetadata callback
- db()->LoadCallback(false);
- // In the case where initialization fails, the store should be fully purged.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 1 /* kLoadMetadataFailed */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 1);
- }
- TEST_F(OptimizationGuideStoreTest,
- InitializeFailedOnUpdateMetadataWithInvalidSchemaEntry) {
- base::HistogramTester histogram_tester;
- SeedInitialData(MetadataSchemaState::kInvalid, 10);
- CreateDatabase();
- InitializeDatabase(true /*=success*/);
- // OnLoadMetadata callback
- db()->LoadCallback(true);
- // OnPurgeDatabase callback
- db()->UpdateCallback(false);
- // In the case where initialization fails, the store should be fully purged.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 3 /* kSchemaMetadataWrongVersion */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 1);
- }
- TEST_F(OptimizationGuideStoreTest,
- InitializeFailedOnLoadHintEntryKeysWithInitialData) {
- base::HistogramTester histogram_tester;
- SeedInitialData(MetadataSchemaState::kValid, 10, base::Time().Now());
- CreateDatabase();
- InitializeDatabase(true /*=success*/);
- // OnLoadMetadata callback
- db()->LoadCallback(true);
- // OnLoadEntryKeys callback
- db()->LoadCallback(false);
- // In the case where initialization fails, the store should be fully purged.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 0 /* kSuccess */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 1);
- }
- TEST_F(OptimizationGuideStoreTest, InitializeSucceededWithoutSchemaEntry) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kMissing;
- SeedInitialData(schema_state);
- CreateDatabase();
- InitializeStore(schema_state);
- // The store should contain the schema metadata entry and nothing else.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(1));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent());
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 2 /* kSchemaMetadataMissing */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 0);
- }
- TEST_F(OptimizationGuideStoreTest, InitializeSucceededWithInvalidSchemaEntry) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kInvalid;
- SeedInitialData(schema_state);
- CreateDatabase();
- InitializeStore(schema_state);
- // The store should contain the schema metadata entry and nothing else.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(1));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent());
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 3 /* kSchemaMetadataWrongVersion */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 0);
- }
- TEST_F(OptimizationGuideStoreTest, InitializeSucceededWithValidSchemaEntry) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state);
- CreateDatabase();
- InitializeStore(schema_state);
- // The store should contain the schema metadata entry and nothing else.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(1));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent());
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 4 /* kComponentMetadataMissing*/, 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 5 /* kFetchedMetadataMissing*/, 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 6 /* kComponentAndFetchedMetadataMissing*/, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 0);
- }
- TEST_F(OptimizationGuideStoreTest,
- InitializeSucceededWithInvalidSchemaEntryAndInitialData) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kInvalid;
- SeedInitialData(schema_state, 10);
- CreateDatabase();
- InitializeStore(schema_state);
- // The store should contain the schema metadata entry and nothing else, as
- // the initial component hints are all purged.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(1));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent());
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 3 /* kSchemaMetadataWrongVersion */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 0);
- }
- TEST_F(OptimizationGuideStoreTest, InitializeSucceededWithPurgeExistingData) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 10);
- CreateDatabase();
- InitializeStore(schema_state, true /*=purge_existing_data*/);
- // The store should contain the schema metadata entry and nothing else.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(1));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent());
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 0);
- }
- TEST_F(OptimizationGuideStoreTest,
- InitializeSucceededWithValidSchemaEntryAndInitialData) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t component_hint_count = 10;
- SeedInitialData(schema_state, component_hint_count,
- base::Time().Now() /* fetch_update_time */);
- CreateDatabase();
- InitializeStore(schema_state);
- // The store should contain the schema metadata entry, the component metadata
- // entry, and all of the initial component hints.
- EXPECT_EQ(GetDBStoreEntryCount(),
- static_cast<size_t>(component_hint_count + 3));
- EXPECT_EQ(GetStoreEntryKeyCount(), component_hint_count);
- EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent());
- ExpectComponentHintsPresent(kDefaultComponentVersion, component_hint_count);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 0 /* kSuccess */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 0);
- }
- TEST_F(OptimizationGuideStoreTest,
- InitializeSucceededWithValidSchemaEntryAndComponentDataOnly) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t component_hint_count = 10;
- SeedInitialData(schema_state, component_hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- // The store should contain the schema metadata entry, the component metadata
- // entry, and all of the initial component hints.
- EXPECT_EQ(GetDBStoreEntryCount(),
- static_cast<size_t>(component_hint_count + 2));
- EXPECT_EQ(GetStoreEntryKeyCount(), component_hint_count);
- EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent());
- ExpectComponentHintsPresent(kDefaultComponentVersion, component_hint_count);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 4 /* kComponentMetadataMissing*/, 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 5 /* kFetchedMetadataMissing*/, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 6 /* kComponentAndFetchedMetadataMissing*/, 0);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 0);
- }
- TEST_F(OptimizationGuideStoreTest,
- InitializeSucceededWithValidSchemaEntryAndFetchedMetaData) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t component_hint_count = 0;
- SeedInitialData(schema_state, component_hint_count, base::Time().Now());
- CreateDatabase();
- InitializeStore(schema_state);
- // The store should contain the schema metadata entry, the component metadata
- // entry, and all of the initial component hints.
- EXPECT_EQ(GetDBStoreEntryCount(),
- static_cast<size_t>(component_hint_count + 2));
- EXPECT_EQ(GetStoreEntryKeyCount(), component_hint_count);
- EXPECT_TRUE(IsMetadataSchemaEntryKeyPresent());
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.LoadMetadataResult",
- 4 /* kComponentMetadataMissing*/, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 0 /* kUninitialized */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 1 /* kInitializing */,
- 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 2 /* kAvailable */, 1);
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheLevelDBStore.Status", 3 /* kFailed */, 0);
- }
- TEST_F(OptimizationGuideStoreTest,
- CreateComponentUpdateDataFailsForUninitializedStore) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 10);
- CreateDatabase();
- // StoreUpdateData for a component update should only be created if the store
- // is initialized.
- EXPECT_FALSE(guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion)));
- }
- TEST_F(OptimizationGuideStoreTest,
- CreateComponentUpdateDataFailsForEarlierVersion) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 10);
- CreateDatabase();
- InitializeStore(schema_state);
- // No StoreUpdateData for a component update should be created when the
- // component version of the update is older than the store's component
- // version.
- EXPECT_FALSE(guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version("0.0.0")));
- }
- TEST_F(OptimizationGuideStoreTest,
- CreateComponentUpdateDataFailsForCurrentVersion) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 10);
- CreateDatabase();
- InitializeStore(schema_state);
- // No StoreUpdateData should be created when the component version of the
- // update is the same as the store's component version.
- EXPECT_FALSE(guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kDefaultComponentVersion)));
- }
- TEST_F(OptimizationGuideStoreTest,
- CreateComponentUpdateDataSucceedsWithNoPreexistingVersion) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state);
- CreateDatabase();
- InitializeStore(schema_state);
- // StoreUpdateData for a component update should be created when there is no
- // pre-existing component in the store.
- EXPECT_TRUE(guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kDefaultComponentVersion)));
- }
- TEST_F(OptimizationGuideStoreTest,
- CreateComponentUpdateDataSucceedsForNewerVersion) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 10);
- CreateDatabase();
- InitializeStore(schema_state);
- // StoreUpdateData for a component update should be created when the component
- // version of the update is newer than the store's component version.
- EXPECT_TRUE(guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion)));
- }
- TEST_F(OptimizationGuideStoreTest, UpdateComponentHintsUpdateEntriesFails) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 10);
- CreateDatabase();
- InitializeStore(schema_state);
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(update_data);
- SeedComponentUpdateData(update_data.get(), 5);
- UpdateComponentHints(std::move(update_data), false /*update_success*/);
- // The store should be purged if the component data update fails.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- }
- TEST_F(OptimizationGuideStoreTest, UpdateComponentHintsGetKeysFails) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 10);
- CreateDatabase();
- InitializeStore(schema_state);
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(update_data);
- SeedComponentUpdateData(update_data.get(), 5);
- UpdateComponentHints(std::move(update_data), true /*update_success*/,
- false /*load_hints_keys_success*/);
- // The store should be purged if loading the keys after the component update
- // fails.
- EXPECT_EQ(GetDBStoreEntryCount(), static_cast<size_t>(0));
- EXPECT_EQ(GetStoreEntryKeyCount(), static_cast<size_t>(0));
- }
- TEST_F(OptimizationGuideStoreTest, UpdateComponentHints) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t initial_hint_count = 10;
- size_t update_hint_count = 5;
- SeedInitialData(schema_state, initial_hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(update_data);
- SeedComponentUpdateData(update_data.get(), update_hint_count);
- UpdateComponentHints(std::move(update_data));
- // When the component update succeeds, the store should contain the schema
- // metadata entry, the component metadata entry, and all of the update's
- // component hints.
- EXPECT_EQ(GetDBStoreEntryCount(), update_hint_count + 2);
- EXPECT_EQ(GetStoreEntryKeyCount(), update_hint_count);
- ExpectComponentHintsPresent(kUpdateComponentVersion, update_hint_count);
- }
- TEST_F(OptimizationGuideStoreTest,
- UpdateComponentHintsAfterInitializationDataPurge) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t initial_hint_count = 10;
- size_t update_hint_count = 5;
- SeedInitialData(schema_state, initial_hint_count);
- CreateDatabase();
- InitializeStore(schema_state, true /*=purge_existing_data*/);
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(update_data);
- SeedComponentUpdateData(update_data.get(), update_hint_count);
- UpdateComponentHints(std::move(update_data));
- // When the component update succeeds, the store should contain the schema
- // metadata entry, the component metadata entry, and all of the update's
- // component hints.
- EXPECT_EQ(GetDBStoreEntryCount(), update_hint_count + 2);
- EXPECT_EQ(GetStoreEntryKeyCount(), update_hint_count);
- ExpectComponentHintsPresent(kUpdateComponentVersion, update_hint_count);
- }
- TEST_F(OptimizationGuideStoreTest,
- CreateComponentDataWithAlreadyUpdatedVersionFails) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t initial_hint_count = 10;
- size_t update_hint_count = 5;
- SeedInitialData(schema_state, initial_hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(update_data);
- SeedComponentUpdateData(update_data.get(), update_hint_count);
- UpdateComponentHints(std::move(update_data));
- // StoreUpdateData for the component update should not be created for a second
- // component update with the same version as the first component update.
- EXPECT_FALSE(guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion)));
- }
- TEST_F(OptimizationGuideStoreTest,
- UpdateComponentHintsWithUpdatedVersionFails) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t initial_hint_count = 10;
- size_t update_hint_count_1 = 5;
- size_t update_hint_count_2 = 15;
- SeedInitialData(schema_state, initial_hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- // Create two updates for the same component version with different counts.
- std::unique_ptr<StoreUpdateData> update_data_1 =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- std::unique_ptr<StoreUpdateData> update_data_2 =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(update_data_1);
- SeedComponentUpdateData(update_data_1.get(), update_hint_count_1);
- ASSERT_TRUE(update_data_2);
- SeedComponentUpdateData(update_data_2.get(), update_hint_count_2);
- // Update the component data with the same component version twice:
- // first with |update_data_1| and then with |update_data_2|.
- UpdateComponentHints(std::move(update_data_1));
- EXPECT_CALL(*this, OnUpdateStore());
- guide_store()->UpdateComponentHints(
- std::move(update_data_2),
- base::BindOnce(&OptimizationGuideStoreTest::OnUpdateStore,
- base::Unretained(this)));
- // Verify that the store is populated with the component data from
- // |update_data_1| and not |update_data_2|.
- EXPECT_EQ(GetDBStoreEntryCount(), update_hint_count_1 + 2);
- EXPECT_EQ(GetStoreEntryKeyCount(), update_hint_count_1);
- ExpectComponentHintsPresent(kUpdateComponentVersion, update_hint_count_1);
- }
- TEST_F(OptimizationGuideStoreTest, LoadHintOnUnavailableStore) {
- size_t initial_hint_count = 10;
- SeedInitialData(MetadataSchemaState::kValid, initial_hint_count);
- CreateDatabase();
- const OptimizationGuideStore::EntryKey kInvalidEntryKey = "invalid";
- guide_store()->LoadHint(
- kInvalidEntryKey,
- base::BindOnce(&OptimizationGuideStoreTest::OnHintLoaded,
- base::Unretained(this)));
- // Verify that the OnHintLoaded callback runs when the store is unavailable
- // and that both the key and the hint were correctly set in it.
- EXPECT_EQ(last_loaded_entry_key(), kInvalidEntryKey);
- EXPECT_FALSE(last_loaded_hint());
- }
- TEST_F(OptimizationGuideStoreTest, LoadHintFailure) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t hint_count = 10;
- SeedInitialData(schema_state, hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- const OptimizationGuideStore::EntryKey kInvalidEntryKey = "invalid";
- guide_store()->LoadHint(
- kInvalidEntryKey,
- base::BindOnce(&OptimizationGuideStoreTest::OnHintLoaded,
- base::Unretained(this)));
- // OnLoadHint callback
- db()->GetCallback(false);
- // Verify that the OnHintLoaded callback runs when the store is unavailable
- // and that both the key and the hint were correctly set in it.
- EXPECT_EQ(last_loaded_entry_key(), kInvalidEntryKey);
- EXPECT_FALSE(last_loaded_hint());
- }
- TEST_F(OptimizationGuideStoreTest, LoadHintSuccessInitialData) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t hint_count = 10;
- SeedInitialData(schema_state, hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- // Verify that all component hints in the initial data can successfully be
- // loaded from the store.
- for (size_t i = 0; i < hint_count; ++i) {
- std::string host = GetHost(i);
- OptimizationGuideStore::EntryKey hint_entry_key;
- if (!guide_store()->FindHintEntryKey(host, &hint_entry_key)) {
- FAIL() << "Hint entry not found for host: " << host;
- }
- guide_store()->LoadHint(
- hint_entry_key,
- base::BindOnce(&OptimizationGuideStoreTest::OnHintLoaded,
- base::Unretained(this)));
- // OnLoadHint callback
- db()->GetCallback(true);
- EXPECT_EQ(last_loaded_entry_key(), hint_entry_key);
- if (!last_loaded_hint()) {
- FAIL() << "Loaded hint was null for entry key: " << hint_entry_key;
- }
- EXPECT_EQ(last_loaded_hint()->hint()->key(), host);
- EXPECT_FALSE(last_loaded_hint()->expiry_time().has_value());
- }
- }
- TEST_F(OptimizationGuideStoreTest, LoadHintSuccessUpdateData) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t initial_hint_count = 10;
- size_t update_hint_count = 5;
- SeedInitialData(schema_state, initial_hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(update_data);
- SeedComponentUpdateData(update_data.get(), update_hint_count);
- UpdateComponentHints(std::move(update_data));
- // Verify that all component hints within a successful component update can
- // be loaded from the store.
- for (size_t i = 0; i < update_hint_count; ++i) {
- std::string host = GetHost(i);
- OptimizationGuideStore::EntryKey hint_entry_key;
- if (!guide_store()->FindHintEntryKey(host, &hint_entry_key)) {
- FAIL() << "Hint entry not found for host: " << host;
- }
- guide_store()->LoadHint(
- hint_entry_key,
- base::BindOnce(&OptimizationGuideStoreTest::OnHintLoaded,
- base::Unretained(this)));
- // OnLoadHint callback
- db()->GetCallback(true);
- EXPECT_EQ(last_loaded_entry_key(), hint_entry_key);
- if (!last_loaded_hint()) {
- FAIL() << "Loaded hint was null for entry key: " << hint_entry_key;
- }
- EXPECT_EQ(last_loaded_hint()->hint()->key(), host);
- EXPECT_FALSE(last_loaded_hint()->expiry_time().has_value());
- }
- }
- TEST_F(OptimizationGuideStoreTest, FindHintEntryKeyOnUnavailableStore) {
- size_t initial_hint_count = 10;
- SeedInitialData(MetadataSchemaState::kValid, initial_hint_count);
- CreateDatabase();
- std::string host = GetHost(0);
- OptimizationGuideStore::EntryKey hint_entry_key;
- // Verify that hint entry keys can't be found when the store is unavailable.
- EXPECT_FALSE(guide_store()->FindHintEntryKey(host, &hint_entry_key));
- }
- TEST_F(OptimizationGuideStoreTest, FindHintEntryKeyInitialData) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t hint_count = 10;
- SeedInitialData(schema_state, hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- // Verify that all hints contained within the initial store data are reported
- // as being found and hints that are not containd within the initial data are
- // properly reported as not being found.
- for (size_t i = 0; i < hint_count * 2; ++i) {
- std::string host = GetHost(i);
- OptimizationGuideStore::EntryKey hint_entry_key;
- bool success = guide_store()->FindHintEntryKey(host, &hint_entry_key);
- EXPECT_EQ(success, i < hint_count);
- }
- }
- TEST_F(OptimizationGuideStoreTest, FindHintEntryKeyUpdateData) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t initial_hint_count = 10;
- size_t update_hint_count = 5;
- SeedInitialData(schema_state, initial_hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(update_data);
- SeedComponentUpdateData(update_data.get(), update_hint_count);
- UpdateComponentHints(std::move(update_data));
- // Verify that all hints contained within the component update are reported
- // by the store as being found and hints that are not containd within the
- // component update are properly reported as not being found.
- for (size_t i = 0; i < update_hint_count * 2; ++i) {
- std::string host = GetHost(i);
- OptimizationGuideStore::EntryKey hint_entry_key;
- bool success = guide_store()->FindHintEntryKey(host, &hint_entry_key);
- EXPECT_EQ(success, i < update_hint_count);
- }
- }
- TEST_F(OptimizationGuideStoreTest, FetchedHintsMetadataStored) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- base::Time update_time = base::Time().Now();
- SeedInitialData(schema_state, 10, update_time);
- CreateDatabase();
- InitializeStore(schema_state);
- ExpectFetchedMetadata(update_time);
- }
- TEST_F(OptimizationGuideStoreTest, FindHintEntryKeyForFetchedHints) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t update_hint_count = 5;
- base::Time update_time = base::Time().Now();
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForFetchedHints(update_time);
- ASSERT_TRUE(update_data);
- SeedFetchedUpdateData(update_data.get(), update_hint_count);
- UpdateFetchedHints(std::move(update_data));
- for (size_t i = 0; i < update_hint_count; ++i) {
- std::string host = GetHost(i);
- OptimizationGuideStore::EntryKey hint_entry_key;
- bool success = guide_store()->FindHintEntryKey(host, &hint_entry_key);
- EXPECT_EQ(success, i < update_hint_count);
- }
- }
- TEST_F(OptimizationGuideStoreTest,
- FindHintEntryKeyCheckFetchedBeforeComponentHints) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t initial_hint_count = 10;
- base::Time update_time = base::Time().Now();
- SeedInitialData(schema_state, initial_hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Version version("2.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(update_data);
- proto::Hint hint1;
- hint1.set_key("domain1.org");
- hint1.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint1));
- proto::Hint hint2;
- hint2.set_key("host.domain2.org");
- hint2.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint2));
- UpdateComponentHints(std::move(update_data));
- // Add fetched hints to the store that overlap with the same hosts as the
- // initial set.
- update_data = guide_store()->CreateUpdateDataForFetchedHints(update_time);
- proto::Hint hint;
- hint.set_key("host.domain2.org");
- hint.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint));
- UpdateFetchedHints(std::move(update_data));
- // Hint for host.domain2.org should be a fetched hint ("3_" prefix)
- // as fetched hints take priority.
- std::string host = "host.domain2.org";
- OptimizationGuideStore::EntryKey hint_entry_key;
- if (!guide_store()->FindHintEntryKey(host, &hint_entry_key)) {
- FAIL() << "Hint entry not found for host: " << host;
- }
- EXPECT_EQ(hint_entry_key, "3_host.domain2.org");
- host = "domain1.org";
- if (!guide_store()->FindHintEntryKey(host, &hint_entry_key)) {
- FAIL() << "Hint entry not found for host: " << host;
- }
- EXPECT_EQ(hint_entry_key, "2_2.0.0_domain1.org");
- }
- TEST_F(OptimizationGuideStoreTest, SuccessfulRemovedFetchedHintsByKey) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 10);
- CreateDatabase();
- InitializeStore(schema_state);
- std::unique_ptr<StoreUpdateData> component_update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(component_update_data);
- proto::Hint hint1;
- hint1.set_key("domain1.org");
- hint1.set_key_representation(proto::HOST);
- component_update_data->MoveHintIntoUpdateData(std::move(hint1));
- proto::Hint hint2;
- hint2.set_key("domain2.org");
- hint2.set_key_representation(proto::HOST);
- component_update_data->MoveHintIntoUpdateData(std::move(hint2));
- UpdateComponentHints(std::move(component_update_data));
- std::unique_ptr<StoreUpdateData> fetched_update_data =
- guide_store()->CreateUpdateDataForFetchedHints(base::Time().Now());
- proto::Hint fetched_hint1;
- fetched_hint1.set_key("domain2.org");
- fetched_hint1.set_key_representation(proto::HOST);
- fetched_update_data->MoveHintIntoUpdateData(std::move(fetched_hint1));
- proto::Hint fetched_hint2;
- fetched_hint2.set_key("domain3.org");
- fetched_hint2.set_key_representation(proto::HOST);
- fetched_update_data->MoveHintIntoUpdateData(std::move(fetched_hint2));
- UpdateFetchedHints(std::move(fetched_update_data));
- base::RunLoop run_loop;
- guide_store()->RemoveFetchedHintsByKey(run_loop.QuitClosure(),
- {
- "domain1.org",
- "domain2.org",
- "domain3.org",
- "domain4.org",
- });
- db()->UpdateCallback(/*success=*/true);
- run_loop.Run();
- OptimizationGuideStore::EntryKey hint_entry_key;
- // Check for keys that should exist.
- EXPECT_TRUE(guide_store()->FindHintEntryKey("domain1.org", &hint_entry_key));
- EXPECT_EQ("2_2.0.0_domain1.org", hint_entry_key);
- EXPECT_TRUE(guide_store()->FindHintEntryKey("domain2.org", &hint_entry_key));
- EXPECT_EQ("2_2.0.0_domain2.org", hint_entry_key);
- // Check for keys that should not exist.
- EXPECT_FALSE(guide_store()->FindHintEntryKey("domain3.org", &hint_entry_key));
- }
- TEST_F(OptimizationGuideStoreTest, FailedRemovedFetchedHintsByKey) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 10);
- CreateDatabase();
- InitializeStore(schema_state);
- std::unique_ptr<StoreUpdateData> component_update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(component_update_data);
- proto::Hint hint1;
- hint1.set_key("domain1.org");
- hint1.set_key_representation(proto::HOST);
- component_update_data->MoveHintIntoUpdateData(std::move(hint1));
- proto::Hint hint2;
- hint2.set_key("domain2.org");
- hint2.set_key_representation(proto::HOST);
- component_update_data->MoveHintIntoUpdateData(std::move(hint2));
- UpdateComponentHints(std::move(component_update_data));
- std::unique_ptr<StoreUpdateData> fetched_update_data =
- guide_store()->CreateUpdateDataForFetchedHints(base::Time().Now());
- ASSERT_TRUE(fetched_update_data);
- proto::Hint fetched_hint1;
- fetched_hint1.set_key("domain2.org");
- fetched_hint1.set_key_representation(proto::HOST);
- fetched_update_data->MoveHintIntoUpdateData(std::move(fetched_hint1));
- proto::Hint fetched_hint2;
- fetched_hint2.set_key("domain3.org");
- fetched_hint2.set_key_representation(proto::HOST);
- fetched_update_data->MoveHintIntoUpdateData(std::move(fetched_hint2));
- UpdateFetchedHints(std::move(fetched_update_data));
- bool did_callback_run = false;
- base::OnceClosure callback = base::BindOnce(
- [](bool* set_when_run) { *set_when_run = true; }, &did_callback_run);
- guide_store()->RemoveFetchedHintsByKey(std::move(callback), {
- "domain1.org",
- "domain2.org",
- "domain3.org",
- "domain4.org",
- });
- RunUntilIdle();
- db()->UpdateCallback(/*success=*/false);
- RunUntilIdle();
- EXPECT_FALSE(did_callback_run);
- // The callback did not succeed, so the store should no longer be available.
- EXPECT_EQ(0U, GetStoreEntryKeyCount());
- EXPECT_FALSE(guide_store()->IsAvailable());
- }
- TEST_F(OptimizationGuideStoreTest, ClearFetchedHints) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t initial_hint_count = 10;
- base::Time update_time = base::Time().Now();
- SeedInitialData(schema_state, initial_hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Version version("2.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(update_data);
- proto::Hint hint1;
- hint1.set_key("domain1.org");
- hint1.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint1));
- proto::Hint hint2;
- hint2.set_key("host.domain2.org");
- hint2.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint2));
- UpdateComponentHints(std::move(update_data));
- // Add fetched hints to the store that overlap with the same hosts as the
- // initial set.
- update_data = guide_store()->CreateUpdateDataForFetchedHints(update_time);
- proto::Hint fetched_hint1;
- fetched_hint1.set_key("host.domain2.org");
- fetched_hint1.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(fetched_hint1));
- proto::Hint fetched_hint2;
- fetched_hint2.set_key("domain3.org");
- fetched_hint2.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(fetched_hint2));
- UpdateFetchedHints(std::move(update_data));
- // Hint for host.domain2.org should be a fetched hint ("3_" prefix)
- // as fetched hints take priority.
- std::string host = "host.domain2.org";
- OptimizationGuideStore::EntryKey hint_entry_key;
- if (!guide_store()->FindHintEntryKey(host, &hint_entry_key)) {
- FAIL() << "Hint entry not found for host: " << host;
- }
- EXPECT_EQ(hint_entry_key, "3_host.domain2.org");
- host = "domain1.org";
- if (!guide_store()->FindHintEntryKey(host, &hint_entry_key)) {
- FAIL() << "Hint entry not found for host: " << host;
- }
- EXPECT_EQ(hint_entry_key, "2_2.0.0_domain1.org");
- // Remove the fetched hints from the OptimizationGuideStore.
- ClearFetchedHintsFromDatabase();
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.ClearFetchedHints.StoreAvailable", true, 1);
- host = "domain1.org";
- // Component hint should still exist.
- EXPECT_TRUE(guide_store()->FindHintEntryKey(host, &hint_entry_key));
- host = "domain3.org";
- // Fetched hint should not still exist.
- EXPECT_FALSE(guide_store()->FindHintEntryKey(host, &hint_entry_key));
- // Add Components back - newer version.
- base::Version version3("3.0.0");
- std::unique_ptr<StoreUpdateData> update_data2 =
- guide_store()->MaybeCreateUpdateDataForComponentHints(version3);
- ASSERT_TRUE(update_data2);
- proto::Hint new_hint2;
- new_hint2.set_key("host.domain2.org");
- new_hint2.set_key_representation(proto::HOST);
- update_data2->MoveHintIntoUpdateData(std::move(new_hint2));
- UpdateComponentHints(std::move(update_data2));
- host = "host.domain2.org";
- EXPECT_TRUE(guide_store()->FindHintEntryKey(host, &hint_entry_key));
- update_data = guide_store()->CreateUpdateDataForFetchedHints(update_time);
- proto::Hint new_hint;
- new_hint.set_key("domain1.org");
- new_hint.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(new_hint));
- UpdateFetchedHints(std::move(update_data));
- // Add fetched hints to the store that overlap with the same hosts as the
- // initial set.
- host = "domain1.org";
- if (!guide_store()->FindHintEntryKey(host, &hint_entry_key)) {
- FAIL() << "Hint entry not found for host: " << host;
- }
- EXPECT_EQ(hint_entry_key, "3_domain1.org");
- }
- TEST_F(OptimizationGuideStoreTest, FetchHintsPurgeExpiredFetchedHints) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t initial_hint_count = 10;
- base::Time update_time = base::Time().Now();
- SeedInitialData(schema_state, initial_hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Version version("2.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(update_data);
- proto::Hint hint1;
- hint1.set_key("domain1.org");
- hint1.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint1));
- proto::Hint hint2;
- hint2.set_key("host.domain2.org");
- hint2.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint2));
- UpdateComponentHints(std::move(update_data));
- // Add fetched hints to the store that overlap with the same hosts as the
- // initial set.
- update_data = guide_store()->CreateUpdateDataForFetchedHints(update_time);
- proto::Hint fetched_hint1;
- fetched_hint1.set_key("domain2.org");
- fetched_hint1.set_key_representation(proto::HOST);
- fetched_hint1.mutable_max_cache_duration()->set_seconds(
- base::Days(7).InSeconds());
- update_data->MoveHintIntoUpdateData(std::move(fetched_hint1));
- proto::Hint fetched_hint2;
- fetched_hint2.set_key("domain3.org");
- fetched_hint2.set_key_representation(proto::HOST);
- fetched_hint2.mutable_max_cache_duration()->set_seconds(
- base::Days(7).InSeconds());
- update_data->MoveHintIntoUpdateData(std::move(fetched_hint2));
- UpdateFetchedHints(std::move(update_data));
- // Add expired fetched hints to the store.
- update_data = guide_store()->CreateUpdateDataForFetchedHints(update_time);
- proto::Hint fetched_hint3;
- fetched_hint1.set_key("domain4.org");
- fetched_hint1.set_key_representation(proto::HOST);
- fetched_hint1.mutable_max_cache_duration()->set_seconds(
- base::Days(-7).InSeconds());
- update_data->MoveHintIntoUpdateData(std::move(fetched_hint1));
- proto::Hint fetched_hint4;
- fetched_hint2.set_key("domain5.org");
- fetched_hint2.set_key_representation(proto::HOST);
- fetched_hint2.mutable_max_cache_duration()->set_seconds(
- base::Days(-7).InSeconds());
- update_data->MoveHintIntoUpdateData(std::move(fetched_hint2));
- UpdateFetchedHints(std::move(update_data));
- PurgeExpiredFetchedHints();
- OptimizationGuideStore::EntryKey hint_entry_key;
- EXPECT_FALSE(guide_store()->FindHintEntryKey("domain4.org", &hint_entry_key));
- EXPECT_FALSE(guide_store()->FindHintEntryKey("domain5.org", &hint_entry_key));
- EXPECT_TRUE(guide_store()->FindHintEntryKey("domain2.org", &hint_entry_key));
- EXPECT_TRUE(guide_store()->FindHintEntryKey("domain3.org", &hint_entry_key));
- }
- TEST_F(OptimizationGuideStoreTest, FetchedHintsLoadExpiredHint) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t initial_hint_count = 10;
- base::Time update_time = base::Time().Now();
- SeedInitialData(schema_state, initial_hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Version version("2.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(update_data);
- proto::Hint hint1;
- hint1.set_key("domain1.org");
- hint1.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint1));
- proto::Hint hint2;
- hint2.set_key("host.domain2.org");
- hint2.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint2));
- UpdateComponentHints(std::move(update_data));
- // Add fetched hints to the store that expired.
- update_data = guide_store()->CreateUpdateDataForFetchedHints(update_time);
- proto::Hint fetched_hint1;
- fetched_hint1.set_key("host.domain2.org");
- fetched_hint1.set_key_representation(proto::HOST);
- fetched_hint1.mutable_max_cache_duration()->set_seconds(
- base::Days(-10).InSeconds());
- update_data->MoveHintIntoUpdateData(std::move(fetched_hint1));
- proto::Hint fetched_hint2;
- fetched_hint2.set_key("domain3.org");
- fetched_hint2.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(fetched_hint2));
- UpdateFetchedHints(std::move(update_data));
- // Hint for host.domain2.org should be a fetched hint ("3_" prefix)
- // as fetched hints take priority.
- std::string host = "host.domain2.org";
- OptimizationGuideStore::EntryKey hint_entry_key;
- if (!guide_store()->FindHintEntryKey(host, &hint_entry_key)) {
- FAIL() << "Hint entry not found for host: " << host;
- }
- EXPECT_EQ(hint_entry_key, "3_host.domain2.org");
- guide_store()->LoadHint(
- hint_entry_key, base::BindOnce(&OptimizationGuideStoreTest::OnHintLoaded,
- base::Unretained(this)));
- // OnLoadHint callback
- db()->GetCallback(true);
- // |hint_entry_key| will be a fetched hint but the entry will be empty.
- EXPECT_EQ(last_loaded_entry_key(), hint_entry_key);
- EXPECT_FALSE(last_loaded_hint());
- histogram_tester.ExpectBucketCount(
- "OptimizationGuide.HintCacheStore.OnLoadHint.FetchedHintExpired", true,
- 1);
- }
- TEST_F(OptimizationGuideStoreTest, FetchedHintsLoadPopulatesExpiryTime) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- size_t initial_hint_count = 10;
- base::Time update_time = base::Time().Now();
- SeedInitialData(schema_state, initial_hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Version version("2.0.0");
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->MaybeCreateUpdateDataForComponentHints(
- base::Version(kUpdateComponentVersion));
- ASSERT_TRUE(update_data);
- proto::Hint hint1;
- hint1.set_key("domain1.org");
- hint1.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint1));
- proto::Hint hint2;
- hint2.set_key("host.domain2.org");
- hint2.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(hint2));
- UpdateComponentHints(std::move(update_data));
- // Add fetched hints to the store that expired.
- update_data = guide_store()->CreateUpdateDataForFetchedHints(update_time);
- proto::Hint fetched_hint1;
- fetched_hint1.set_key("host.domain2.org");
- fetched_hint1.set_key_representation(proto::HOST);
- fetched_hint1.mutable_max_cache_duration()->set_seconds(
- base::Days(10).InSeconds());
- update_data->MoveHintIntoUpdateData(std::move(fetched_hint1));
- proto::Hint fetched_hint2;
- fetched_hint2.set_key("domain3.org");
- fetched_hint2.set_key_representation(proto::HOST);
- update_data->MoveHintIntoUpdateData(std::move(fetched_hint2));
- UpdateFetchedHints(std::move(update_data));
- // Hint for host.domain2.org should be a fetched hint ("3_" prefix)
- // as fetched hints take priority.
- std::string host = "host.domain2.org";
- OptimizationGuideStore::EntryKey hint_entry_key;
- if (!guide_store()->FindHintEntryKey(host, &hint_entry_key)) {
- FAIL() << "Hint entry not found for host: " << host;
- }
- EXPECT_EQ(hint_entry_key, "3_host.domain2.org");
- guide_store()->LoadHint(
- hint_entry_key, base::BindOnce(&OptimizationGuideStoreTest::OnHintLoaded,
- base::Unretained(this)));
- // OnLoadHint callback
- db()->GetCallback(true);
- // |hint_entry_key| will be a fetched hint but the entry will be empty.
- EXPECT_EQ(last_loaded_entry_key(), hint_entry_key);
- EXPECT_TRUE(last_loaded_hint());
- EXPECT_TRUE(last_loaded_hint()->expiry_time().has_value());
- }
- TEST_F(OptimizationGuideStoreTest, FindPredictionModelEntryKey) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_UNKNOWN);
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
- UpdatePredictionModels(std::move(update_data));
- OptimizationGuideStore::EntryKey entry_key;
- bool success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- EXPECT_TRUE(success);
- EXPECT_EQ(entry_key, "4_1");
- }
- TEST_F(OptimizationGuideStoreTest,
- FindEntryKeyMissingForMissingPredictionModel) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_UNKNOWN);
- UpdatePredictionModels(std::move(update_data));
- OptimizationGuideStore::EntryKey entry_key;
- bool success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- EXPECT_FALSE(success);
- EXPECT_EQ(entry_key, "4_1");
- }
- TEST_F(OptimizationGuideStoreTest, FindAndRemovePredictionModelEntryKey) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_UNKNOWN);
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
- UpdatePredictionModels(std::move(update_data));
- const OptimizationGuideStore::EntryKey kInvalidEntryKey = "4_2";
- EXPECT_FALSE(
- guide_store()->RemovePredictionModelFromEntryKey(kInvalidEntryKey));
- OptimizationGuideStore::EntryKey entry_key;
- bool success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- ASSERT_TRUE(success);
- EXPECT_TRUE(guide_store()->RemovePredictionModelFromEntryKey(entry_key));
- // OnLoadModelsToBeUpdated
- db()->LoadCallback(true);
- // OnUpdateStore
- db()->UpdateCallback(true);
- // OnLoadEntryKeys
- db()->LoadCallback(true);
- EXPECT_FALSE(guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key));
- }
- TEST_F(OptimizationGuideStoreTest, LoadPredictionModel) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
- UpdatePredictionModels(std::move(update_data));
- OptimizationGuideStore::EntryKey entry_key;
- bool success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- EXPECT_TRUE(success);
- guide_store()->LoadPredictionModel(
- entry_key,
- base::BindOnce(&OptimizationGuideStoreTest::OnPredictionModelLoaded,
- base::Unretained(this)));
- // OnPredictionModelLoaded callback
- db()->GetCallback(true);
- EXPECT_TRUE(last_loaded_prediction_model());
- }
- TEST_F(OptimizationGuideStoreTest, LoadPredictionModelOnUnavailableStore) {
- base::HistogramTester histogram_tester;
- size_t initial_hint_count = 10;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, initial_hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- const OptimizationGuideStore::EntryKey kInvalidEntryKey = "4_2";
- guide_store()->LoadPredictionModel(
- kInvalidEntryKey,
- base::BindOnce(&OptimizationGuideStoreTest::OnPredictionModelLoaded,
- base::Unretained(this)));
- // OnPredictionModelLoaded callback
- db()->GetCallback(true);
- // Verify that the OnPredictionModelLoaded callback runs when the store is
- // unavailable and that the prediction model was correctly set.
- EXPECT_FALSE(last_loaded_prediction_model());
- }
- TEST_F(OptimizationGuideStoreTest, LoadPredictionModelOnExpiredModel) {
- base::HistogramTester histogram_tester;
- size_t initial_hint_count = 10;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, initial_hint_count);
- CreateDatabase();
- InitializeStore(schema_state);
- // Add an update with models that are "inactive".
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time -
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- SeedPredictionModelUpdateData(
- update_data.get(), proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- /*model_file_path=*/absl::nullopt,
- /*info=*/{},
- update_time - optimization_guide::features::StoredModelsValidDuration());
- UpdatePredictionModels(std::move(update_data));
- // Since models haven't been purged yet it will initially show up as valid.
- OptimizationGuideStore::EntryKey entry_key;
- EXPECT_TRUE(guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key));
- guide_store()->LoadPredictionModel(
- entry_key,
- base::BindOnce(&OptimizationGuideStoreTest::OnPredictionModelLoaded,
- base::Unretained(this)));
- // OnPredictionModelLoaded callback
- db()->GetCallback(true);
- // After load completes, the key will still exist until after purge.
- EXPECT_TRUE(guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key));
- // Verify that the OnPredictionModelLoaded callback runs when the store is
- // unavailable and that the prediction model was correctly not available.
- EXPECT_FALSE(last_loaded_prediction_model());
- }
- TEST_F(OptimizationGuideStoreTest, LoadPredictionModelWithUpdateInFlight) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
- UpdatePredictionModels(std::move(update_data));
- const OptimizationGuideStore::EntryKey kEntryKey = "4_1";
- guide_store()->LoadPredictionModel(
- kEntryKey,
- base::BindOnce(&OptimizationGuideStoreTest::OnPredictionModelLoaded,
- base::Unretained(this)));
- db()->GetCallback(true);
- // Verify that the OnPredictionModelLoaded callback eventually runs with the
- // prediction model being correctly set.
- EXPECT_TRUE(last_loaded_prediction_model());
- }
- TEST_F(OptimizationGuideStoreTest,
- LoadPredictionModelWithDownloadUrlDoesntExist) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- temp_dir().AppendASCII("doesntexist"));
- UpdatePredictionModels(std::move(update_data));
- OptimizationGuideStore::EntryKey entry_key;
- bool success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- EXPECT_TRUE(success);
- guide_store()->LoadPredictionModel(
- entry_key,
- base::BindOnce(&OptimizationGuideStoreTest::OnPredictionModelLoaded,
- base::Unretained(this)));
- // OnPredictionModelLoaded callback
- db()->GetCallback(true);
- // Wait for file to be verified.
- RunUntilIdle();
- // OnLoadModelsToBeUpdated callback
- db()->LoadCallback(true);
- // OnUpdateStore callback
- db()->UpdateCallback(true);
- // OnLoadEntryKeys callback
- db()->LoadCallback(true);
- EXPECT_FALSE(last_loaded_prediction_model());
- // Make sure key is deleted.
- success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- EXPECT_FALSE(success);
- }
- TEST_F(OptimizationGuideStoreTest,
- LoadPredictionModelWithAdditionalFileDoesntExist) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- base::FilePath model_file_path = temp_dir().AppendASCII("model.tflite");
- ASSERT_EQ(static_cast<int32_t>(3),
- base::WriteFile(model_file_path, "boo", 3));
- base::FilePath additional_file_path = temp_dir().AppendASCII("doesntexist");
- proto::ModelInfo info;
- info.add_additional_files()->set_file_path(
- FilePathToString(additional_file_path));
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- temp_dir().AppendASCII("doesntexist"), info);
- UpdatePredictionModels(std::move(update_data));
- OptimizationGuideStore::EntryKey entry_key;
- bool success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- EXPECT_TRUE(success);
- guide_store()->LoadPredictionModel(
- entry_key,
- base::BindOnce(&OptimizationGuideStoreTest::OnPredictionModelLoaded,
- base::Unretained(this)));
- // OnPredictionModelLoaded callback
- db()->GetCallback(true);
- // Wait for file to be verified.
- RunUntilIdle();
- // OnLoadModelsToBeUpdated callback
- db()->LoadCallback(true);
- // OnUpdateStore callback
- db()->UpdateCallback(true);
- // OnLoadEntryKeys callback
- db()->LoadCallback(true);
- EXPECT_FALSE(last_loaded_prediction_model());
- // Make sure key is deleted.
- success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- EXPECT_FALSE(success);
- histogram_tester.ExpectUniqueSample(
- "OptimizationGuide.ModelFilesVerified.PainfulPageLoad", false, 1);
- }
- TEST_F(OptimizationGuideStoreTest,
- LoadPredictionModelWithAdditionalFileThatExists) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- base::FilePath model_file_path = temp_dir().AppendASCII("model.tflite");
- ASSERT_EQ(static_cast<int32_t>(3),
- base::WriteFile(model_file_path, "boo", 3));
- base::FilePath additional_file_path =
- temp_dir().AppendASCII("additional_file.txt");
- ASSERT_EQ(static_cast<int32_t>(3),
- base::WriteFile(additional_file_path, "ah!", 3));
- proto::ModelInfo info;
- info.add_additional_files()->set_file_path(
- FilePathToString(additional_file_path));
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- model_file_path, info);
- UpdatePredictionModels(std::move(update_data));
- OptimizationGuideStore::EntryKey entry_key;
- bool success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- EXPECT_TRUE(success);
- guide_store()->LoadPredictionModel(
- entry_key,
- base::BindOnce(&OptimizationGuideStoreTest::OnPredictionModelLoaded,
- base::Unretained(this)));
- // OnPredictionModelLoaded callback
- db()->GetCallback(true);
- // Wait for file to be verified.
- RunUntilIdle();
- proto::PredictionModel* loaded_model = last_loaded_prediction_model();
- ASSERT_TRUE(loaded_model);
- EXPECT_EQ(StringToFilePath(loaded_model->model().download_url()).value(),
- model_file_path);
- ASSERT_EQ(loaded_model->model_info().additional_files().size(), 1);
- EXPECT_EQ(StringToFilePath(
- loaded_model->model_info().additional_files(0).file_path()),
- additional_file_path);
- histogram_tester.ExpectUniqueSample(
- "OptimizationGuide.ModelFilesVerified.PainfulPageLoad", true, 1);
- }
- TEST_F(OptimizationGuideStoreTest,
- LoadPredictionModelWithDownloadUrlThatExists) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- base::FilePath file_path = temp_dir().AppendASCII("file");
- ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(file_path, "boo", 3));
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- file_path);
- UpdatePredictionModels(std::move(update_data));
- OptimizationGuideStore::EntryKey entry_key;
- bool success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- EXPECT_TRUE(success);
- guide_store()->LoadPredictionModel(
- entry_key,
- base::BindOnce(&OptimizationGuideStoreTest::OnPredictionModelLoaded,
- base::Unretained(this)));
- // OnPredictionModelLoaded callback
- db()->GetCallback(true);
- // Wait for file to be verified.
- RunUntilIdle();
- proto::PredictionModel* loaded_model = last_loaded_prediction_model();
- EXPECT_TRUE(loaded_model);
- EXPECT_EQ(StringToFilePath(loaded_model->model().download_url()).value(),
- file_path);
- histogram_tester.ExpectUniqueSample(
- "OptimizationGuide.ModelFilesVerified.PainfulPageLoad", true, 1);
- }
- TEST_F(OptimizationGuideStoreTest, UpdatePredictionModelsDeletesOldFile) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- base::FilePath old_dir = temp_dir().AppendASCII("model_v1");
- base::FilePath new_dir = temp_dir().AppendASCII("model_v2");
- ASSERT_TRUE(base::CreateDirectory(old_dir));
- ASSERT_TRUE(base::CreateDirectory(new_dir));
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- base::FilePath old_file_path = old_dir.AppendASCII("model.tflite");
- ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(old_file_path, "boo", 3));
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- old_file_path);
- UpdatePredictionModels(std::move(update_data));
- OptimizationGuideStore::EntryKey entry_key;
- bool success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- EXPECT_TRUE(success);
- std::unique_ptr<StoreUpdateData> update_data2 =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data2);
- base::FilePath new_file_path = new_dir.AppendASCII("model.tflite");
- ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(new_file_path, "boo", 3));
- SeedPredictionModelUpdateData(update_data2.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- new_file_path);
- UpdatePredictionModels(std::move(update_data2));
- RunUntilIdle();
- // Make sure new file exists.
- EXPECT_TRUE(base::PathExists(new_file_path));
- EXPECT_TRUE(base::PathExists(new_dir));
- // Make sure the path to delete gets stored in the pref.
- EXPECT_FALSE(IsStoreFilesToDeletePrefEmpty());
- // Re-create the database so the old file gets deleted.
- CreateDatabase();
- RunUntilIdle();
- // Make sure old file is deleted when store is deleted.
- EXPECT_FALSE(base::PathExists(old_file_path));
- EXPECT_FALSE(base::PathExists(old_dir));
- // Make sure the pref gets cleared out.
- EXPECT_TRUE(IsStoreFilesToDeletePrefEmpty());
- }
- TEST_F(OptimizationGuideStoreTest,
- BackwardCompatibilityForParentDirectoryStorage) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- base::FilePath old_dir = temp_dir().AppendASCII("OptGuideModels");
- base::FilePath new_dir = old_dir.AppendASCII("foo_target_v2");
- ASSERT_TRUE(base::CreateDirectory(old_dir));
- ASSERT_TRUE(base::CreateDirectory(new_dir));
- base::FilePath old_unassociated_model_path =
- old_dir.AppendASCII("other_model.tflite");
- ASSERT_EQ(static_cast<int32_t>(3),
- base::WriteFile(old_unassociated_model_path, "boo", 3));
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- base::FilePath old_file_path = old_dir.AppendASCII("model_v1.tflite");
- ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(old_file_path, "boo", 3));
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- old_file_path);
- UpdatePredictionModels(std::move(update_data));
- OptimizationGuideStore::EntryKey entry_key;
- bool success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- EXPECT_TRUE(success);
- std::unique_ptr<StoreUpdateData> update_data2 =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data2);
- base::FilePath new_file_path = new_dir.Append(GetBaseFileNameForModels());
- ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(new_file_path, "boo", 3));
- SeedPredictionModelUpdateData(update_data2.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- new_file_path);
- UpdatePredictionModels(std::move(update_data2));
- RunUntilIdle();
- EXPECT_FALSE(IsStoreFilesToDeletePrefEmpty());
- // Re-create database so files get deleted.
- CreateDatabase();
- RunUntilIdle();
- // The old file should have been deleted, but not its containing directory
- // because that is recognized as the OptGuideModel parent storage directory.
- EXPECT_FALSE(base::PathExists(old_file_path));
- EXPECT_TRUE(base::PathExists(old_dir));
- // The other unassociated old-code model should not have been touched.
- EXPECT_TRUE(base::PathExists(old_unassociated_model_path));
- EXPECT_TRUE(base::PathExists(new_file_path));
- EXPECT_TRUE(base::PathExists(new_dir));
- EXPECT_TRUE(IsStoreFilesToDeletePrefEmpty());
- }
- TEST_F(OptimizationGuideStoreTest, RemovePredictionModelEntryKeyDeletesFile) {
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- base::FilePath file_path = temp_dir().AppendASCII("file");
- ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(file_path, "boo", 3));
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- file_path);
- UpdatePredictionModels(std::move(update_data));
- OptimizationGuideStore::EntryKey entry_key;
- bool success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- ASSERT_TRUE(success);
- EXPECT_TRUE(guide_store()->RemovePredictionModelFromEntryKey(entry_key));
- // OnLoadModelsToBeUpdated
- db()->LoadCallback(true);
- RunUntilIdle();
- // OnUpdateStore
- db()->UpdateCallback(true);
- // OnLoadEntryKeys
- db()->LoadCallback(true);
- EXPECT_FALSE(guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key));
- // Ensure that file to delete gets persisted so it can be deleted later.
- EXPECT_FALSE(IsStoreFilesToDeletePrefEmpty());
- // Re-create the database so files get deleted.
- CreateDatabase();
- RunUntilIdle();
- // Make sure file is deleted when model is removed and store is getting
- // cleaned up.
- EXPECT_FALSE(base::PathExists(file_path));
- // Make sure pref gets cleaned up when path gets deleted.
- EXPECT_TRUE(IsStoreFilesToDeletePrefEmpty());
- }
- TEST_F(OptimizationGuideStoreTest, PurgeInactiveModels) {
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- // Add an update with models that are "inactive".
- base::Time update_time = base::Time().Now();
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time -
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data);
- base::FilePath old_file_path = temp_dir().AppendASCII("model_v1.tflite");
- ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(old_file_path, "boo", 3));
- proto::ModelInfo model_info;
- model_info.set_version(123);
- SeedPredictionModelUpdateData(
- update_data.get(), proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- old_file_path, model_info,
- update_time - optimization_guide::features::StoredModelsValidDuration());
- UpdatePredictionModels(std::move(update_data));
- // Add an update with models that are "active".
- std::unique_ptr<StoreUpdateData> update_data2 =
- guide_store()->CreateUpdateDataForPredictionModels(
- update_time +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data2);
- SeedPredictionModelUpdateData(update_data2.get(),
- proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION);
- UpdatePredictionModels(std::move(update_data2));
- // Make sure both models are in the store.
- OptimizationGuideStore::EntryKey entry_key;
- bool success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- ASSERT_TRUE(success);
- success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION, &entry_key);
- ASSERT_TRUE(success);
- PurgeInactiveModels();
- RunUntilIdle();
- // The expired model should be removed.
- EXPECT_FALSE(guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key));
- // Should not purge models that are still active.
- EXPECT_TRUE(guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION, &entry_key));
- histogram_tester.ExpectUniqueSample(
- "OptimizationGuide.PredictionModelExpired.PainfulPageLoad", true, 1);
- histogram_tester.ExpectUniqueSample(
- "OptimizationGuide.PredictionModelExpiredVersion.PainfulPageLoad", 123,
- 1);
- histogram_tester.ExpectTotalCount(
- "OptimizationGuide.PredictionModelExpired.LanguageDetection", 0);
- histogram_tester.ExpectTotalCount(
- "OptimizationGuide.PredictionModelExpiredVersion.LanguageDetection", 0);
- // Make sure old file path gets persisted to be deleted later.
- EXPECT_FALSE(IsStoreFilesToDeletePrefEmpty());
- // Reset database to clean up old files.
- CreateDatabase();
- RunUntilIdle();
- EXPECT_FALSE(base::PathExists(old_file_path));
- // Make sure pref gets cleaned up when file path gets deleted.
- EXPECT_TRUE(IsStoreFilesToDeletePrefEmpty());
- }
- struct ValidityTestCase {
- std::string test_name;
- bool keep_beyond_valid_duration;
- bool initially_expired;
- bool expect_kept;
- };
- class OptimizationGuideStoreValidityTest
- : public OptimizationGuideStoreTest,
- public ::testing::WithParamInterface<ValidityTestCase> {};
- TEST_P(OptimizationGuideStoreValidityTest, PurgeInactiveModels) {
- const ValidityTestCase& test_case = GetParam();
- base::HistogramTester histogram_tester;
- MetadataSchemaState schema_state = MetadataSchemaState::kValid;
- SeedInitialData(schema_state, 0);
- CreateDatabase();
- InitializeStore(schema_state);
- // Add an update with one model according to ValidityTestCase settings.
- base::Time update_time = base::Time().Now();
- if (test_case.initially_expired) {
- update_time -= optimization_guide::features::StoredModelsValidDuration();
- } else {
- update_time += optimization_guide::features::StoredModelsValidDuration();
- }
- std::unique_ptr<StoreUpdateData> update_data =
- guide_store()->CreateUpdateDataForPredictionModels(update_time);
- ASSERT_TRUE(update_data);
- proto::ModelInfo info;
- info.set_version(123);
- info.set_keep_beyond_valid_duration(test_case.keep_beyond_valid_duration);
- base::FilePath old_file_path = temp_dir().AppendASCII("model_v1.tflite");
- ASSERT_EQ(static_cast<int32_t>(3), base::WriteFile(old_file_path, "boo", 3));
- SeedPredictionModelUpdateData(update_data.get(),
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD,
- old_file_path, info, update_time);
- UpdatePredictionModels(std::move(update_data));
- // Add an update with models that are "active" and should be unaffected.
- std::unique_ptr<StoreUpdateData> update_data2 =
- guide_store()->CreateUpdateDataForPredictionModels(
- base::Time().Now() +
- optimization_guide::features::StoredModelsValidDuration());
- ASSERT_TRUE(update_data2);
- SeedPredictionModelUpdateData(update_data2.get(),
- proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION);
- UpdatePredictionModels(std::move(update_data2));
- // Make sure both models are in the store.
- OptimizationGuideStore::EntryKey entry_key;
- bool success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key);
- ASSERT_TRUE(success);
- EXPECT_TRUE(base::PathExists(old_file_path));
- success = guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION, &entry_key);
- ASSERT_TRUE(success);
- PurgeInactiveModels();
- RunUntilIdle();
- // Verify that the model file, entry key and histogram match expectations for
- // PageLoad.
- EXPECT_EQ(test_case.expect_kept,
- guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD, &entry_key));
- if (test_case.expect_kept) {
- histogram_tester.ExpectTotalCount(
- "OptimizationGuide.PredictionModelExpired.PainfulPageLoad", 0);
- histogram_tester.ExpectTotalCount(
- "OptimizationGuide.PredictionModelExpiredVersion.PainfulPageLoad", 0);
- } else {
- histogram_tester.ExpectUniqueSample(
- "OptimizationGuide.PredictionModelExpired.PainfulPageLoad", true, 1);
- histogram_tester.ExpectUniqueSample(
- "OptimizationGuide.PredictionModelExpiredVersion.PainfulPageLoad", 123,
- 1);
- }
- // Verify that the other model is not deleted.
- EXPECT_TRUE(guide_store()->FindPredictionModelEntryKey(
- proto::OPTIMIZATION_TARGET_LANGUAGE_DETECTION, &entry_key));
- histogram_tester.ExpectTotalCount(
- "OptimizationGuide.PredictionModelExpired.LanguageDetection", 0);
- histogram_tester.ExpectTotalCount(
- "OptimizationGuide.PredictionModelExpiredVersion.LanguageDetection", 0);
- // Make sure file to delete gets put in pref to delete later, if applicable.
- EXPECT_EQ(test_case.expect_kept, IsStoreFilesToDeletePrefEmpty());
- // Reset database to delete files.
- CreateDatabase();
- RunUntilIdle();
- // Make sure old file is deleted if we expect it to.
- EXPECT_EQ(test_case.expect_kept, base::PathExists(old_file_path));
- // Make sure pref doesn't have any items in it.
- EXPECT_TRUE(IsStoreFilesToDeletePrefEmpty());
- }
- INSTANTIATE_TEST_SUITE_P(
- OptimizationGuideStoreValidityTests,
- OptimizationGuideStoreValidityTest,
- testing::ValuesIn<ValidityTestCase>({
- {
- "KeepDespiteInvalidModel",
- /*keep_beyond_valid_duration=*/true,
- /*initially_expired=*/true,
- /*expect_kept=*/true,
- },
- {
- "KeepAndInitiallyValid",
- /*keep_beyond_valid_duration=*/true,
- /*initially_expired=*/false,
- /*expect_kept=*/true,
- },
- {
- "DeleteAndInitiallyValid",
- /*keep_beyond_valid_duration=*/false,
- /*initially_expired=*/false,
- /*expect_kept=*/true,
- },
- // Only in this case should the model be removed.
- {
- "DeleteAndInvalidModel",
- /*keep_beyond_valid_duration=*/false,
- /*initially_expired=*/true,
- /*expect_kept=*/false,
- },
- }),
- [](const testing::TestParamInfo<
- OptimizationGuideStoreValidityTest::ParamType>& info) {
- return info.param.test_name;
- });
- } // namespace optimization_guide
|