clusterer_unittest.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  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/clusterer.h"
  5. #include "base/test/task_environment.h"
  6. #include "components/history_clusters/core/clustering_test_utils.h"
  7. #include "testing/gmock/include/gmock/gmock.h"
  8. #include "testing/gtest/include/gtest/gtest.h"
  9. namespace history_clusters {
  10. namespace {
  11. using ::testing::ElementsAre;
  12. class ClustererTest : public ::testing::Test {
  13. public:
  14. void SetUp() override { clusterer_ = std::make_unique<Clusterer>(); }
  15. void TearDown() override { clusterer_.reset(); }
  16. std::vector<history::Cluster> CreateInitialClustersFromVisits(
  17. std::vector<history::ClusterVisit> visits) {
  18. return clusterer_->CreateInitialClustersFromVisits(&visits);
  19. }
  20. private:
  21. std::unique_ptr<Clusterer> clusterer_;
  22. base::test::TaskEnvironment task_environment_;
  23. };
  24. TEST_F(ClustererTest, ClusterOneVisit) {
  25. std::vector<history::ClusterVisit> visits;
  26. // Fill in the visits vector with 1 visit.
  27. history::AnnotatedVisit visit = testing::CreateDefaultAnnotatedVisit(
  28. 1, GURL("https://google.com/"), base::Time::FromTimeT(1));
  29. visits.push_back(testing::CreateClusterVisit(visit));
  30. std::vector<history::Cluster> result_clusters =
  31. CreateInitialClustersFromVisits(visits);
  32. EXPECT_THAT(testing::ToVisitResults(result_clusters),
  33. ElementsAre(ElementsAre(testing::VisitResult(1, 1.0))));
  34. }
  35. TEST_F(ClustererTest, ClusterTwoVisitsTiedByReferringVisit) {
  36. std::vector<history::ClusterVisit> visits;
  37. // Visit2's referrer is visit 1 and are close together.
  38. history::AnnotatedVisit visit = testing::CreateDefaultAnnotatedVisit(
  39. 1, GURL("https://google.com/"), base::Time::FromTimeT(1));
  40. visits.push_back(testing::CreateClusterVisit(visit));
  41. history::AnnotatedVisit visit2 = testing::CreateDefaultAnnotatedVisit(
  42. 2, GURL("https://google.com/next"), base::Time::FromTimeT(2));
  43. visit2.referring_visit_of_redirect_chain_start = 1;
  44. visits.push_back(testing::CreateClusterVisit(visit2));
  45. std::vector<history::Cluster> result_clusters =
  46. CreateInitialClustersFromVisits(visits);
  47. EXPECT_THAT(testing::ToVisitResults(result_clusters),
  48. ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
  49. testing::VisitResult(2, 1.0))));
  50. }
  51. TEST_F(ClustererTest, ClusterTwoVisitsTiedByOpenerVisit) {
  52. std::vector<history::ClusterVisit> visits;
  53. // Visit2's referrer is visit 5 and are close together. Have the visit IDs be
  54. // misordered to ensure that the visits are sorted by visit time rather than
  55. // by ID.
  56. history::AnnotatedVisit visit = testing::CreateDefaultAnnotatedVisit(
  57. 5, GURL("https://google.com/"), base::Time::FromTimeT(1));
  58. visits.push_back(testing::CreateClusterVisit(visit));
  59. history::AnnotatedVisit visit2 = testing::CreateDefaultAnnotatedVisit(
  60. 2, GURL("https://google.com/next"), base::Time::FromTimeT(2));
  61. visit2.opener_visit_of_redirect_chain_start = 5;
  62. visits.push_back(testing::CreateClusterVisit(visit2));
  63. std::vector<history::Cluster> result_clusters =
  64. CreateInitialClustersFromVisits(visits);
  65. EXPECT_THAT(testing::ToVisitResults(result_clusters),
  66. ElementsAre(ElementsAre(testing::VisitResult(5, 1.0),
  67. testing::VisitResult(2, 1.0))));
  68. }
  69. TEST_F(ClustererTest, ClusterTwoVisitsTiedByURL) {
  70. std::vector<history::ClusterVisit> visits;
  71. // Visit2 has the same URL as Visit1.
  72. history::AnnotatedVisit visit = testing::CreateDefaultAnnotatedVisit(
  73. 1, GURL("https://google.com/"), base::Time::FromTimeT(1));
  74. visits.push_back(testing::CreateClusterVisit(visit));
  75. history::AnnotatedVisit visit2 = testing::CreateDefaultAnnotatedVisit(
  76. 2, GURL("https://google.com/"), base::Time::FromTimeT(2));
  77. visits.push_back(testing::CreateClusterVisit(visit2));
  78. std::vector<history::Cluster> result_clusters =
  79. CreateInitialClustersFromVisits(visits);
  80. EXPECT_THAT(testing::ToVisitResults(result_clusters),
  81. ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
  82. testing::VisitResult(2, 1.0))));
  83. }
  84. TEST_F(ClustererTest, ClusterTwoVisitsTiedByNormalizedURL) {
  85. std::vector<history::ClusterVisit> visits;
  86. // Visit2 has the same URL as Visit1.
  87. history::AnnotatedVisit visit = testing::CreateDefaultAnnotatedVisit(
  88. 1, GURL("https://example.com/normalized?q=whatever"),
  89. base::Time::FromTimeT(1));
  90. visits.push_back(testing::CreateClusterVisit(
  91. visit, GURL("https://example.com/normalized")));
  92. history::AnnotatedVisit visit2 = testing::CreateDefaultAnnotatedVisit(
  93. 2, GURL("https://example.com/normalized"), base::Time::FromTimeT(2));
  94. visits.push_back(testing::CreateClusterVisit(visit2));
  95. std::vector<history::Cluster> result_clusters =
  96. CreateInitialClustersFromVisits(visits);
  97. EXPECT_THAT(testing::ToVisitResults(result_clusters),
  98. ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
  99. testing::VisitResult(2, 1.0))));
  100. }
  101. TEST_F(ClustererTest, MultipleClusters) {
  102. std::vector<history::ClusterVisit> visits;
  103. // Visit2's referrer is visit 1 and visit 4 is a back navigation from visit 2.
  104. // Visit 3 is a different journey altogether. Visit 10 is referring to a
  105. // missing visit and should be considered as in its own cluster.
  106. // Also, make sure these aren't sorted so we test that we are sorting the
  107. // visits by time.
  108. history::AnnotatedVisit visit = testing::CreateDefaultAnnotatedVisit(
  109. 1, GURL("https://github.com/"), base::Time::FromTimeT(1));
  110. visits.push_back(testing::CreateClusterVisit(visit));
  111. history::AnnotatedVisit visit2 = testing::CreateDefaultAnnotatedVisit(
  112. 2, GURL("https://google.com/"), base::Time::FromTimeT(2));
  113. visit2.referring_visit_of_redirect_chain_start = 1;
  114. // Set the visit duration to be 2x the default so it has the same duration
  115. // after |visit| and |visit4| are deduped.
  116. visit2.visit_row.visit_duration = base::Seconds(20);
  117. visits.push_back(testing::CreateClusterVisit(visit2));
  118. history::AnnotatedVisit visit4 = testing::CreateDefaultAnnotatedVisit(
  119. 4, GURL("https://github.com/"), base::Time::FromTimeT(4));
  120. visits.push_back(testing::CreateClusterVisit(visit4));
  121. history::AnnotatedVisit visit5 = testing::CreateDefaultAnnotatedVisit(
  122. 10, GURL("https://nonexistentreferrer.com/"), base::Time::FromTimeT(10));
  123. visit5.referring_visit_of_redirect_chain_start = 6;
  124. visits.push_back(testing::CreateClusterVisit(visit5));
  125. history::AnnotatedVisit visit3 = testing::CreateDefaultAnnotatedVisit(
  126. 3, GURL("https://whatever.com/"), base::Time::FromTimeT(3));
  127. visits.push_back(testing::CreateClusterVisit(visit3));
  128. std::vector<history::Cluster> result_clusters =
  129. CreateInitialClustersFromVisits(visits);
  130. EXPECT_THAT(testing::ToVisitResults(result_clusters),
  131. ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
  132. testing::VisitResult(2, 1.0),
  133. testing::VisitResult(4, 1.0)),
  134. ElementsAre(testing::VisitResult(3, 1.0)),
  135. ElementsAre(testing::VisitResult(10, 1.0))));
  136. }
  137. TEST_F(ClustererTest, SplitClusterOnNavigationTime) {
  138. std::vector<history::ClusterVisit> visits;
  139. history::AnnotatedVisit visit =
  140. testing::CreateDefaultAnnotatedVisit(1, GURL("https://google.com/"));
  141. visit.visit_row.visit_time = base::Time::Now();
  142. visits.push_back(testing::CreateClusterVisit(visit));
  143. // Visit2 has a different URL but is linked by referring id to visit.
  144. history::AnnotatedVisit visit2 =
  145. testing::CreateDefaultAnnotatedVisit(2, GURL("https://bar.com/"));
  146. visit2.referring_visit_of_redirect_chain_start = 1;
  147. visit2.visit_row.visit_time = base::Time::Now() + base::Minutes(5);
  148. visits.push_back(testing::CreateClusterVisit(visit2));
  149. // Visit3 has a different URL but is linked by referring id to visit but the
  150. // cutoff has passed so it should be in a different cluster.
  151. history::AnnotatedVisit visit3 =
  152. testing::CreateDefaultAnnotatedVisit(3, GURL("https://foo.com/"));
  153. visit3.referring_visit_of_redirect_chain_start = 1;
  154. visit3.visit_row.visit_time = base::Time::Now() + base::Hours(2);
  155. visits.push_back(testing::CreateClusterVisit(visit3));
  156. std::vector<history::Cluster> result_clusters =
  157. CreateInitialClustersFromVisits(visits);
  158. EXPECT_THAT(testing::ToVisitResults(result_clusters),
  159. ElementsAre(ElementsAre(testing::VisitResult(1, 1.0),
  160. testing::VisitResult(2, 1.0)),
  161. ElementsAre(testing::VisitResult(3, 1.0))));
  162. }
  163. TEST_F(ClustererTest, SplitClusterOnSearchVisit) {
  164. std::vector<history::ClusterVisit> visits;
  165. history::AnnotatedVisit visit =
  166. testing::CreateDefaultAnnotatedVisit(1, GURL("https://google.com/"));
  167. visit.visit_row.visit_time = base::Time::Now();
  168. visits.push_back(testing::CreateClusterVisit(visit));
  169. // Visit2 has a different URL but is linked by referring id to visit.
  170. history::AnnotatedVisit visit2 =
  171. testing::CreateDefaultAnnotatedVisit(2, GURL("https://bar.com/"));
  172. visit2.referring_visit_of_redirect_chain_start = 1;
  173. visit2.visit_row.visit_time = base::Time::Now() + base::Minutes(5);
  174. visits.push_back(testing::CreateClusterVisit(visit2));
  175. // Visit3 has a different URL but is linked by referring id to visit but the
  176. // cutoff has passed so it should be in a different cluster.
  177. history::AnnotatedVisit visit3 =
  178. testing::CreateDefaultAnnotatedVisit(3, GURL("https://foo.com/"));
  179. visit3.referring_visit_of_redirect_chain_start = 1;
  180. visit3.visit_row.visit_time = base::Time::Now() + base::Hours(2);
  181. visits.push_back(testing::CreateClusterVisit(visit3));
  182. // Visit4 was referred by visit 3 but is a search visit.
  183. history::AnnotatedVisit visit4 =
  184. testing::CreateDefaultAnnotatedVisit(4, GURL("https://search.com/"));
  185. visit4.referring_visit_of_redirect_chain_start = 3;
  186. visit4.visit_row.visit_time =
  187. base::Time::Now() + base::Hours(2) + base::Minutes(1);
  188. history::ClusterVisit cluster_visit4 = testing::CreateClusterVisit(visit4);
  189. cluster_visit4.annotated_visit.content_annotations.search_terms = u"whatever";
  190. visits.push_back(cluster_visit4);
  191. // Visit5 was referred by visit 4.
  192. history::AnnotatedVisit visit5 =
  193. testing::CreateDefaultAnnotatedVisit(5, GURL("https://resultlink.com/"));
  194. visit5.referring_visit_of_redirect_chain_start = 4;
  195. visit5.visit_row.visit_time =
  196. base::Time::Now() + base::Hours(2) + base::Minutes(1);
  197. visits.push_back(testing::CreateClusterVisit(visit5));
  198. // Visit6 is a search visit (back-forward) and has the same search terms as
  199. // visit 4.
  200. history::AnnotatedVisit visit6 =
  201. testing::CreateDefaultAnnotatedVisit(6, GURL("https://search.com/"));
  202. visit6.visit_row.visit_time =
  203. base::Time::Now() + base::Hours(2) + base::Minutes(2);
  204. history::ClusterVisit cluster_visit6 = testing::CreateClusterVisit(visit6);
  205. cluster_visit6.annotated_visit.content_annotations.search_terms = u"whatever";
  206. visits.push_back(cluster_visit6);
  207. // Visit7 was referred by visit 6, is a search visit but has different search
  208. // terms as visit 6.
  209. history::AnnotatedVisit visit7 =
  210. testing::CreateDefaultAnnotatedVisit(7, GURL("https://search.com/"));
  211. visit7.referring_visit_of_redirect_chain_start = 6;
  212. visit7.visit_row.visit_time =
  213. base::Time::Now() + base::Hours(2) + base::Minutes(3);
  214. history::ClusterVisit cluster_visit7 = testing::CreateClusterVisit(visit7);
  215. cluster_visit7.annotated_visit.content_annotations.search_terms =
  216. u"different";
  217. visits.push_back(cluster_visit7);
  218. std::vector<history::Cluster> result_clusters =
  219. CreateInitialClustersFromVisits(visits);
  220. EXPECT_THAT(
  221. testing::ToVisitResults(result_clusters),
  222. ElementsAre(
  223. ElementsAre(testing::VisitResult(1, 1.0),
  224. testing::VisitResult(2, 1.0)),
  225. ElementsAre(testing::VisitResult(3, 1.0)),
  226. ElementsAre(testing::VisitResult(4, 1.0, /*duplicate_visits=*/{},
  227. u"whatever"),
  228. testing::VisitResult(5, 1.0),
  229. testing::VisitResult(6, 1.0, /*duplicate_visits=*/{},
  230. u"whatever")),
  231. ElementsAre(testing::VisitResult(7, 1.0, /*duplicate_visits=*/{},
  232. u"different"))));
  233. }
  234. } // namespace
  235. } // namespace history_clusters