hint_cache_unittest.cc 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/optimization_guide/core/hint_cache.h"
  5. #include <string>
  6. #include "base/bind.h"
  7. #include "base/files/scoped_temp_dir.h"
  8. #include "base/memory/raw_ptr.h"
  9. #include "base/run_loop.h"
  10. #include "base/strings/string_number_conversions.h"
  11. #include "base/test/metrics/histogram_tester.h"
  12. #include "base/test/task_environment.h"
  13. #include "components/optimization_guide/core/optimization_guide_features.h"
  14. #include "components/optimization_guide/core/optimization_guide_store.h"
  15. #include "components/optimization_guide/core/proto_database_provider_test_base.h"
  16. #include "components/optimization_guide/core/store_update_data.h"
  17. #include "components/optimization_guide/proto/hint_cache.pb.h"
  18. #include "components/optimization_guide/proto/hints.pb.h"
  19. #include "testing/gtest/include/gtest/gtest.h"
  20. #include "third_party/abseil-cpp/absl/types/optional.h"
  21. #include "url/gurl.h"
  22. namespace optimization_guide {
  23. namespace {
  24. std::string GetHostDomainOrg(int index) {
  25. return "host.domain" + base::NumberToString(index) + ".org";
  26. }
  27. class HintCacheTest : public ProtoDatabaseProviderTestBase,
  28. public testing::WithParamInterface<bool> {
  29. public:
  30. HintCacheTest() : loaded_hint_(nullptr) {}
  31. HintCacheTest(const HintCacheTest&) = delete;
  32. HintCacheTest& operator=(const HintCacheTest&) = delete;
  33. ~HintCacheTest() override {}
  34. void SetUp() override { ProtoDatabaseProviderTestBase::SetUp(); }
  35. void TearDown() override {
  36. ProtoDatabaseProviderTestBase::TearDown();
  37. DestroyHintCache();
  38. }
  39. protected:
  40. // Creates and initializes the hint cache and optimization guide store and
  41. // waits for the callback indicating that initialization is complete.
  42. void CreateAndInitializeHintCache(int memory_cache_size,
  43. bool purge_existing_data = false) {
  44. auto database_path = temp_dir_.GetPath();
  45. auto database_task_runner = task_environment_.GetMainThreadTaskRunner();
  46. optimization_guide_store_ =
  47. IsBackedByPersistentStore()
  48. ? std::make_unique<OptimizationGuideStore>(
  49. db_provider_.get(), database_path, database_task_runner,
  50. /*pref_service_=*/nullptr)
  51. : nullptr;
  52. hint_cache_ = std::make_unique<HintCache>(
  53. optimization_guide_store_ ? optimization_guide_store_->AsWeakPtr()
  54. : nullptr,
  55. memory_cache_size);
  56. is_store_initialized_ = false;
  57. hint_cache_->Initialize(purge_existing_data,
  58. base::BindOnce(&HintCacheTest::OnStoreInitialized,
  59. base::Unretained(this)));
  60. while (!is_store_initialized_) {
  61. RunUntilIdle();
  62. }
  63. hint_cache_->SetClockForTesting(task_environment_.GetMockClock());
  64. }
  65. void DestroyHintCache() {
  66. hint_cache_.reset();
  67. optimization_guide_store_.reset();
  68. loaded_hint_ = nullptr;
  69. is_store_initialized_ = false;
  70. are_component_hints_updated_ = false;
  71. on_load_hint_callback_called_ = false;
  72. are_fetched_hints_updated_ = false;
  73. RunUntilIdle();
  74. }
  75. HintCache* hint_cache() { return hint_cache_.get(); }
  76. bool are_fetched_hints_updated() { return are_fetched_hints_updated_; }
  77. // Updates the cache with |component_data| and waits for callback indicating
  78. // that the update is complete.
  79. void UpdateComponentHints(std::unique_ptr<StoreUpdateData> component_data) {
  80. are_component_hints_updated_ = false;
  81. hint_cache_->UpdateComponentHints(
  82. std::move(component_data),
  83. base::BindOnce(&HintCacheTest::OnUpdateComponentHints,
  84. base::Unretained(this)));
  85. while (!are_component_hints_updated_) {
  86. RunUntilIdle();
  87. }
  88. }
  89. void UpdateFetchedHintsAndWait(
  90. std::unique_ptr<proto::GetHintsResponse> get_hints_response,
  91. base::Time stored_time,
  92. const base::flat_set<std::string>& hosts_fetched,
  93. const base::flat_set<GURL>& urls_fetched) {
  94. are_fetched_hints_updated_ = false;
  95. hint_cache_->UpdateFetchedHints(
  96. std::move(get_hints_response), stored_time, hosts_fetched, urls_fetched,
  97. base::BindOnce(&HintCacheTest::OnHintsUpdated, base::Unretained(this)));
  98. while (!are_fetched_hints_updated_)
  99. RunUntilIdle();
  100. }
  101. void OnHintsUpdated() { are_fetched_hints_updated_ = true; }
  102. // Loads hint for the specified host from the cache and waits for callback
  103. // indicating that loading the hint is complete.
  104. void LoadHint(const std::string& host) {
  105. on_load_hint_callback_called_ = false;
  106. loaded_hint_ = nullptr;
  107. hint_cache_->LoadHint(host, base::BindOnce(&HintCacheTest::OnLoadHint,
  108. base::Unretained(this)));
  109. while (!on_load_hint_callback_called_) {
  110. RunUntilIdle();
  111. }
  112. }
  113. const proto::Hint* GetLoadedHint() const { return loaded_hint_; }
  114. proto::Hint CreateHintForURL(
  115. const GURL& url,
  116. absl::optional<int> cache_duration_in_secs = absl::optional<int>()) {
  117. proto::Hint hint;
  118. hint.set_key(url.spec());
  119. hint.set_key_representation(proto::FULL_URL);
  120. if (cache_duration_in_secs)
  121. hint.mutable_max_cache_duration()->set_seconds(*cache_duration_in_secs);
  122. proto::PageHint* page_hint = hint.add_page_hints();
  123. page_hint->add_allowlisted_optimizations()->set_optimization_type(
  124. optimization_guide::proto::PERFORMANCE_HINTS);
  125. page_hint->set_page_pattern("whatever/*");
  126. return hint;
  127. }
  128. void MoveClockForwardBy(base::TimeDelta time_delta) {
  129. task_environment_.FastForwardBy(time_delta);
  130. RunUntilIdle();
  131. }
  132. void RunUntilIdle() {
  133. task_environment_.RunUntilIdle();
  134. base::RunLoop().RunUntilIdle();
  135. }
  136. bool IsBackedByPersistentStore() const { return GetParam(); }
  137. private:
  138. void OnStoreInitialized() { is_store_initialized_ = true; }
  139. void OnUpdateComponentHints() { are_component_hints_updated_ = true; }
  140. void OnLoadHint(const proto::Hint* hint) {
  141. on_load_hint_callback_called_ = true;
  142. loaded_hint_ = hint;
  143. }
  144. base::test::TaskEnvironment task_environment_{
  145. base::test::TaskEnvironment::TimeSource::MOCK_TIME};
  146. std::unique_ptr<OptimizationGuideStore> optimization_guide_store_;
  147. std::unique_ptr<HintCache> hint_cache_;
  148. raw_ptr<const proto::Hint> loaded_hint_;
  149. bool is_store_initialized_;
  150. bool are_component_hints_updated_;
  151. bool on_load_hint_callback_called_;
  152. bool are_fetched_hints_updated_;
  153. };
  154. INSTANTIATE_TEST_SUITE_P(WithPersistentStore,
  155. HintCacheTest,
  156. testing::Values(true, false));
  157. TEST_P(HintCacheTest, ComponentUpdate) {
  158. if (!IsBackedByPersistentStore())
  159. return;
  160. const int kMemoryCacheSize = 5;
  161. CreateAndInitializeHintCache(kMemoryCacheSize);
  162. base::Version version("2.0.0");
  163. std::unique_ptr<StoreUpdateData> update_data =
  164. hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
  165. ASSERT_TRUE(update_data);
  166. proto::Hint hint1;
  167. hint1.set_key("subdomain.domain.org");
  168. hint1.set_key_representation(proto::HOST);
  169. proto::Hint hint2;
  170. hint2.set_key("host.domain.org");
  171. hint2.set_key_representation(proto::HOST);
  172. proto::Hint hint3;
  173. hint3.set_key("otherhost.subdomain.domain.org");
  174. hint3.set_key_representation(proto::HOST);
  175. update_data->MoveHintIntoUpdateData(std::move(hint1));
  176. update_data->MoveHintIntoUpdateData(std::move(hint2));
  177. update_data->MoveHintIntoUpdateData(std::move(hint3));
  178. UpdateComponentHints(std::move(update_data));
  179. // Not matched
  180. EXPECT_FALSE(hint_cache()->HasHint("domain.org"));
  181. EXPECT_FALSE(hint_cache()->HasHint("othersubdomain.domain.org"));
  182. // Matched
  183. EXPECT_TRUE(hint_cache()->HasHint("otherhost.subdomain.domain.org"));
  184. EXPECT_TRUE(hint_cache()->HasHint("host.domain.org"));
  185. EXPECT_TRUE(hint_cache()->HasHint("subdomain.domain.org"));
  186. }
  187. TEST_P(HintCacheTest, ComponentUpdateWithSameVersionIgnored) {
  188. if (!IsBackedByPersistentStore())
  189. return;
  190. const int kMemoryCacheSize = 5;
  191. CreateAndInitializeHintCache(kMemoryCacheSize);
  192. base::Version version("2.0.0");
  193. std::unique_ptr<StoreUpdateData> update_data =
  194. hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
  195. ASSERT_TRUE(update_data);
  196. UpdateComponentHints(std::move(update_data));
  197. EXPECT_FALSE(hint_cache()->MaybeCreateUpdateDataForComponentHints(version));
  198. }
  199. TEST_P(HintCacheTest, ComponentUpdateWithEarlierVersionIgnored) {
  200. if (!IsBackedByPersistentStore())
  201. return;
  202. const int kMemoryCacheSize = 5;
  203. CreateAndInitializeHintCache(kMemoryCacheSize);
  204. base::Version version_1("1.0.0");
  205. base::Version version_2("2.0.0");
  206. std::unique_ptr<StoreUpdateData> update_data =
  207. hint_cache()->MaybeCreateUpdateDataForComponentHints(version_2);
  208. ASSERT_TRUE(update_data);
  209. UpdateComponentHints(std::move(update_data));
  210. EXPECT_FALSE(hint_cache()->MaybeCreateUpdateDataForComponentHints(version_1));
  211. }
  212. TEST_P(HintCacheTest, ComponentUpdateWithLaterVersionProcessed) {
  213. if (!IsBackedByPersistentStore())
  214. return;
  215. const int kMemoryCacheSize = 5;
  216. CreateAndInitializeHintCache(kMemoryCacheSize);
  217. base::Version version_1("1.0.0");
  218. base::Version version_2("2.0.0");
  219. std::unique_ptr<StoreUpdateData> update_data_1 =
  220. hint_cache()->MaybeCreateUpdateDataForComponentHints(version_1);
  221. ASSERT_TRUE(update_data_1);
  222. proto::Hint hint1;
  223. hint1.set_key("subdomain.domain.org");
  224. hint1.set_key_representation(proto::HOST);
  225. proto::Hint hint2;
  226. hint2.set_key("host.domain.org");
  227. hint2.set_key_representation(proto::HOST);
  228. proto::Hint hint3;
  229. hint3.set_key("otherhost.subdomain.domain.org");
  230. hint3.set_key_representation(proto::HOST);
  231. update_data_1->MoveHintIntoUpdateData(std::move(hint1));
  232. update_data_1->MoveHintIntoUpdateData(std::move(hint2));
  233. update_data_1->MoveHintIntoUpdateData(std::move(hint3));
  234. UpdateComponentHints(std::move(update_data_1));
  235. // Not matched
  236. EXPECT_FALSE(hint_cache()->HasHint("domain.org"));
  237. EXPECT_FALSE(hint_cache()->HasHint("othersubdomain.domain.org"));
  238. // Matched
  239. EXPECT_TRUE(hint_cache()->HasHint("otherhost.subdomain.domain.org"));
  240. EXPECT_TRUE(hint_cache()->HasHint("host.domain.org"));
  241. EXPECT_TRUE(hint_cache()->HasHint("subdomain.domain.org"));
  242. std::unique_ptr<StoreUpdateData> update_data_2 =
  243. hint_cache()->MaybeCreateUpdateDataForComponentHints(version_2);
  244. ASSERT_TRUE(update_data_2);
  245. proto::Hint hint4;
  246. hint4.set_key("subdomain.domain2.org");
  247. hint4.set_key_representation(proto::HOST);
  248. proto::Hint hint5;
  249. hint5.set_key("host.domain2.org");
  250. hint5.set_key_representation(proto::HOST);
  251. proto::Hint hint6;
  252. hint6.set_key("otherhost.subdomain.domain2.org");
  253. hint6.set_key_representation(proto::HOST);
  254. update_data_2->MoveHintIntoUpdateData(std::move(hint4));
  255. update_data_2->MoveHintIntoUpdateData(std::move(hint5));
  256. update_data_2->MoveHintIntoUpdateData(std::move(hint6));
  257. UpdateComponentHints(std::move(update_data_2));
  258. // Not matched
  259. EXPECT_FALSE(hint_cache()->HasHint("otherhost.subdomain.domain.org"));
  260. EXPECT_FALSE(hint_cache()->HasHint("host.subdomain.domain.org"));
  261. EXPECT_FALSE(hint_cache()->HasHint("subhost.host.subdomain.domain.org"));
  262. EXPECT_FALSE(hint_cache()->HasHint("domain2.org"));
  263. EXPECT_FALSE(hint_cache()->HasHint("othersubdomain.domain2.org"));
  264. // Matched
  265. EXPECT_TRUE(hint_cache()->HasHint("otherhost.subdomain.domain2.org"));
  266. EXPECT_TRUE(hint_cache()->HasHint("subdomain.domain2.org"));
  267. EXPECT_TRUE(hint_cache()->HasHint("host.domain2.org"));
  268. }
  269. TEST_P(HintCacheTest, ComponentHintsAvailableAfterRestart) {
  270. if (!IsBackedByPersistentStore())
  271. return;
  272. for (int i = 0; i < 2; ++i) {
  273. const int kMemoryCacheSize = 5;
  274. CreateAndInitializeHintCache(kMemoryCacheSize,
  275. false /*=purge_existing_data*/);
  276. base::Version version("2.0.0");
  277. std::unique_ptr<StoreUpdateData> update_data =
  278. hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
  279. if (i == 0) {
  280. ASSERT_TRUE(update_data);
  281. proto::Hint hint1;
  282. hint1.set_key("subdomain.domain.org");
  283. hint1.set_key_representation(proto::HOST);
  284. proto::Hint hint2;
  285. hint2.set_key("host.domain.org");
  286. hint2.set_key_representation(proto::HOST);
  287. proto::Hint hint3;
  288. hint3.set_key("otherhost.subdomain.domain.org");
  289. hint3.set_key_representation(proto::HOST);
  290. update_data->MoveHintIntoUpdateData(std::move(hint1));
  291. update_data->MoveHintIntoUpdateData(std::move(hint2));
  292. update_data->MoveHintIntoUpdateData(std::move(hint3));
  293. UpdateComponentHints(std::move(update_data));
  294. } else {
  295. EXPECT_FALSE(update_data);
  296. }
  297. // Not matched
  298. EXPECT_FALSE(hint_cache()->HasHint("domain.org"));
  299. EXPECT_FALSE(hint_cache()->HasHint("othersubdomain.domain.org"));
  300. // Matched
  301. EXPECT_TRUE(hint_cache()->HasHint("otherhost.subdomain.domain.org"));
  302. EXPECT_TRUE(hint_cache()->HasHint("host.domain.org"));
  303. EXPECT_TRUE(hint_cache()->HasHint("subdomain.domain.org"));
  304. DestroyHintCache();
  305. }
  306. }
  307. TEST_P(HintCacheTest, ComponentHintsUpdatableAfterRestartWithPurge) {
  308. if (!IsBackedByPersistentStore())
  309. return;
  310. for (int i = 0; i < 2; ++i) {
  311. const int kMemoryCacheSize = 5;
  312. CreateAndInitializeHintCache(kMemoryCacheSize,
  313. true /*=purge_existing_data*/);
  314. base::Version version("2.0.0");
  315. std::unique_ptr<StoreUpdateData> update_data =
  316. hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
  317. ASSERT_TRUE(update_data);
  318. proto::Hint hint1;
  319. hint1.set_key("subdomain.domain.org");
  320. hint1.set_key_representation(proto::HOST);
  321. proto::Hint hint2;
  322. hint2.set_key("host.domain.org");
  323. hint2.set_key_representation(proto::HOST);
  324. proto::Hint hint3;
  325. hint3.set_key("otherhost.subdomain.domain.org");
  326. hint3.set_key_representation(proto::HOST);
  327. update_data->MoveHintIntoUpdateData(std::move(hint1));
  328. update_data->MoveHintIntoUpdateData(std::move(hint2));
  329. update_data->MoveHintIntoUpdateData(std::move(hint3));
  330. UpdateComponentHints(std::move(update_data));
  331. // Not matched
  332. EXPECT_FALSE(hint_cache()->HasHint("domain.org"));
  333. EXPECT_FALSE(hint_cache()->HasHint("othersubdomain.domain.org"));
  334. // Matched
  335. EXPECT_TRUE(hint_cache()->HasHint("otherhost.subdomain.domain.org"));
  336. EXPECT_TRUE(hint_cache()->HasHint("host.domain.org"));
  337. EXPECT_TRUE(hint_cache()->HasHint("subdomain.domain.org"));
  338. DestroyHintCache();
  339. }
  340. }
  341. TEST_P(HintCacheTest, ComponentHintsNotRetainedAfterRestartWithPurge) {
  342. if (!IsBackedByPersistentStore())
  343. return;
  344. for (int i = 0; i < 2; ++i) {
  345. const int kMemoryCacheSize = 5;
  346. CreateAndInitializeHintCache(kMemoryCacheSize,
  347. true /*=purge_existing_data*/);
  348. base::Version version("2.0.0");
  349. std::unique_ptr<StoreUpdateData> update_data =
  350. hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
  351. if (i == 0) {
  352. ASSERT_TRUE(update_data);
  353. proto::Hint hint1;
  354. hint1.set_key("subdomain.domain.org");
  355. hint1.set_key_representation(proto::HOST);
  356. proto::Hint hint2;
  357. hint2.set_key("host.domain.org");
  358. hint2.set_key_representation(proto::HOST);
  359. proto::Hint hint3;
  360. hint3.set_key("otherhost.subdomain.domain.org");
  361. hint3.set_key_representation(proto::HOST);
  362. update_data->MoveHintIntoUpdateData(std::move(hint1));
  363. update_data->MoveHintIntoUpdateData(std::move(hint2));
  364. update_data->MoveHintIntoUpdateData(std::move(hint3));
  365. UpdateComponentHints(std::move(update_data));
  366. } else {
  367. EXPECT_TRUE(update_data);
  368. }
  369. // Not matched
  370. EXPECT_FALSE(hint_cache()->HasHint("domain.org"));
  371. EXPECT_FALSE(hint_cache()->HasHint("othersubdomain.domain.org"));
  372. // Maybe matched
  373. bool should_match = (i == 0);
  374. EXPECT_EQ(hint_cache()->HasHint("otherhost.subdomain.domain.org"),
  375. should_match);
  376. EXPECT_EQ(hint_cache()->HasHint("subdomain.domain.org"), should_match);
  377. EXPECT_EQ(hint_cache()->HasHint("host.domain.org"), should_match);
  378. DestroyHintCache();
  379. }
  380. }
  381. TEST_P(HintCacheTest, TestMemoryCacheLeastRecentlyUsedPurge) {
  382. if (!IsBackedByPersistentStore())
  383. return;
  384. const int kTestHintCount = 10;
  385. const int kMemoryCacheSize = 5;
  386. CreateAndInitializeHintCache(kMemoryCacheSize);
  387. base::Version version("1.0.0");
  388. std::unique_ptr<StoreUpdateData> update_data =
  389. hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
  390. ASSERT_TRUE(update_data);
  391. for (int i = 0; i < kTestHintCount; ++i) {
  392. proto::Hint hint;
  393. hint.set_key(GetHostDomainOrg(i));
  394. hint.set_key_representation(proto::HOST);
  395. update_data->MoveHintIntoUpdateData(std::move(hint));
  396. }
  397. UpdateComponentHints(std::move(update_data));
  398. for (int i = kTestHintCount - 1; i >= 0; --i) {
  399. std::string host = GetHostDomainOrg(i);
  400. EXPECT_TRUE(hint_cache()->HasHint(host));
  401. LoadHint(host);
  402. ASSERT_TRUE(GetLoadedHint());
  403. EXPECT_EQ(GetLoadedHint()->key(), host);
  404. }
  405. for (int i = 0; i < kTestHintCount; ++i) {
  406. std::string host = GetHostDomainOrg(i);
  407. if (i < kMemoryCacheSize) {
  408. ASSERT_TRUE(hint_cache()->GetHostKeyedHintIfLoaded(host));
  409. EXPECT_EQ(GetHostDomainOrg(i),
  410. hint_cache()->GetHostKeyedHintIfLoaded(host)->key());
  411. } else {
  412. EXPECT_FALSE(hint_cache()->GetHostKeyedHintIfLoaded(host));
  413. }
  414. EXPECT_TRUE(hint_cache()->HasHint(host));
  415. }
  416. }
  417. TEST_P(HintCacheTest, TestHostNotInCache) {
  418. if (!IsBackedByPersistentStore())
  419. return;
  420. const int kTestHintCount = 10;
  421. const int kMemoryCacheSize = 5;
  422. CreateAndInitializeHintCache(kMemoryCacheSize);
  423. base::Version version("1.0.0");
  424. std::unique_ptr<StoreUpdateData> update_data =
  425. hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
  426. ASSERT_TRUE(update_data);
  427. for (int i = 0; i < kTestHintCount; ++i) {
  428. proto::Hint hint;
  429. hint.set_key(GetHostDomainOrg(i));
  430. hint.set_key_representation(proto::HOST);
  431. update_data->MoveHintIntoUpdateData(std::move(hint));
  432. }
  433. UpdateComponentHints(std::move(update_data));
  434. EXPECT_FALSE(hint_cache()->HasHint(GetHostDomainOrg(kTestHintCount)));
  435. }
  436. TEST_P(HintCacheTest, TestMemoryCacheLoadCallback) {
  437. if (!IsBackedByPersistentStore())
  438. return;
  439. const int kMemoryCacheSize = 5;
  440. CreateAndInitializeHintCache(kMemoryCacheSize);
  441. base::Version version("1.0.0");
  442. std::unique_ptr<StoreUpdateData> update_data =
  443. hint_cache()->MaybeCreateUpdateDataForComponentHints(version);
  444. ASSERT_TRUE(update_data);
  445. std::string hint_key = "subdomain.domain.org";
  446. proto::Hint hint;
  447. hint.set_key(hint_key);
  448. hint.set_key_representation(proto::HOST);
  449. update_data->MoveHintIntoUpdateData(std::move(hint));
  450. UpdateComponentHints(std::move(update_data));
  451. EXPECT_FALSE(hint_cache()->GetHostKeyedHintIfLoaded("subdomain.domain.org"));
  452. LoadHint("subdomain.domain.org");
  453. EXPECT_TRUE(hint_cache()->GetHostKeyedHintIfLoaded("subdomain.domain.org"));
  454. EXPECT_TRUE(GetLoadedHint());
  455. EXPECT_EQ(hint_key, GetLoadedHint()->key());
  456. }
  457. TEST_P(HintCacheTest, StoreValidFetchedHints) {
  458. if (!IsBackedByPersistentStore()) {
  459. // Checking the fetched hints update time is not relevant when we don't have
  460. // a backing store.
  461. return;
  462. }
  463. const int kMemoryCacheSize = 5;
  464. CreateAndInitializeHintCache(kMemoryCacheSize);
  465. // Default update time for empty optimization guide store is base::Time().
  466. EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), base::Time());
  467. std::unique_ptr<proto::GetHintsResponse> get_hints_response =
  468. std::make_unique<proto::GetHintsResponse>();
  469. proto::Hint* hint = get_hints_response->add_hints();
  470. hint->set_key_representation(proto::HOST);
  471. hint->set_key("host.domain.org");
  472. proto::PageHint* page_hint = hint->add_page_hints();
  473. page_hint->set_page_pattern("page pattern");
  474. base::Time stored_time = base::Time().Now();
  475. UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
  476. {"host.domain.org"}, {});
  477. EXPECT_TRUE(are_fetched_hints_updated());
  478. // Next update time for hints should be updated.
  479. EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), stored_time);
  480. }
  481. TEST_P(HintCacheTest, ParseEmptyFetchedHints) {
  482. const int kMemoryCacheSize = 5;
  483. CreateAndInitializeHintCache(kMemoryCacheSize);
  484. base::Time stored_time = base::Time().Now() + base::Days(1);
  485. std::unique_ptr<proto::GetHintsResponse> get_hints_response =
  486. std::make_unique<proto::GetHintsResponse>();
  487. UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
  488. {"host.domain.org"}, {});
  489. // Empty Fetched Hints causes the metadata entry to be updated if store is
  490. // available.
  491. EXPECT_TRUE(are_fetched_hints_updated());
  492. if (IsBackedByPersistentStore()) {
  493. EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), stored_time);
  494. } else {
  495. EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), base::Time());
  496. // Fetched hosts should still have an entry despite not getting a hint back
  497. // for it.
  498. EXPECT_TRUE(hint_cache()->HasHint("host.domain.org"));
  499. }
  500. }
  501. TEST_P(HintCacheTest, StoreValidFetchedHintsWithServerProvidedExpiryTime) {
  502. const int kMemoryCacheSize = 5;
  503. const int kFetchedHintExpirationSecs = 60;
  504. CreateAndInitializeHintCache(kMemoryCacheSize);
  505. // Default update time for empty optimization guide store is base::Time().
  506. EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), base::Time());
  507. std::unique_ptr<proto::GetHintsResponse> get_hints_response =
  508. std::make_unique<proto::GetHintsResponse>();
  509. // Set server-provided expiration time.
  510. proto::Hint* hint = get_hints_response->add_hints();
  511. hint->set_key_representation(proto::HOST);
  512. hint->set_key("host.domain.org");
  513. hint->mutable_max_cache_duration()->set_seconds(kFetchedHintExpirationSecs);
  514. proto::PageHint* page_hint = hint->add_page_hints();
  515. page_hint->set_page_pattern("page pattern");
  516. base::Time stored_time = base::Time().Now();
  517. GURL navigation_url("https://foo.com");
  518. UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
  519. {"host.domain.org"}, {navigation_url});
  520. EXPECT_TRUE(are_fetched_hints_updated());
  521. if (IsBackedByPersistentStore()) {
  522. // Next update time for hints should be updated.
  523. EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), stored_time);
  524. } else {
  525. EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), base::Time());
  526. }
  527. // Should be loaded right when response is received.
  528. EXPECT_TRUE(hint_cache()->GetHostKeyedHintIfLoaded("host.domain.org"));
  529. // Set time so hint should be expired.
  530. MoveClockForwardBy(base::Seconds(kFetchedHintExpirationSecs + 1));
  531. EXPECT_FALSE(hint_cache()->GetHostKeyedHintIfLoaded("host.domain.org"));
  532. }
  533. TEST_P(HintCacheTest, StoreValidFetchedHintsWithDefaultExpiryTime) {
  534. const int kMemoryCacheSize = 5;
  535. CreateAndInitializeHintCache(kMemoryCacheSize);
  536. // Default update time for empty optimization guide store is base::Time().
  537. EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), base::Time());
  538. std::unique_ptr<proto::GetHintsResponse> get_hints_response =
  539. std::make_unique<proto::GetHintsResponse>();
  540. proto::Hint* hint = get_hints_response->add_hints();
  541. hint->set_key_representation(proto::HOST);
  542. hint->set_key("host.domain.org");
  543. proto::PageHint* page_hint = hint->add_page_hints();
  544. page_hint->set_page_pattern("page pattern");
  545. base::Time stored_time = base::Time().Now();
  546. UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
  547. {"host.domain.org"}, {});
  548. EXPECT_TRUE(are_fetched_hints_updated());
  549. if (IsBackedByPersistentStore()) {
  550. // Next update time for hints should be updated.
  551. EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), stored_time);
  552. } else {
  553. EXPECT_EQ(hint_cache()->GetFetchedHintsUpdateTime(), base::Time());
  554. }
  555. // Should be loaded right when response is received.
  556. EXPECT_TRUE(hint_cache()->GetHostKeyedHintIfLoaded("host.domain.org"));
  557. // Set time so hint should be expired.
  558. MoveClockForwardBy(
  559. optimization_guide::features::StoredFetchedHintsFreshnessDuration() +
  560. base::Seconds(1));
  561. EXPECT_FALSE(hint_cache()->GetHostKeyedHintIfLoaded("host.domain.org"));
  562. }
  563. TEST_P(HintCacheTest, CacheValidURLKeyedHint) {
  564. const int kMemoryCacheSize = 5;
  565. CreateAndInitializeHintCache(kMemoryCacheSize);
  566. std::unique_ptr<StoreUpdateData> update_data =
  567. hint_cache()->CreateUpdateDataForFetchedHints(base::Time());
  568. ASSERT_EQ(update_data != nullptr, IsBackedByPersistentStore());
  569. GURL url("https://whatever.com/r/werd");
  570. google::protobuf::RepeatedPtrField<proto::Hint> hints;
  571. *(hints.Add()) = CreateHintForURL(url);
  572. // Only URL-keyed hint included so there are no hints to store within the
  573. // update data.
  574. EXPECT_FALSE(hint_cache()->ProcessAndCacheHints(
  575. &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
  576. EXPECT_TRUE(hint_cache()->GetURLKeyedHint(url));
  577. }
  578. TEST_P(HintCacheTest, URLKeyedHintExpired) {
  579. const int kMemoryCacheSize = 5;
  580. CreateAndInitializeHintCache(kMemoryCacheSize);
  581. std::unique_ptr<StoreUpdateData> update_data =
  582. hint_cache()->CreateUpdateDataForFetchedHints(base::Time());
  583. ASSERT_EQ(update_data != nullptr, IsBackedByPersistentStore());
  584. GURL url("https://whatever.com/r/werd");
  585. int cache_duration_in_secs = 60;
  586. google::protobuf::RepeatedPtrField<proto::Hint> hints;
  587. *(hints.Add()) = CreateHintForURL(url, cache_duration_in_secs);
  588. // Only URL-keyed hint included so there are no hints to store within the
  589. // update data.
  590. EXPECT_FALSE(hint_cache()->ProcessAndCacheHints(
  591. &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
  592. EXPECT_TRUE(hint_cache()->GetURLKeyedHint(url));
  593. MoveClockForwardBy(base::Seconds(cache_duration_in_secs + 1));
  594. EXPECT_FALSE(hint_cache()->GetURLKeyedHint(url));
  595. }
  596. TEST_P(HintCacheTest, PurgeExpiredFetchedHints) {
  597. if (!IsBackedByPersistentStore()) {
  598. // Purging expired fetched hints is only really relevant for when we have
  599. // a backing store.
  600. return;
  601. }
  602. const int kMemoryCacheSize = 5;
  603. CreateAndInitializeHintCache(kMemoryCacheSize);
  604. std::unique_ptr<StoreUpdateData> update_data =
  605. hint_cache()->CreateUpdateDataForFetchedHints(base::Time());
  606. ASSERT_TRUE(update_data);
  607. int cache_duration_in_secs = 60;
  608. std::unique_ptr<proto::GetHintsResponse> get_hints_response =
  609. std::make_unique<proto::GetHintsResponse>();
  610. std::string host = "shouldpurge.com";
  611. proto::Hint* hint1 = get_hints_response->add_hints();
  612. hint1->set_key_representation(proto::HOST);
  613. hint1->set_key(host);
  614. hint1->mutable_max_cache_duration()->set_seconds(cache_duration_in_secs);
  615. proto::PageHint* page_hint1 = hint1->add_page_hints();
  616. page_hint1->set_page_pattern("page pattern");
  617. std::string host2 = "notpurged.com";
  618. proto::Hint* hint2 = get_hints_response->add_hints();
  619. hint2->set_key_representation(proto::HOST);
  620. hint2->set_key(host2);
  621. hint2->mutable_max_cache_duration()->set_seconds(cache_duration_in_secs * 2);
  622. proto::PageHint* page_hint2 = hint2->add_page_hints();
  623. page_hint2->set_page_pattern("page pattern");
  624. base::Time stored_time = base::Time().Now();
  625. UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
  626. {"shouldpurge.com", "notpurged.com"}, {});
  627. EXPECT_TRUE(are_fetched_hints_updated());
  628. EXPECT_TRUE(hint_cache()->HasHint("shouldpurge.com"));
  629. EXPECT_TRUE(hint_cache()->HasHint("notpurged.com"));
  630. MoveClockForwardBy(base::Seconds(cache_duration_in_secs + 1));
  631. hint_cache()->PurgeExpiredFetchedHints();
  632. RunUntilIdle();
  633. EXPECT_FALSE(hint_cache()->HasHint("shouldpurge.com"));
  634. EXPECT_TRUE(hint_cache()->HasHint("notpurged.com"));
  635. }
  636. TEST_P(HintCacheTest, ClearFetchedHints) {
  637. const int kMemoryCacheSize = 5;
  638. CreateAndInitializeHintCache(kMemoryCacheSize);
  639. std::unique_ptr<StoreUpdateData> update_data =
  640. hint_cache()->CreateUpdateDataForFetchedHints(base::Time());
  641. ASSERT_EQ(update_data != nullptr, IsBackedByPersistentStore());
  642. GURL url("https://whatever.com/r/werd");
  643. int cache_duration_in_secs = 60;
  644. google::protobuf::RepeatedPtrField<proto::Hint> hints;
  645. *(hints.Add()) = CreateHintForURL(url, cache_duration_in_secs);
  646. std::unique_ptr<proto::GetHintsResponse> get_hints_response =
  647. std::make_unique<proto::GetHintsResponse>();
  648. std::string host = "host.com";
  649. proto::Hint* hint = get_hints_response->add_hints();
  650. hint->set_key_representation(proto::HOST);
  651. hint->set_key(host);
  652. proto::PageHint* page_hint = hint->add_page_hints();
  653. page_hint->set_page_pattern("page pattern");
  654. base::Time stored_time = base::Time().Now();
  655. UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
  656. {"host.com"}, {});
  657. EXPECT_TRUE(are_fetched_hints_updated());
  658. LoadHint(host);
  659. // Only URL-keyed hint included so there are no hints to store within the
  660. // update data.
  661. EXPECT_FALSE(hint_cache()->ProcessAndCacheHints(
  662. &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
  663. EXPECT_TRUE(hint_cache()->GetURLKeyedHint(url));
  664. EXPECT_TRUE(hint_cache()->GetHostKeyedHintIfLoaded(host));
  665. hint_cache()->ClearFetchedHints();
  666. EXPECT_FALSE(hint_cache()->GetURLKeyedHint(url));
  667. EXPECT_FALSE(hint_cache()->GetHostKeyedHintIfLoaded(host));
  668. }
  669. TEST_P(HintCacheTest, UnsupportedURLsForURLKeyedHints) {
  670. const int kMemoryCacheSize = 5;
  671. CreateAndInitializeHintCache(kMemoryCacheSize);
  672. std::unique_ptr<StoreUpdateData> update_data =
  673. hint_cache()->CreateUpdateDataForFetchedHints(base::Time());
  674. ASSERT_EQ(update_data != nullptr, IsBackedByPersistentStore());
  675. GURL https_url("https://whatever.com/r/werd");
  676. GURL http_url("http://werd.com/werd/");
  677. GURL file_url("file://dog.png");
  678. GURL chrome_url("chrome://dog.png");
  679. GURL auth_url("https://username:password@www.example.com/");
  680. google::protobuf::RepeatedPtrField<proto::Hint> hints;
  681. *(hints.Add()) = CreateHintForURL(https_url);
  682. *(hints.Add()) = CreateHintForURL(http_url);
  683. *(hints.Add()) = CreateHintForURL(file_url);
  684. *(hints.Add()) = CreateHintForURL(chrome_url);
  685. *(hints.Add()) = CreateHintForURL(auth_url);
  686. // Only URL-keyed hint included so there are no hints to store within the
  687. // update data.
  688. EXPECT_FALSE(hint_cache()->ProcessAndCacheHints(
  689. &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
  690. EXPECT_TRUE(hint_cache()->GetURLKeyedHint(https_url));
  691. EXPECT_TRUE(hint_cache()->GetURLKeyedHint(http_url));
  692. EXPECT_FALSE(hint_cache()->GetURLKeyedHint(file_url));
  693. EXPECT_FALSE(hint_cache()->GetURLKeyedHint(chrome_url));
  694. EXPECT_FALSE(hint_cache()->GetURLKeyedHint(auth_url));
  695. }
  696. TEST_P(HintCacheTest, URLsWithNoURLKeyedHints) {
  697. const int kMemoryCacheSize = 5;
  698. CreateAndInitializeHintCache(kMemoryCacheSize);
  699. std::unique_ptr<StoreUpdateData> update_data =
  700. hint_cache()->CreateUpdateDataForFetchedHints(base::Time());
  701. ASSERT_EQ(update_data != nullptr, IsBackedByPersistentStore());
  702. GURL https_url_without_hint("https://whatever.com/r/nohint");
  703. GURL https_url_with_hint("https://whatever.com/r/hint");
  704. GURL https_url_unseen("https://unseen.com/new");
  705. GURL file_url("file://dog.png");
  706. GURL chrome_url("chrome://dog.png");
  707. GURL auth_url("https://username:password@www.example.com/");
  708. google::protobuf::RepeatedPtrField<proto::Hint> hints;
  709. *(hints.Add()) = CreateHintForURL(https_url_with_hint);
  710. // Only URL-keyed hint included so there are no hints to store within the
  711. // update data.
  712. EXPECT_FALSE(hint_cache()->ProcessAndCacheHints(
  713. &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
  714. // Add the url without hint to the url-keyed cache via UpdateFetchedHints.
  715. std::unique_ptr<proto::GetHintsResponse> get_hints_response =
  716. std::make_unique<proto::GetHintsResponse>();
  717. std::string host = "host.com";
  718. proto::Hint* hint = get_hints_response->add_hints();
  719. hint->set_key_representation(proto::HOST);
  720. hint->set_key(host);
  721. proto::PageHint* page_hint = hint->add_page_hints();
  722. page_hint->set_page_pattern("page pattern");
  723. base::Time stored_time = base::Time().Now();
  724. UpdateFetchedHintsAndWait(std::move(get_hints_response), stored_time,
  725. {"host.com"}, {https_url_without_hint});
  726. EXPECT_TRUE(hint_cache()->HasURLKeyedEntryForURL(https_url_with_hint));
  727. EXPECT_TRUE(hint_cache()->HasURLKeyedEntryForURL(https_url_with_hint));
  728. EXPECT_FALSE(hint_cache()->HasURLKeyedEntryForURL(file_url));
  729. EXPECT_FALSE(hint_cache()->HasURLKeyedEntryForURL(chrome_url));
  730. EXPECT_FALSE(hint_cache()->HasURLKeyedEntryForURL(auth_url));
  731. EXPECT_FALSE(hint_cache()->HasURLKeyedEntryForURL(https_url_unseen));
  732. }
  733. TEST_P(HintCacheTest, ProcessHintsNoUpdateData) {
  734. const int kMemoryCacheSize = 5;
  735. CreateAndInitializeHintCache(kMemoryCacheSize);
  736. proto::Hint hint;
  737. hint.set_key("whatever.com");
  738. hint.set_key_representation(proto::HOST);
  739. proto::PageHint* page_hint = hint.add_page_hints();
  740. page_hint->set_page_pattern("foo.org/*/one/");
  741. google::protobuf::RepeatedPtrField<proto::Hint> hints;
  742. *(hints.Add()) = hint;
  743. EXPECT_EQ(hint_cache()->ProcessAndCacheHints(&hints, nullptr),
  744. !IsBackedByPersistentStore());
  745. }
  746. TEST_P(HintCacheTest,
  747. ProcessHintsWithNoPageHintsOrAllowlistedOptimizationsAndUpdateData) {
  748. const int kMemoryCacheSize = 5;
  749. CreateAndInitializeHintCache(kMemoryCacheSize);
  750. proto::Hint hint;
  751. hint.set_key("whatever.com");
  752. hint.set_key_representation(proto::HOST);
  753. google::protobuf::RepeatedPtrField<proto::Hint> hints;
  754. *(hints.Add()) = hint;
  755. std::unique_ptr<StoreUpdateData> update_data =
  756. StoreUpdateData::CreateComponentStoreUpdateData(base::Version("1.0.0"));
  757. EXPECT_FALSE(hint_cache()->ProcessAndCacheHints(
  758. &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
  759. if (IsBackedByPersistentStore()) {
  760. // Verify there is 1 store entries: 1 for the metadata entry.
  761. EXPECT_EQ(1ul, update_data->TakeUpdateEntries()->size());
  762. }
  763. }
  764. TEST_P(HintCacheTest,
  765. ProcessHintsWithNoPageHintsButHasAllowlistedOptimizationsAndUpdateData) {
  766. const int kMemoryCacheSize = 5;
  767. CreateAndInitializeHintCache(kMemoryCacheSize);
  768. proto::Hint hint;
  769. hint.set_key("whatever.com");
  770. hint.set_key_representation(proto::HOST);
  771. hint.add_allowlisted_optimizations()->set_optimization_type(
  772. optimization_guide::proto::DEFER_ALL_SCRIPT);
  773. google::protobuf::RepeatedPtrField<proto::Hint> hints;
  774. *(hints.Add()) = hint;
  775. std::unique_ptr<StoreUpdateData> update_data =
  776. StoreUpdateData::CreateComponentStoreUpdateData(base::Version("1.0.0"));
  777. EXPECT_TRUE(hint_cache()->ProcessAndCacheHints(
  778. &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
  779. if (IsBackedByPersistentStore()) {
  780. // Verify there is 1 store entries: 1 for the metadata entry plus the 1
  781. // added hint entry.
  782. EXPECT_EQ(2ul, update_data->TakeUpdateEntries()->size());
  783. }
  784. }
  785. TEST_P(HintCacheTest, ProcessHintsWithPageHintsAndUpdateData) {
  786. const int kMemoryCacheSize = 5;
  787. CreateAndInitializeHintCache(kMemoryCacheSize);
  788. google::protobuf::RepeatedPtrField<proto::Hint> hints;
  789. proto::Hint hint;
  790. hint.set_key("foo.org");
  791. hint.set_key_representation(proto::HOST);
  792. proto::PageHint* page_hint = hint.add_page_hints();
  793. page_hint->set_page_pattern("foo.org/*/one/");
  794. *(hints.Add()) = hint;
  795. proto::Hint no_page_hints_hint;
  796. no_page_hints_hint.set_key("nopagehints.com");
  797. no_page_hints_hint.set_key_representation(proto::HOST);
  798. *(hints.Add()) = no_page_hints_hint;
  799. std::unique_ptr<StoreUpdateData> update_data =
  800. StoreUpdateData::CreateComponentStoreUpdateData(base::Version("1.0.0"));
  801. EXPECT_TRUE(hint_cache()->ProcessAndCacheHints(
  802. &hints, IsBackedByPersistentStore() ? update_data.get() : nullptr));
  803. if (IsBackedByPersistentStore()) {
  804. // Verify there are 2 store entries: 1 for the metadata entry plus
  805. // the 1 added hint entry.
  806. EXPECT_EQ(2ul, update_data->TakeUpdateEntries()->size());
  807. }
  808. }
  809. TEST_P(HintCacheTest, RemoveHintsForURLs) {
  810. const int kMemoryCacheSize = 5;
  811. CreateAndInitializeHintCache(kMemoryCacheSize);
  812. int cache_duration_in_secs = 60;
  813. std::string host = "host.com";
  814. GURL url("https://bar.com/r/baz");
  815. std::unique_ptr<proto::GetHintsResponse> get_hints_response =
  816. std::make_unique<proto::GetHintsResponse>();
  817. *(get_hints_response->add_hints()) =
  818. CreateHintForURL(url, cache_duration_in_secs);
  819. proto::Hint* hint = get_hints_response->add_hints();
  820. hint->set_key_representation(proto::HOST);
  821. hint->set_key(host);
  822. proto::PageHint* page_hint = hint->add_page_hints();
  823. page_hint->set_page_pattern("page pattern");
  824. UpdateFetchedHintsAndWait(std::move(get_hints_response), base::Time().Now(),
  825. {host}, {url});
  826. EXPECT_TRUE(are_fetched_hints_updated());
  827. EXPECT_TRUE(hint_cache()->HasHint(host));
  828. EXPECT_TRUE(hint_cache()->HasURLKeyedEntryForURL(url));
  829. hint_cache()->RemoveHintsForURLs({url, GURL(host)});
  830. EXPECT_TRUE(hint_cache()->HasHint(host));
  831. EXPECT_FALSE(hint_cache()->HasURLKeyedEntryForURL(url));
  832. }
  833. TEST_P(HintCacheTest, RemoveHintsForHosts) {
  834. const int kMemoryCacheSize = 5;
  835. CreateAndInitializeHintCache(kMemoryCacheSize);
  836. int cache_duration_in_secs = 60;
  837. std::string host = "host.com";
  838. GURL url("https://bar.com/r/baz");
  839. std::unique_ptr<proto::GetHintsResponse> get_hints_response =
  840. std::make_unique<proto::GetHintsResponse>();
  841. *(get_hints_response->add_hints()) =
  842. CreateHintForURL(url, cache_duration_in_secs);
  843. proto::Hint* hint = get_hints_response->add_hints();
  844. hint->set_key_representation(proto::HOST);
  845. hint->set_key(host);
  846. proto::PageHint* page_hint = hint->add_page_hints();
  847. page_hint->set_page_pattern("page pattern");
  848. UpdateFetchedHintsAndWait(std::move(get_hints_response), base::Time().Now(),
  849. {host}, {url});
  850. EXPECT_TRUE(are_fetched_hints_updated());
  851. EXPECT_TRUE(hint_cache()->HasHint(host));
  852. EXPECT_TRUE(hint_cache()->HasURLKeyedEntryForURL(url));
  853. std::unique_ptr<base::RunLoop> run_loop = std::make_unique<base::RunLoop>();
  854. hint_cache()->RemoveHintsForHosts(run_loop->QuitClosure(),
  855. {url.spec(), host});
  856. run_loop->Run();
  857. EXPECT_FALSE(hint_cache()->HasHint(host));
  858. EXPECT_TRUE(hint_cache()->HasURLKeyedEntryForURL(url));
  859. }
  860. } // namespace
  861. } // namespace optimization_guide