on_device_clustering_util_unittest.cc 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // Copyright 2021 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/history_clusters/core/on_device_clustering_util.h"
  5. #include "base/test/task_environment.h"
  6. #include "components/history/core/browser/url_row.h"
  7. #include "components/history_clusters/core/clustering_test_utils.h"
  8. #include "testing/gmock/include/gmock/gmock.h"
  9. #include "testing/gtest/include/gtest/gtest.h"
  10. namespace history_clusters {
  11. namespace {
  12. using ::testing::UnorderedElementsAre;
  13. using OnDeviceClusteringUtilTest = ::testing::Test;
  14. TEST_F(OnDeviceClusteringUtilTest, MergeDuplicateVisitIntoCanonicalVisit) {
  15. // canonical_visit has the same normalized URL as duplicated_visit.
  16. history::ClusterVisit duplicate_visit = testing::CreateClusterVisit(
  17. testing::CreateDefaultAnnotatedVisit(
  18. 1, GURL("https://example.com/normalized?q=whatever")),
  19. GURL("https://example.com/normalized"));
  20. duplicate_visit.annotated_visit.content_annotations.related_searches = {
  21. "xyz"};
  22. duplicate_visit.annotated_visit.context_annotations.omnibox_url_copied = true;
  23. duplicate_visit.annotated_visit.context_annotations.is_existing_bookmark =
  24. true;
  25. duplicate_visit.annotated_visit.context_annotations
  26. .is_existing_part_of_tab_group = true;
  27. duplicate_visit.annotated_visit.context_annotations.is_new_bookmark = true;
  28. duplicate_visit.annotated_visit.context_annotations.is_placed_in_tab_group =
  29. true;
  30. duplicate_visit.annotated_visit.context_annotations.is_ntp_custom_link = true;
  31. duplicate_visit.annotated_visit.context_annotations
  32. .total_foreground_duration = base::Seconds(20);
  33. duplicate_visit.annotated_visit.content_annotations.model_annotations
  34. .visibility_score = 0.6;
  35. duplicate_visit.annotated_visit.content_annotations.model_annotations
  36. .categories.emplace_back("category1", 40);
  37. duplicate_visit.annotated_visit.content_annotations.model_annotations.entities
  38. .emplace_back("entity1", 20);
  39. history::ClusterVisit canonical_visit =
  40. testing::CreateClusterVisit(testing::CreateDefaultAnnotatedVisit(
  41. 2, GURL("https://example.com/normalized")));
  42. canonical_visit.annotated_visit.content_annotations.related_searches = {
  43. "abc", "xyz"};
  44. canonical_visit.annotated_visit.context_annotations.omnibox_url_copied =
  45. false;
  46. canonical_visit.annotated_visit.context_annotations.is_existing_bookmark =
  47. false;
  48. canonical_visit.annotated_visit.context_annotations
  49. .is_existing_part_of_tab_group = false;
  50. canonical_visit.annotated_visit.context_annotations.is_new_bookmark = false;
  51. canonical_visit.annotated_visit.context_annotations.is_placed_in_tab_group =
  52. false;
  53. canonical_visit.annotated_visit.context_annotations.is_ntp_custom_link =
  54. false;
  55. canonical_visit.annotated_visit.context_annotations
  56. .total_foreground_duration = base::Seconds(20);
  57. canonical_visit.annotated_visit.content_annotations.model_annotations
  58. .visibility_score = 0.5;
  59. canonical_visit.annotated_visit.content_annotations.model_annotations
  60. .categories.emplace_back("category1", 20);
  61. MergeDuplicateVisitIntoCanonicalVisit(std::move(duplicate_visit),
  62. canonical_visit);
  63. EXPECT_TRUE(
  64. canonical_visit.annotated_visit.context_annotations.omnibox_url_copied);
  65. EXPECT_TRUE(
  66. canonical_visit.annotated_visit.context_annotations.is_existing_bookmark);
  67. EXPECT_TRUE(canonical_visit.annotated_visit.context_annotations
  68. .is_existing_part_of_tab_group);
  69. EXPECT_TRUE(
  70. canonical_visit.annotated_visit.context_annotations.is_new_bookmark);
  71. EXPECT_TRUE(canonical_visit.annotated_visit.context_annotations
  72. .is_placed_in_tab_group);
  73. EXPECT_TRUE(
  74. canonical_visit.annotated_visit.context_annotations.is_ntp_custom_link);
  75. EXPECT_THAT(
  76. canonical_visit.annotated_visit.content_annotations.related_searches,
  77. UnorderedElementsAre("abc", "xyz"));
  78. EXPECT_EQ(canonical_visit.annotated_visit.visit_row.visit_duration,
  79. base::Seconds(10 * 2));
  80. EXPECT_EQ(canonical_visit.annotated_visit.context_annotations
  81. .total_foreground_duration,
  82. base::Seconds(20 * 2));
  83. EXPECT_FLOAT_EQ(canonical_visit.annotated_visit.content_annotations
  84. .model_annotations.visibility_score,
  85. 0.5);
  86. ASSERT_EQ(canonical_visit.annotated_visit.content_annotations
  87. .model_annotations.categories.size(),
  88. 1U);
  89. EXPECT_EQ(
  90. canonical_visit.annotated_visit.content_annotations.model_annotations
  91. .categories[0]
  92. .id,
  93. "category1");
  94. EXPECT_EQ(
  95. canonical_visit.annotated_visit.content_annotations.model_annotations
  96. .categories[0]
  97. .weight,
  98. 40);
  99. ASSERT_EQ(canonical_visit.annotated_visit.content_annotations
  100. .model_annotations.entities.size(),
  101. 1U);
  102. EXPECT_EQ(
  103. canonical_visit.annotated_visit.content_annotations.model_annotations
  104. .entities[0]
  105. .id,
  106. "entity1");
  107. EXPECT_EQ(
  108. canonical_visit.annotated_visit.content_annotations.model_annotations
  109. .entities[0]
  110. .weight,
  111. 20);
  112. }
  113. TEST_F(OnDeviceClusteringUtilTest, SortClusters) {
  114. std::vector<history::Cluster> clusters;
  115. // This first cluster is meant to validate that the higher scoring "visit 1"
  116. // gets sorted to the top, even though "visit 1" is older than "visit 2".
  117. // It's to validate the within-cluster sorting.
  118. clusters.push_back(history::Cluster(
  119. 0,
  120. {
  121. testing::CreateClusterVisit(
  122. testing::CreateDefaultAnnotatedVisit(2, GURL("https://two.com/"),
  123. base::Time::FromTimeT(10)),
  124. absl::nullopt, 0.5),
  125. testing::CreateClusterVisit(
  126. testing::CreateDefaultAnnotatedVisit(1, GURL("https://one.com/"),
  127. base::Time::FromTimeT(5)),
  128. absl::nullopt, 0.9),
  129. },
  130. {}));
  131. // The second cluster is lower scoring, but newer, because the top visit is
  132. // newer. It should be sorted above the first cluster because of reverse
  133. // chronological between-cluster sorting.
  134. clusters.push_back(history::Cluster(
  135. 0,
  136. {
  137. testing::CreateClusterVisit(
  138. testing::CreateDefaultAnnotatedVisit(2, GURL("https://two.com/"),
  139. base::Time::FromTimeT(10)),
  140. absl::nullopt, 0.1),
  141. },
  142. {}));
  143. SortClusters(&clusters);
  144. ASSERT_EQ(clusters.size(), 2u);
  145. auto& visits = clusters[0].visits;
  146. ASSERT_EQ(visits.size(), 1u);
  147. EXPECT_EQ(visits[0].annotated_visit.url_row.url(), "https://two.com/");
  148. EXPECT_FLOAT_EQ(visits[0].score, 0.1);
  149. visits = clusters[1].visits;
  150. ASSERT_EQ(visits.size(), 2u);
  151. EXPECT_EQ(visits[0].annotated_visit.url_row.url(), "https://one.com/");
  152. EXPECT_FLOAT_EQ(visits[0].score, 0.9);
  153. EXPECT_EQ(visits[1].annotated_visit.url_row.url(), "https://two.com/");
  154. EXPECT_FLOAT_EQ(visits[1].score, 0.5);
  155. }
  156. TEST_F(OnDeviceClusteringUtilTest, IsNoisyVisitSearchHighEngagementVisit) {
  157. history::ClusterVisit visit;
  158. visit.annotated_visit.content_annotations.search_terms = u"search";
  159. visit.engagement_score = 90.0;
  160. EXPECT_FALSE(IsNoisyVisit(visit));
  161. }
  162. TEST_F(OnDeviceClusteringUtilTest, IsNoisyVisitNotSearchHighEngagementVisit) {
  163. history::ClusterVisit visit;
  164. visit.annotated_visit.content_annotations.search_terms = u"";
  165. visit.engagement_score = 90.0;
  166. EXPECT_TRUE(IsNoisyVisit(visit));
  167. }
  168. TEST_F(OnDeviceClusteringUtilTest, IsNoisyVisitNotSearchLowEngagementVisit) {
  169. history::ClusterVisit visit;
  170. visit.annotated_visit.content_annotations.search_terms = u"";
  171. visit.engagement_score = 1.0;
  172. EXPECT_FALSE(IsNoisyVisit(visit));
  173. }
  174. TEST_F(OnDeviceClusteringUtilTest, IsNoisyVisitSearchLowEngagementVisit) {
  175. history::ClusterVisit visit;
  176. visit.annotated_visit.content_annotations.search_terms = u"search";
  177. visit.engagement_score = 1.0;
  178. EXPECT_FALSE(IsNoisyVisit(visit));
  179. }
  180. } // namespace
  181. } // namespace history_clusters