tile_manager_unittest.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. // Copyright 2020 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/query_tiles/internal/tile_manager.h"
  5. #include <memory>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/memory/raw_ptr.h"
  9. #include "base/run_loop.h"
  10. #include "base/test/scoped_feature_list.h"
  11. #include "base/test/task_environment.h"
  12. #include "base/time/time.h"
  13. #include "components/query_tiles/internal/tile_config.h"
  14. #include "components/query_tiles/internal/tile_store.h"
  15. #include "components/query_tiles/switches.h"
  16. #include "components/query_tiles/test/test_utils.h"
  17. #include "testing/gmock/include/gmock/gmock.h"
  18. #include "testing/gtest/include/gtest/gtest.h"
  19. using ::testing::_;
  20. using ::testing::Invoke;
  21. using ::testing::StrictMock;
  22. namespace query_tiles {
  23. namespace {
  24. const char kGuid[] = "awesome_guid";
  25. class MockTileStore : public Store<TileGroup> {
  26. public:
  27. MockTileStore() = default;
  28. ~MockTileStore() override = default;
  29. MOCK_METHOD(void, InitAndLoad, (TileStore::LoadCallback), (override));
  30. MOCK_METHOD(void,
  31. Update,
  32. (const std::string&, const TileGroup&, UpdateCallback),
  33. (override));
  34. MOCK_METHOD(void,
  35. Delete,
  36. (const std::string&, TileStore::DeleteCallback),
  37. (override));
  38. };
  39. class TileManagerTest : public testing::Test {
  40. public:
  41. TileManagerTest() = default;
  42. ~TileManagerTest() override = default;
  43. TileManagerTest(const TileManagerTest& other) = delete;
  44. TileManagerTest& operator=(const TileManagerTest& other) = delete;
  45. void SetUp() override {
  46. auto tile_store = std::make_unique<StrictMock<MockTileStore>>();
  47. tile_store_ = tile_store.get();
  48. current_time_ = base::Time::Now();
  49. manager_ = TileManager::Create(std::move(tile_store), "en-US");
  50. }
  51. // Initialize the store, compare the |expected_status| to the
  52. // actual returned status.
  53. void Init(TileGroupStatus expected_status, bool success = true) {
  54. InitWithData(expected_status, std::vector<TileGroup>(), success);
  55. }
  56. // Initialize the store and load |groups|, compare the |expected_status| to
  57. // the actual returned status.
  58. void InitWithData(TileGroupStatus expected_status,
  59. std::vector<TileGroup> groups,
  60. bool success = true) {
  61. MockTileStore::KeysAndEntries entries;
  62. for (const auto& group : groups) {
  63. entries[group.id] = std::make_unique<TileGroup>(group);
  64. }
  65. EXPECT_CALL(*tile_store(), InitAndLoad(_))
  66. .WillOnce(Invoke(
  67. [&](base::OnceCallback<void(bool, MockTileStore::KeysAndEntries)>
  68. callback) {
  69. std::move(callback).Run(success, std::move(entries));
  70. }));
  71. base::RunLoop loop;
  72. manager()->Init(base::BindOnce(&TileManagerTest::OnInitCompleted,
  73. base::Unretained(this), loop.QuitClosure(),
  74. expected_status));
  75. loop.Run();
  76. }
  77. void OnInitCompleted(base::RepeatingClosure closure,
  78. TileGroupStatus expected_status,
  79. TileGroupStatus status) {
  80. EXPECT_EQ(status, expected_status);
  81. std::move(closure).Run();
  82. }
  83. TileGroup CreateValidGroup(const std::string& group_id,
  84. const std::string& tile_id) {
  85. TileGroup group;
  86. group.last_updated_ts = current_time();
  87. group.id = group_id;
  88. group.locale = "en-US";
  89. Tile tile;
  90. tile.id = tile_id;
  91. group.tiles.emplace_back(std::make_unique<Tile>(tile));
  92. return group;
  93. }
  94. // Run SaveTiles call from manager_, compare the |expected_status| to the
  95. // actual returned status.
  96. void SaveTiles(std::vector<std::unique_ptr<Tile>> tiles,
  97. TileGroupStatus expected_status) {
  98. auto group = CreateValidGroup(kGuid, "");
  99. group.tiles = std::move(tiles);
  100. SaveTiles(group, expected_status);
  101. }
  102. void SaveTiles(const TileGroup& group, TileGroupStatus expected_status) {
  103. base::RunLoop loop;
  104. manager()->SaveTiles(
  105. std::make_unique<TileGroup>(group),
  106. base::BindOnce(&TileManagerTest::OnTilesSaved, base::Unretained(this),
  107. loop.QuitClosure(), expected_status));
  108. loop.Run();
  109. }
  110. void OnTilesSaved(base::RepeatingClosure closure,
  111. TileGroupStatus expected_status,
  112. TileGroupStatus status) {
  113. EXPECT_EQ(status, expected_status);
  114. std::move(closure).Run();
  115. }
  116. // Run GetTiles call from manager_, compare the |expected| to the actual
  117. // returned tiles.
  118. void GetTiles(std::vector<Tile> expected) {
  119. base::RunLoop loop;
  120. manager()->GetTiles(
  121. true, base::BindOnce(&TileManagerTest::OnTilesReturned,
  122. base::Unretained(this), loop.QuitClosure(),
  123. std::move(expected)));
  124. loop.Run();
  125. }
  126. void OnTilesReturned(base::RepeatingClosure closure,
  127. std::vector<Tile> expected,
  128. std::vector<Tile> tiles) {
  129. EXPECT_TRUE(test::AreTilesIdentical(expected, tiles));
  130. std::move(closure).Run();
  131. }
  132. void GetSingleTile(const std::string& id, absl::optional<Tile> expected) {
  133. base::RunLoop loop;
  134. manager()->GetTile(
  135. id, true,
  136. base::BindOnce(&TileManagerTest::OnGetTile, base::Unretained(this),
  137. loop.QuitClosure(), std::move(expected)));
  138. loop.Run();
  139. }
  140. void OnGetTile(base::RepeatingClosure closure,
  141. absl::optional<Tile> expected,
  142. absl::optional<Tile> actual) {
  143. ASSERT_EQ(expected.has_value(), actual.has_value());
  144. if (expected.has_value())
  145. EXPECT_TRUE(test::AreTilesIdentical(expected.value(), actual.value()));
  146. std::move(closure).Run();
  147. }
  148. void OnTileClicked(const std::string& tile_id) {
  149. EXPECT_CALL(*tile_store(), Update(_, _, _))
  150. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  151. MockTileStore::UpdateCallback callback) {
  152. std::move(callback).Run(true);
  153. }));
  154. manager()->OnTileClicked(tile_id);
  155. }
  156. protected:
  157. TileManager* manager() { return manager_.get(); }
  158. MockTileStore* tile_store() { return tile_store_; }
  159. const base::Time current_time() const { return current_time_; }
  160. private:
  161. base::test::TaskEnvironment task_environment_;
  162. std::unique_ptr<TileManager> manager_;
  163. raw_ptr<MockTileStore> tile_store_;
  164. base::Time current_time_;
  165. };
  166. TEST_F(TileManagerTest, InitAndLoadWithDbOperationFailed) {
  167. Init(TileGroupStatus::kFailureDbOperation, false /*success*/);
  168. GetTiles(std::vector<Tile>() /*expect an empty result*/);
  169. }
  170. TEST_F(TileManagerTest, InitWithEmptyDb) {
  171. InitWithData(TileGroupStatus::kNoTiles, std::vector<TileGroup>());
  172. GetTiles(std::vector<Tile>() /*expect an empty result*/);
  173. }
  174. // Expired group will be deleted during initialization.
  175. TEST_F(TileManagerTest, InitAndLoadWithInvalidGroup) {
  176. // Create an expired group.
  177. auto expired_group = CreateValidGroup("expired_group_id", "tile_id");
  178. expired_group.last_updated_ts = current_time() - base::Days(3);
  179. // Locale mismatch group.
  180. auto locale_mismatch_group =
  181. CreateValidGroup("locale_group_id", "locale_tile_id");
  182. locale_mismatch_group.locale = "";
  183. EXPECT_CALL(*tile_store(), Delete("expired_group_id", _));
  184. InitWithData(TileGroupStatus::kNoTiles, {expired_group});
  185. GetTiles(std::vector<Tile>());
  186. }
  187. // The most recent valid group will be selected during initialization.
  188. TEST_F(TileManagerTest, InitAndLoadSuccess) {
  189. // Two valid groups are loaded, the most recent one will be selected.
  190. auto group1 = CreateValidGroup("group_id_1", "tile_id_1");
  191. group1.last_updated_ts -= base::Minutes(5);
  192. auto group2 = CreateValidGroup("group_id_2", "tile_id_2");
  193. const Tile expected = *group2.tiles[0];
  194. EXPECT_CALL(*tile_store(), Delete("group_id_1", _));
  195. InitWithData(TileGroupStatus::kSuccess, {group1, group2});
  196. GetTiles({expected});
  197. }
  198. // Failed to init an empty db, and save tiles call failed because of db is
  199. // uninitialized. GetTiles should return empty result.
  200. TEST_F(TileManagerTest, SaveTilesWhenUnintialized) {
  201. EXPECT_CALL(*tile_store(), Update(_, _, _)).Times(0);
  202. EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
  203. Init(TileGroupStatus::kFailureDbOperation, false /*success*/);
  204. auto tile_to_save = std::make_unique<Tile>();
  205. test::ResetTestEntry(tile_to_save.get());
  206. std::vector<std::unique_ptr<Tile>> tiles_to_save;
  207. tiles_to_save.emplace_back(std::move(tile_to_save));
  208. SaveTiles(std::move(tiles_to_save), TileGroupStatus::kUninitialized);
  209. GetTiles(std::vector<Tile>() /*expect an empty result*/);
  210. }
  211. // Init with empty db successfully, and save tiles failed because of db
  212. // operation failed. GetTiles should return empty result.
  213. TEST_F(TileManagerTest, SaveTilesFailed) {
  214. EXPECT_CALL(*tile_store(), Update(_, _, _))
  215. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  216. MockTileStore::UpdateCallback callback) {
  217. std::move(callback).Run(false);
  218. }));
  219. EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
  220. Init(TileGroupStatus::kNoTiles);
  221. auto tile_to_save = std::make_unique<Tile>();
  222. test::ResetTestEntry(tile_to_save.get());
  223. std::vector<std::unique_ptr<Tile>> tiles_to_save;
  224. tiles_to_save.emplace_back(std::move(tile_to_save));
  225. SaveTiles(std::move(tiles_to_save), TileGroupStatus::kFailureDbOperation);
  226. GetTiles(std::vector<Tile>() /*expect an empty result*/);
  227. }
  228. // Init with empty db successfully, and save tiles successfully. GetTiles should
  229. // return the recent saved tiles, and no Delete call is executed.
  230. TEST_F(TileManagerTest, SaveTilesSuccess) {
  231. EXPECT_CALL(*tile_store(), Update(_, _, _))
  232. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  233. MockTileStore::UpdateCallback callback) {
  234. std::move(callback).Run(true);
  235. }));
  236. EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
  237. Init(TileGroupStatus::kNoTiles);
  238. auto tile_to_save = std::make_unique<Tile>();
  239. auto expected_tile = std::make_unique<Tile>();
  240. test::ResetTestEntry(tile_to_save.get());
  241. test::ResetTestEntry(expected_tile.get());
  242. std::vector<std::unique_ptr<Tile>> tiles_to_save;
  243. tiles_to_save.emplace_back(std::move(tile_to_save));
  244. std::vector<Tile> expected;
  245. expected.emplace_back(*expected_tile.get());
  246. SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
  247. GetTiles(std::move(expected));
  248. }
  249. // Init with store successfully. The store originally has entries loaded into
  250. // memory. Save new tiles successfully. GetTiles should return original saved
  251. // tiles.
  252. TEST_F(TileManagerTest, SaveTilesStillReturnOldTiles) {
  253. TileGroup old_group = CreateValidGroup("old_group_id", "old_tile_id");
  254. const Tile old_tile = *old_group.tiles[0].get();
  255. InitWithData(TileGroupStatus::kSuccess, {old_group});
  256. EXPECT_CALL(*tile_store(), Update("new_group_id", _, _))
  257. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  258. MockTileStore::UpdateCallback callback) {
  259. std::move(callback).Run(true);
  260. }));
  261. TileGroup new_group = CreateValidGroup("new_group_id", "new_tile_id");
  262. SaveTiles(new_group, TileGroupStatus::kSuccess);
  263. GetTiles({old_tile});
  264. }
  265. // Verifies GetTile(tile_id) API can return the right thing.
  266. TEST_F(TileManagerTest, GetTileById) {
  267. TileGroup group;
  268. test::ResetTestGroup(&group, current_time());
  269. InitWithData(TileGroupStatus::kSuccess, {group});
  270. GetSingleTile("guid-1-1", *group.tiles[0]);
  271. GetSingleTile("id_not_exist", absl::nullopt);
  272. }
  273. // Verify that GetTiles will return empty result if no matching AcceptLanguages
  274. // is found.
  275. TEST_F(TileManagerTest, GetTilesWithoutMatchingAcceptLanguages) {
  276. manager()->SetAcceptLanguagesForTesting("zh");
  277. TileGroup group;
  278. test::ResetTestGroup(&group, current_time());
  279. EXPECT_CALL(*tile_store(), Delete("group_guid", _));
  280. InitWithData(TileGroupStatus::kNoTiles, {group});
  281. GetTiles(std::vector<Tile>());
  282. }
  283. // Verify that GetTiles will return a valid result if a matching AcceptLanguages
  284. // is found.
  285. TEST_F(TileManagerTest, GetTilesWithMatchingAcceptLanguages) {
  286. manager()->SetAcceptLanguagesForTesting("zh, en");
  287. TileGroup group = CreateValidGroup("group_id", "tile_id");
  288. const Tile tile = *group.tiles[0];
  289. InitWithData(TileGroupStatus::kSuccess, {group});
  290. GetTiles({tile});
  291. }
  292. TEST_F(TileManagerTest, PurgeDb) {
  293. TileGroup group;
  294. test::ResetTestGroup(&group, current_time());
  295. InitWithData(TileGroupStatus::kSuccess, {group});
  296. EXPECT_CALL(*tile_store(), Delete(group.id, _));
  297. manager()->PurgeDb();
  298. GetTiles(std::vector<Tile>() /*expect an empty result*/);
  299. }
  300. TEST_F(TileManagerTest, GetTileGroup) {
  301. TileGroup expected;
  302. test::ResetTestGroup(&expected, current_time());
  303. InitWithData(TileGroupStatus::kSuccess, {expected});
  304. TileGroup* actual = manager()->GetTileGroup();
  305. EXPECT_TRUE(test::AreTileGroupsIdentical(*actual, expected));
  306. }
  307. // Check that the right number of trending tiles are returned.
  308. TEST_F(TileManagerTest, GetTilesWithTrendingTiles) {
  309. EXPECT_CALL(*tile_store(), Update(_, _, _))
  310. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  311. MockTileStore::UpdateCallback callback) {
  312. std::move(callback).Run(true);
  313. }));
  314. EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
  315. Init(TileGroupStatus::kNoTiles);
  316. std::vector<std::unique_ptr<Tile>> tiles_to_save =
  317. test::GetTestTrendingTileList();
  318. std::vector<Tile> expected;
  319. expected.emplace_back(*tiles_to_save[0].get());
  320. expected.emplace_back(*tiles_to_save[1].get());
  321. SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
  322. GetTiles(std::move(expected));
  323. }
  324. // Check that the getTiles() will return all trending subtiles.
  325. TEST_F(TileManagerTest, GetTilesWithTrendingSubTiles) {
  326. EXPECT_CALL(*tile_store(), Update(_, _, _))
  327. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  328. MockTileStore::UpdateCallback callback) {
  329. std::move(callback).Run(true);
  330. }));
  331. EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
  332. Init(TileGroupStatus::kNoTiles);
  333. auto parent_tile = std::make_unique<Tile>();
  334. parent_tile->id = "parent";
  335. parent_tile->sub_tiles = test::GetTestTrendingTileList();
  336. // The last subtile will be removed from the result.
  337. std::vector<Tile> expected;
  338. expected.emplace_back(*parent_tile.get());
  339. std::vector<std::unique_ptr<Tile>> tiles_to_save;
  340. tiles_to_save.emplace_back(std::move(parent_tile));
  341. SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
  342. GetTiles(std::move(expected));
  343. }
  344. // Check that GetSingleTile() will filter and return the right number of
  345. // trending subtiles.
  346. TEST_F(TileManagerTest, GetSingleTileWithTrendingSubTiles) {
  347. EXPECT_CALL(*tile_store(), Update(_, _, _))
  348. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  349. MockTileStore::UpdateCallback callback) {
  350. std::move(callback).Run(true);
  351. }));
  352. EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
  353. Init(TileGroupStatus::kNoTiles);
  354. auto parent_tile = std::make_unique<Tile>();
  355. parent_tile->id = "parent";
  356. parent_tile->sub_tiles = test::GetTestTrendingTileList();
  357. absl::optional<Tile> parent_tile2 = absl::make_optional(*parent_tile.get());
  358. parent_tile2->sub_tiles.pop_back();
  359. std::vector<std::unique_ptr<Tile>> tiles_to_save;
  360. tiles_to_save.emplace_back(std::move(parent_tile));
  361. SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
  362. GetSingleTile("parent", std::move(parent_tile2));
  363. }
  364. // Check that trending tiles get removed after inactivity.
  365. TEST_F(TileManagerTest, TrendingTopTilesRemovedAfterShown) {
  366. base::test::ScopedFeatureList feature_list;
  367. EXPECT_CALL(*tile_store(), Update(_, _, _))
  368. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  369. MockTileStore::UpdateCallback callback) {
  370. std::move(callback).Run(true);
  371. }));
  372. EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
  373. Init(TileGroupStatus::kNoTiles);
  374. std::vector<std::unique_ptr<Tile>> tiles_to_save =
  375. test::GetTestTrendingTileList();
  376. std::vector<Tile> expected;
  377. expected.emplace_back(*tiles_to_save[0].get());
  378. expected.emplace_back(*tiles_to_save[1].get());
  379. Tile trending_3 = *tiles_to_save[2].get();
  380. SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
  381. GetTiles(expected);
  382. // Click the 2nd tile.
  383. OnTileClicked("trending_2");
  384. // Both the first and the second tile will be removed.
  385. expected.erase(expected.begin(), expected.begin() + 2);
  386. expected.emplace_back(std::move(trending_3));
  387. EXPECT_CALL(*tile_store(), Update(_, _, _))
  388. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  389. MockTileStore::UpdateCallback callback) {
  390. std::move(callback).Run(true);
  391. }));
  392. GetTiles(expected);
  393. // The 3rd tile will be removed due to max impression threshold.
  394. expected.erase(expected.begin());
  395. EXPECT_CALL(*tile_store(), Update(_, _, _))
  396. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  397. MockTileStore::UpdateCallback callback) {
  398. std::move(callback).Run(true);
  399. }));
  400. GetTiles(expected);
  401. }
  402. // Check that trending subtiles will not be removed if they are not displayed.
  403. TEST_F(TileManagerTest, UnshownTrendingSubTilesNotRemoved) {
  404. base::test::ScopedFeatureList feature_list;
  405. EXPECT_CALL(*tile_store(), Update(_, _, _))
  406. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  407. MockTileStore::UpdateCallback callback) {
  408. std::move(callback).Run(true);
  409. }));
  410. EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
  411. Init(TileGroupStatus::kNoTiles);
  412. auto parent_tile = std::make_unique<Tile>();
  413. parent_tile->id = "parent";
  414. parent_tile->sub_tiles = test::GetTestTrendingTileList();
  415. // The last subtile will be removed from the result.
  416. std::vector<Tile> expected;
  417. expected.emplace_back(*parent_tile.get());
  418. std::vector<std::unique_ptr<Tile>> tiles_to_save;
  419. tiles_to_save.emplace_back(std::move(parent_tile));
  420. SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
  421. GetTiles(expected);
  422. // Click the parent tile and then get top level tiles.
  423. OnTileClicked("parent");
  424. GetTiles(expected);
  425. // Get top level tiles again. Since sub tiles were never shown,
  426. // they will not be removed.
  427. OnTileClicked("parent");
  428. GetTiles(expected);
  429. }
  430. // Check that if OnTileClicked() is followed by GetTile(), impression is
  431. // correctly counted.
  432. TEST_F(TileManagerTest, GetSingleTileAfterOnTileClicked) {
  433. base::test::ScopedFeatureList feature_list;
  434. EXPECT_CALL(*tile_store(), Update(_, _, _))
  435. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  436. MockTileStore::UpdateCallback callback) {
  437. std::move(callback).Run(true);
  438. }));
  439. EXPECT_CALL(*tile_store(), Delete(_, _)).Times(0);
  440. Init(TileGroupStatus::kNoTiles);
  441. auto parent_tile = std::make_unique<Tile>();
  442. parent_tile->id = "parent";
  443. parent_tile->sub_tiles = test::GetTestTrendingTileList();
  444. // The last subtile will be removed from the result.
  445. std::vector<Tile> expected;
  446. expected.emplace_back(*parent_tile.get());
  447. Tile trending_3 = *(expected[0].sub_tiles[2]).get();
  448. absl::optional<Tile> get_single_tile_expected =
  449. absl::make_optional(*parent_tile.get());
  450. get_single_tile_expected->sub_tiles.pop_back();
  451. std::vector<std::unique_ptr<Tile>> tiles_to_save;
  452. tiles_to_save.emplace_back(std::move(parent_tile));
  453. SaveTiles(std::move(tiles_to_save), TileGroupStatus::kSuccess);
  454. GetTiles(expected);
  455. // Click the parent tile to show the subtiles.
  456. OnTileClicked("parent");
  457. GetSingleTile("parent", get_single_tile_expected);
  458. // Click a trending tile will not reset its impression.
  459. OnTileClicked("trending_1");
  460. // The first two tiles will get removed.
  461. expected[0].sub_tiles.erase(expected[0].sub_tiles.begin(),
  462. expected[0].sub_tiles.begin() + 2);
  463. EXPECT_CALL(*tile_store(), Update(_, _, _))
  464. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  465. MockTileStore::UpdateCallback callback) {
  466. std::move(callback).Run(true);
  467. }));
  468. GetTiles(expected);
  469. get_single_tile_expected->sub_tiles.clear();
  470. get_single_tile_expected->sub_tiles.emplace_back(
  471. std::make_unique<Tile>(std::move(trending_3)));
  472. OnTileClicked("parent");
  473. GetSingleTile("parent", get_single_tile_expected);
  474. // Finally all tiles are removed.
  475. get_single_tile_expected->sub_tiles.clear();
  476. OnTileClicked("parent");
  477. EXPECT_CALL(*tile_store(), Update(_, _, _))
  478. .WillOnce(Invoke([](const std::string& id, const TileGroup& group,
  479. MockTileStore::UpdateCallback callback) {
  480. std::move(callback).Run(true);
  481. }));
  482. GetSingleTile("parent", get_single_tile_expected);
  483. }
  484. } // namespace
  485. } // namespace query_tiles